2 * PROJECT: ReactOS System Control Panel Applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/userprofile.c
5 * PURPOSE: Computer settings for networking
6 * COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org>
7 * Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
17 typedef struct _PROFILEDATA
24 } PROFILEDATA
, *PPROFILEDATA
;
31 _In_ PPROFILEDATA pProfileData
)
33 PWSTR pszRawBuffer
= NULL
, pszCookedBuffer
= NULL
;
36 nLength
= LoadStringW(hApplet
, IDS_USERPROFILE_TYPE_TEXT
, (PWSTR
)&pszRawBuffer
, 0);
41 pszRawBuffer
= HeapAlloc(GetProcessHeap(), 0, (nLength
+ 1) * sizeof(WCHAR
));
42 if (pszRawBuffer
== NULL
)
45 LoadStringW(hApplet
, IDS_USERPROFILE_TYPE_TEXT
, pszRawBuffer
, nLength
+ 1);
47 pszCookedBuffer
= HeapAlloc(GetProcessHeap(), 0, (nLength
+ wcslen(pProfileData
->pszFullName
) + 1) * sizeof(WCHAR
));
48 if (pszCookedBuffer
== NULL
)
51 swprintf(pszCookedBuffer
, pszRawBuffer
, pProfileData
->pszFullName
);
53 /* Set the full text */
54 SetDlgItemText(hwndDlg
, IDC_USERPROFILE_TYPE_TEXT
, pszCookedBuffer
);
56 /* FIXME: Right now, we support local user profiles only! */
57 EnableWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_TYPE_ROAMING
), FALSE
);
58 Button_SetCheck(GetDlgItem(hwndDlg
, IDC_USERPROFILE_TYPE_LOCAL
), BST_CHECKED
);
59 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), FALSE
);
62 if (pszCookedBuffer
!= NULL
)
63 HeapFree(GetProcessHeap(), 0, pszCookedBuffer
);
65 if (pszRawBuffer
!= NULL
)
66 HeapFree(GetProcessHeap(), 0, pszRawBuffer
);
75 UserProfileTypeDlgProc(
84 OnProfileTypeInit(hwndDlg
, (PPROFILEDATA
)lParam
);
91 switch (LOWORD(wParam
))
108 ChangeUserProfileType(
115 DPRINT("ChangeUserProfileType(%p)\n", hwndDlg
);
117 hwndListView
= GetDlgItem(hwndDlg
, IDC_USERPROFILE_LIST
);
118 if (hwndListView
== NULL
)
121 iSelected
= ListView_GetNextItem(hwndListView
, -1, LVNI_SELECTED
);
125 ZeroMemory(&Item
, sizeof(LVITEM
));
126 Item
.mask
= LVIF_PARAM
;
127 Item
.iItem
= iSelected
;
128 if (!ListView_GetItem(hwndListView
, &Item
))
131 if (Item
.lParam
== 0)
134 if (DialogBoxParam(hApplet
,
135 MAKEINTRESOURCE(IDD_USERPROFILE_TYPE
),
137 UserProfileTypeDlgProc
,
138 (LPARAM
)Item
.lParam
) == IDOK
)
140 /* FIXME: Update the profile list view */
153 WCHAR szTitle
[64], szRawText
[128], szCookedText
[256];
157 PPROFILEDATA pProfileData
;
159 DPRINT("DeleteUserProfile()\n");
161 hwndListView
= GetDlgItem(hwndDlg
, IDC_USERPROFILE_LIST
);
162 if (hwndListView
== NULL
)
165 iSelected
= ListView_GetNextItem(hwndListView
, -1, LVNI_SELECTED
);
169 ZeroMemory(&Item
, sizeof(LVITEM
));
170 Item
.mask
= LVIF_PARAM
;
171 Item
.iItem
= iSelected
;
172 if (!ListView_GetItem(hwndListView
, &Item
))
175 if (Item
.lParam
== 0)
178 pProfileData
= (PPROFILEDATA
)Item
.lParam
;
179 if (pProfileData
->dwRefCount
!= 0)
182 LoadStringW(hApplet
, IDS_USERPROFILE_CONFIRM_DELETE_TITLE
, szTitle
, ARRAYSIZE(szTitle
));
183 LoadStringW(hApplet
, IDS_USERPROFILE_CONFIRM_DELETE
, szRawText
, ARRAYSIZE(szRawText
));
184 swprintf(szCookedText
, szRawText
, pProfileData
->pszFullName
);
186 if (MessageBoxW(hwndDlg
,
189 MB_ICONQUESTION
| MB_YESNO
) == IDYES
)
191 /* FIXME: Delete the profile here! */
202 CopyUserProfileDlgProc(
217 switch (LOWORD(wParam
))
241 DPRINT("CopyUserProfile()\n");
243 hwndListView
= GetDlgItem(hwndDlg
, IDC_USERPROFILE_LIST
);
244 if (hwndListView
== NULL
)
247 iSelected
= ListView_GetNextItem(hwndListView
, -1, LVNI_SELECTED
);
251 ZeroMemory(&Item
, sizeof(LVITEM
));
252 Item
.mask
= LVIF_PARAM
;
253 Item
.iItem
= iSelected
;
254 if (!ListView_GetItem(hwndListView
, &Item
))
257 if (Item
.lParam
== 0)
260 if (DialogBoxParam(hApplet
,
261 MAKEINTRESOURCE(IDD_USERPROFILE_COPY
),
263 CopyUserProfileDlgProc
,
264 (LPARAM
)Item
.lParam
) == IDOK
)
266 /* FIXME: Update the profile list view */
276 _In_ HWND hwndListView
)
282 GetClientRect(hwndListView
, &rect
);
284 SendMessage(hwndListView
, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, LVS_EX_FULLROWSELECT
);
286 memset(&column
, 0x00, sizeof(column
));
287 column
.mask
= LVCF_FMT
| LVCF_WIDTH
| LVCF_SUBITEM
| LVCF_TEXT
;
288 column
.fmt
= LVCFMT_LEFT
;
289 column
.cx
= (INT
)((rect
.right
- rect
.left
) * 0.40);
291 LoadString(hApplet
, IDS_USERPROFILE_NAME
, szStr
, ARRAYSIZE(szStr
));
292 column
.pszText
= szStr
;
293 (void)ListView_InsertColumn(hwndListView
, 0, &column
);
295 column
.fmt
= LVCFMT_RIGHT
;
296 column
.cx
= (INT
)((rect
.right
- rect
.left
) * 0.15);
298 LoadString(hApplet
, IDS_USERPROFILE_SIZE
, szStr
, ARRAYSIZE(szStr
));
299 column
.pszText
= szStr
;
300 (void)ListView_InsertColumn(hwndListView
, 1, &column
);
302 column
.fmt
= LVCFMT_LEFT
;
303 column
.cx
= (INT
)((rect
.right
- rect
.left
) * 0.15);
305 LoadString(hApplet
, IDS_USERPROFILE_TYPE
, szStr
, ARRAYSIZE(szStr
));
306 column
.pszText
= szStr
;
307 (void)ListView_InsertColumn(hwndListView
, 2, &column
);
309 column
.fmt
= LVCFMT_LEFT
;
310 column
.cx
= (INT
)((rect
.right
- rect
.left
) * 0.15);
312 LoadString(hApplet
, IDS_USERPROFILE_STATUS
, szStr
, ARRAYSIZE(szStr
));
313 column
.pszText
= szStr
;
314 (void)ListView_InsertColumn(hwndListView
, 3, &column
);
316 column
.fmt
= LVCFMT_LEFT
;
317 column
.cx
= (INT
)((rect
.right
- rect
.left
) * 0.15) - GetSystemMetrics(SM_CYHSCROLL
);
319 LoadString(hApplet
, IDS_USERPROFILE_MODIFIED
, szStr
, ARRAYSIZE(szStr
));
320 column
.pszText
= szStr
;
321 (void)ListView_InsertColumn(hwndListView
, 4, &column
);
328 _In_ PWSTR pszProfilePath
,
329 _Inout_ PULONGLONG pullProfileSize
)
331 HANDLE hFile
= INVALID_HANDLE_VALUE
;
332 WIN32_FIND_DATA FindData
;
333 DWORD dwProfilePathLength
;
337 dwProfilePathLength
= wcslen(pszProfilePath
);
339 wcscat(pszProfilePath
, L
"\\*.*");
341 hFile
= FindFirstFileW(pszProfilePath
, &FindData
);
342 if (hFile
== INVALID_HANDLE_VALUE
)
344 if ((GetLastError() != ERROR_FILE_NOT_FOUND
) &&
345 (GetLastError() != ERROR_PATH_NOT_FOUND
))
353 if (FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
355 if ((_wcsicmp(FindData
.cFileName
, L
".") == 0) ||
356 (_wcsicmp(FindData
.cFileName
, L
"..") == 0))
359 pszProfilePath
[dwProfilePathLength
+ 1] = UNICODE_NULL
;
360 wcscat(pszProfilePath
, FindData
.cFileName
);
362 if (!GetProfileSize(pszProfilePath
, pullProfileSize
))
370 Size
.u
.LowPart
= FindData
.nFileSizeLow
;
371 Size
.u
.HighPart
= FindData
.nFileSizeHigh
;
372 *pullProfileSize
+= Size
.QuadPart
;
375 while (FindNextFile(hFile
, &FindData
));
378 pszProfilePath
[dwProfilePathLength
] = UNICODE_NULL
;
380 if (hFile
!= INVALID_HANDLE_VALUE
)
390 _In_ PSID pProfileSid
,
391 _In_ DWORD dwNameBufferSize
,
392 _Out_ PWSTR pszNameBuffer
,
393 _Out_ PBOOL pbUnknownProfile
)
395 WCHAR szAccountName
[128], szDomainName
[128];
396 DWORD dwAccountNameSize
, dwDomainNameSize
;
399 dwAccountNameSize
= ARRAYSIZE(szAccountName
);
400 dwDomainNameSize
= ARRAYSIZE(szDomainName
);
401 if (!LookupAccountSidW(NULL
,
409 /* Unknown account */
410 LoadStringW(hApplet
, IDS_USERPROFILE_ACCOUNT_UNKNOWN
, pszNameBuffer
, dwNameBufferSize
);
411 *pbUnknownProfile
= TRUE
;
415 /* Show only the user accounts */
416 if (Use
!= SidTypeUser
)
419 if (szAccountName
[0] == UNICODE_NULL
)
421 /* Deleted account */
422 LoadStringW(hApplet
, IDS_USERPROFILE_ACCOUNT_DELETED
, pszNameBuffer
, dwNameBufferSize
);
427 wsprintf(pszNameBuffer
, L
"%s\\%s", szDomainName
, szAccountName
);
429 *pbUnknownProfile
= FALSE
;
438 _In_ HWND hwndListView
,
439 _In_ PSID pProfileSid
,
440 _In_ HKEY hProfileKey
)
442 WCHAR szTempProfilePath
[MAX_PATH
], szProfilePath
[MAX_PATH
];
443 WCHAR szNameBuffer
[256];
444 PPROFILEDATA pProfileData
= NULL
;
445 DWORD dwProfileData
, dwSize
, dwType
, dwState
= 0, dwRefCount
= 0;
446 DWORD dwProfilePathLength
;
450 WIN32_FIND_DATA FindData
;
452 SYSTEMTIME SystemTime
;
453 ULONGLONG ullProfileSize
;
454 BOOL bUnknownProfile
;
457 /* Get the profile path */
458 dwSize
= MAX_PATH
* sizeof(WCHAR
);
459 dwError
= RegQueryValueExW(hProfileKey
,
463 (LPBYTE
)szTempProfilePath
,
465 if (dwError
!= ERROR_SUCCESS
)
469 ExpandEnvironmentStringsW(szTempProfilePath
,
473 /* Check if the profile path exists */
474 hFile
= FindFirstFileW(szProfilePath
, &FindData
);
475 if (hFile
== INVALID_HANDLE_VALUE
)
480 /* Get the length of the profile path */
481 dwProfilePathLength
= wcslen(szProfilePath
);
483 /* Check for the ntuser.dat file */
484 wcscat(szProfilePath
, L
"\\ntuser.dat");
485 hFile
= FindFirstFileW(szProfilePath
, &FindData
);
486 if (hFile
== INVALID_HANDLE_VALUE
)
490 szProfilePath
[dwProfilePathLength
] = UNICODE_NULL
;
492 /* Get the profile size */
493 ullProfileSize
= 0ULL;
494 GetProfileSize(szProfilePath
, &ullProfileSize
);
496 /* Get the profile name */
497 if (!GetProfileName(pProfileSid
,
498 ARRAYSIZE(szNameBuffer
),
503 /* Get the profile state value */
504 dwSize
= sizeof(dwState
);
505 if (RegQueryValueExW(hProfileKey
,
510 &dwSize
) != ERROR_SUCCESS
)
515 /* Get the profile reference counter */
516 dwSize
= sizeof(dwRefCount
);
517 if (RegQueryValueExW(hProfileKey
,
522 &dwSize
) != ERROR_SUCCESS
)
527 /* Create and fill the profile data entry */
528 dwProfileData
= sizeof(PROFILEDATA
) +
529 ((wcslen(szNameBuffer
) + 1) * sizeof(WCHAR
)) +
530 ((wcslen(szProfilePath
) + 1) * sizeof(WCHAR
));
531 pProfileData
= HeapAlloc(GetProcessHeap(),
534 if (pProfileData
== NULL
)
537 pProfileData
->dwRefCount
= dwRefCount
;
538 pProfileData
->dwState
= dwState
;
539 pProfileData
->bUnknownProfile
= bUnknownProfile
;
541 ptr
= (PWSTR
)((ULONG_PTR
)pProfileData
+ sizeof(PROFILEDATA
));
542 pProfileData
->pszFullName
= ptr
;
544 wcscpy(pProfileData
->pszFullName
, szNameBuffer
);
546 ptr
= (PWSTR
)((ULONG_PTR
)ptr
+ ((wcslen(pProfileData
->pszFullName
) + 1) * sizeof(WCHAR
)));
547 pProfileData
->pszProfilePath
= ptr
;
548 wcscpy(pProfileData
->pszProfilePath
, szProfilePath
);
550 /* Add the profile and set its name */
551 memset(&lvi
, 0x00, sizeof(lvi
));
552 lvi
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
553 lvi
.pszText
= pProfileData
->pszFullName
;
555 lvi
.lParam
= (LPARAM
)pProfileData
;
556 iItem
= ListView_InsertItem(hwndListView
, &lvi
);
558 /* Set the profile size */
559 StrFormatByteSizeW(ullProfileSize
, szNameBuffer
, ARRAYSIZE(szNameBuffer
) - 1);
560 ListView_SetItemText(hwndListView
, iItem
, 1, szNameBuffer
);
562 /* Set the profile type */
563 if (dwState
& 0x0010) // PROFILE_UPDATE_CENTRAL
564 nId
= IDS_USERPROFILE_ROAMING
;
566 nId
= IDS_USERPROFILE_LOCAL
;
568 LoadStringW(hApplet
, nId
, szNameBuffer
, ARRAYSIZE(szNameBuffer
));
570 ListView_SetItemText(hwndListView
, iItem
, 2, szNameBuffer
);
572 /* FIXME: Set the profile status */
573 if (dwState
& 0x0001) // PROFILE_MANDATORY
574 nId
= IDS_USERPROFILE_MANDATORY
;
575 else if (dwState
& 0x0010) // PROFILE_UPDATE_CENTRAL
576 nId
= IDS_USERPROFILE_ROAMING
;
578 nId
= IDS_USERPROFILE_LOCAL
;
580 LoadStringW(hApplet
, nId
, szNameBuffer
, ARRAYSIZE(szNameBuffer
));
582 ListView_SetItemText(hwndListView
, iItem
, 3, szNameBuffer
);
584 /* Set the profile modified time */
585 FileTimeToSystemTime(&FindData
.ftLastWriteTime
,
588 GetDateFormatW(LOCALE_USER_DEFAULT
,
593 ARRAYSIZE(szNameBuffer
));
595 ListView_SetItemText(hwndListView
, iItem
, 4, szNameBuffer
);
602 _In_ HWND hwndListView
)
606 BOOL bChange
= FALSE
;
608 BOOL bDelete
= FALSE
;
609 PPROFILEDATA pProfileData
;
611 if (ListView_GetSelectedCount(hwndListView
) != 0)
613 iSelected
= ListView_GetNextItem(hwndListView
, -1, LVNI_SELECTED
);
616 ZeroMemory(&Item
, sizeof(LVITEM
));
617 Item
.mask
= LVIF_PARAM
;
618 Item
.iItem
= iSelected
;
619 if (ListView_GetItem(hwndListView
, &Item
))
621 if (Item
.lParam
!= 0)
623 pProfileData
= (PPROFILEDATA
)Item
.lParam
;
625 if (pProfileData
->bUnknownProfile
)
632 bDelete
= (pProfileData
->dwRefCount
== 0);
633 bCopy
= (pProfileData
->dwRefCount
== 0);
642 EnableWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_CHANGE
), bChange
);
643 EnableWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_DELETE
), bDelete
);
644 EnableWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_COPY
), bCopy
);
651 _In_ HWND hwndListView
,
654 HKEY hKeyUserProfiles
= INVALID_HANDLE_VALUE
;
657 WCHAR szProfileSid
[64];
659 FILETIME ftLastWrite
;
661 HANDLE hToken
= NULL
;
662 PTOKEN_USER pTokenUser
= NULL
;
666 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
669 if (GetTokenInformation(hToken
, TokenUser
, NULL
, 0, &dwSize
) ||
670 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
675 pTokenUser
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
676 if (pTokenUser
== NULL
)
679 if (!GetTokenInformation(hToken
, TokenUser
, pTokenUser
, dwSize
, &dwSize
))
682 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
683 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
691 for (dwIndex
= 0; ; dwIndex
++)
693 dwSidLength
= ARRAYSIZE(szProfileSid
);
694 if (RegEnumKeyExW(hKeyUserProfiles
,
704 if (RegOpenKeyExW(hKeyUserProfiles
,
708 &hProfileKey
) == ERROR_SUCCESS
)
710 if (ConvertStringSidToSid(szProfileSid
, &pProfileSid
))
712 AddUserProfile(hwndListView
,
715 LocalFree(pProfileSid
);
718 RegCloseKey(hProfileKey
);
724 if (ConvertSidToStringSidW(pTokenUser
->User
.Sid
, &pszProfileSid
))
726 if (RegOpenKeyExW(hKeyUserProfiles
,
730 &hProfileKey
) == ERROR_SUCCESS
)
732 AddUserProfile(hwndListView
,
733 pTokenUser
->User
.Sid
,
735 RegCloseKey(hProfileKey
);
738 LocalFree(pszProfileSid
);
742 if (ListView_GetItemCount(hwndListView
) != 0)
743 ListView_SetItemState(hwndListView
, 0, LVIS_SELECTED
| LVIS_FOCUSED
, LVIS_SELECTED
| LVIS_FOCUSED
);
745 UpdateButtonState(hwndDlg
, hwndListView
);
748 if (hKeyUserProfiles
!= INVALID_HANDLE_VALUE
)
749 RegCloseKey(hKeyUserProfiles
);
751 if (pTokenUser
!= NULL
)
752 HeapFree(GetProcessHeap(), 0, pTokenUser
);
760 OnInitUserProfileDialog(HWND hwndDlg
)
764 bAdmin
= IsUserAdmin();
766 /* Initialize the list view control */
767 SetListViewColumns(GetDlgItem(hwndDlg
, IDC_USERPROFILE_LIST
));
769 /* Hide the delete and copy buttons for non-admins */
770 ShowWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_DELETE
), bAdmin
? SW_SHOW
: SW_HIDE
);
771 ShowWindow(GetDlgItem(hwndDlg
, IDC_USERPROFILE_COPY
), bAdmin
? SW_SHOW
: SW_HIDE
);
773 /* Add the profiles to the list view */
774 AddUserProfiles(hwndDlg
, GetDlgItem(hwndDlg
, IDC_USERPROFILE_LIST
), bAdmin
);
785 if (nmhdr
->idFrom
== IDC_USERACCOUNT_LINK
&& nmhdr
->code
== NM_CLICK
)
787 ShellExecuteW(hwndDlg
, NULL
, L
"usrmgr.cpl", NULL
, NULL
, 0);
789 else if (nmhdr
->idFrom
== IDC_USERPROFILE_LIST
)
793 case LVN_ITEMCHANGED
:
794 UpdateButtonState(hwndDlg
, nmhdr
->hwndFrom
);
798 ChangeUserProfileType(hwndDlg
);
802 pNMLV
= (LPNMLISTVIEW
)nmhdr
;
803 if (pNMLV
->lParam
!= 0)
804 HeapFree(GetProcessHeap(), 0, (LPVOID
)pNMLV
->lParam
);
811 /* Property page dialog callback */
813 UserProfileDlgProc(HWND hwndDlg
,
821 OnInitUserProfileDialog(hwndDlg
);
825 switch (LOWORD(wParam
))
833 case IDC_USERPROFILE_CHANGE
:
834 ChangeUserProfileType(hwndDlg
);
837 case IDC_USERPROFILE_DELETE
:
838 DeleteUserProfile(hwndDlg
);
841 case IDC_USERPROFILE_COPY
:
842 CopyUserProfile(hwndDlg
);
848 OnNotify(hwndDlg
, (NMHDR
*)lParam
);