[SYSDM] Allow deleting and copying of user profiles only for profiles that are curren...
[reactos.git] / dll / cpl / sysdm / userprofile.c
1 /*
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>
8 *
9 */
10
11 #include "precomp.h"
12 #include <sddl.h>
13 #include <winnls.h>
14
15 #include <debug.h>
16
17 typedef struct _PROFILEDATA
18 {
19 DWORD dwRefCount;
20 DWORD dwState;
21 PWSTR pszFullName;
22 } PROFILEDATA, *PPROFILEDATA;
23
24
25 static
26 BOOL
27 OnProfileTypeInit(
28 HWND hwndDlg,
29 PPROFILEDATA pProfileData)
30 {
31 PWSTR pszRawBuffer = NULL, pszCookedBuffer = NULL;
32 INT nLength;
33
34 nLength = LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, (PWSTR)&pszRawBuffer, 0);
35 pszRawBuffer = NULL;
36 if (nLength == 0)
37 return FALSE;
38
39 pszRawBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(WCHAR));
40 if (pszRawBuffer == NULL)
41 return FALSE;
42
43 LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, pszRawBuffer, nLength + 1);
44
45 pszCookedBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR));
46 if (pszCookedBuffer == NULL)
47 goto done;
48
49 swprintf(pszCookedBuffer, pszRawBuffer, pProfileData->pszFullName);
50
51 /* Set the full text */
52 SetDlgItemText(hwndDlg, IDC_USERPROFILE_TYPE_TEXT, pszCookedBuffer);
53
54 /* FIXME: Right now, we support local user profiles only! */
55 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_ROAMING), FALSE);
56 Button_SetCheck(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_LOCAL), BST_CHECKED);
57 EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
58
59 done:
60 if (pszCookedBuffer != NULL)
61 HeapFree(GetProcessHeap(), 0, pszCookedBuffer);
62
63 if (pszRawBuffer != NULL)
64 HeapFree(GetProcessHeap(), 0, pszRawBuffer);
65
66 return TRUE;
67 }
68
69
70 static
71 INT_PTR
72 CALLBACK
73 UserProfileTypeDlgProc(
74 _In_ HWND hwndDlg,
75 _In_ UINT uMsg,
76 _In_ WPARAM wParam,
77 _In_ LPARAM lParam)
78 {
79 switch (uMsg)
80 {
81 case WM_INITDIALOG:
82 OnProfileTypeInit(hwndDlg, (PPROFILEDATA)lParam);
83 return TRUE;
84
85 case WM_DESTROY:
86 break;
87
88 case WM_COMMAND:
89 switch (LOWORD(wParam))
90 {
91 case IDOK:
92 case IDCANCEL:
93 EndDialog(hwndDlg,
94 LOWORD(wParam));
95 return TRUE;
96 }
97 break;
98 }
99
100 return FALSE;
101 }
102
103
104 static
105 BOOL
106 ChangeUserProfileType(
107 _In_ HWND hwndDlg)
108 {
109 HWND hwndListView;
110 LVITEM Item;
111 INT iSelected;
112
113 DPRINT("ChangeUserProfileType(%p)\n", hwndDlg);
114
115 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
116 if (hwndListView == NULL)
117 return FALSE;
118
119 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
120 if (iSelected == -1)
121 return FALSE;
122
123 ZeroMemory(&Item, sizeof(LVITEM));
124 Item.mask = LVIF_PARAM;
125 Item.iItem = iSelected;
126 Item.iSubItem = 0;
127 if (!ListView_GetItem(hwndListView, &Item))
128 return FALSE;
129
130 if (Item.lParam == 0)
131 return FALSE;
132
133 if (DialogBoxParam(hApplet,
134 MAKEINTRESOURCE(IDD_USERPROFILE_TYPE),
135 hwndDlg,
136 UserProfileTypeDlgProc,
137 (LPARAM)Item.lParam) == IDOK)
138 {
139 /* FIXME: Update the profile list view */
140 return TRUE;
141 }
142
143 return FALSE;
144 }
145
146
147 static
148 BOOL
149 DeleteUserProfile(
150 _In_ HWND hwndDlg)
151 {
152 WCHAR szTitle[64], szRawText[128], szCookedText[256];
153 HWND hwndListView;
154 LVITEM Item;
155 INT iSelected;
156 PPROFILEDATA pProfileData;
157
158 DPRINT("DeleteUserProfile()\n");
159
160 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
161 if (hwndListView == NULL)
162 return FALSE;
163
164 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
165 if (iSelected == -1)
166 return FALSE;
167
168 ZeroMemory(&Item, sizeof(LVITEM));
169 Item.mask = LVIF_PARAM;
170 Item.iItem = iSelected;
171 Item.iSubItem = 0;
172 if (!ListView_GetItem(hwndListView, &Item))
173 return FALSE;
174
175 if (Item.lParam == 0)
176 return FALSE;
177
178 pProfileData = (PPROFILEDATA)Item.lParam;
179 if (pProfileData->dwRefCount != 0)
180 return FALSE;
181
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);
185
186 if (MessageBoxW(hwndDlg,
187 szCookedText,
188 szTitle,
189 MB_ICONQUESTION | MB_YESNO) == IDYES)
190 {
191 /* FIXME: Delete the profile here! */
192 return TRUE;
193 }
194
195 return FALSE;
196 }
197
198
199 static
200 INT_PTR
201 CALLBACK
202 CopyUserProfileDlgProc(
203 _In_ HWND hwndDlg,
204 _In_ UINT uMsg,
205 _In_ WPARAM wParam,
206 _In_ LPARAM lParam)
207 {
208 switch (uMsg)
209 {
210 case WM_INITDIALOG:
211 return TRUE;
212
213 case WM_DESTROY:
214 break;
215
216 case WM_COMMAND:
217 switch (LOWORD(wParam))
218 {
219 case IDOK:
220 case IDCANCEL:
221 EndDialog(hwndDlg,
222 LOWORD(wParam));
223 return TRUE;
224 }
225 break;
226 }
227
228 return FALSE;
229 }
230
231
232 static
233 BOOL
234 CopyUserProfile(
235 _In_ HWND hwndDlg)
236 {
237 HWND hwndListView;
238 LVITEM Item;
239 INT iSelected;
240
241 DPRINT("CopyUserProfile()\n");
242
243 hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
244 if (hwndListView == NULL)
245 return FALSE;
246
247 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
248 if (iSelected == -1)
249 return FALSE;
250
251 ZeroMemory(&Item, sizeof(LVITEM));
252 Item.mask = LVIF_PARAM;
253 Item.iItem = iSelected;
254 Item.iSubItem = 0;
255 if (!ListView_GetItem(hwndListView, &Item))
256 return FALSE;
257
258 if (Item.lParam == 0)
259 return FALSE;
260
261 if (DialogBoxParam(hApplet,
262 MAKEINTRESOURCE(IDD_USERPROFILE_COPY),
263 hwndDlg,
264 CopyUserProfileDlgProc,
265 (LPARAM)Item.lParam) == IDOK)
266 {
267 /* FIXME: Update the profile list view */
268 return TRUE;
269 }
270
271 return FALSE;
272 }
273
274
275 static VOID
276 SetListViewColumns(
277 _In_ HWND hwndListView)
278 {
279 LV_COLUMN column;
280 RECT rect;
281 TCHAR szStr[32];
282
283 GetClientRect(hwndListView, &rect);
284
285 SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
286
287 memset(&column, 0x00, sizeof(column));
288 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
289 column.fmt = LVCFMT_LEFT;
290 column.cx = (INT)((rect.right - rect.left) * 0.40);
291 column.iSubItem = 0;
292 LoadString(hApplet, IDS_USERPROFILE_NAME, szStr, ARRAYSIZE(szStr));
293 column.pszText = szStr;
294 (void)ListView_InsertColumn(hwndListView, 0, &column);
295
296 column.fmt = LVCFMT_RIGHT;
297 column.cx = (INT)((rect.right - rect.left) * 0.15);
298 column.iSubItem = 1;
299 LoadString(hApplet, IDS_USERPROFILE_SIZE, szStr, ARRAYSIZE(szStr));
300 column.pszText = szStr;
301 (void)ListView_InsertColumn(hwndListView, 1, &column);
302
303 column.fmt = LVCFMT_LEFT;
304 column.cx = (INT)((rect.right - rect.left) * 0.15);
305 column.iSubItem = 2;
306 LoadString(hApplet, IDS_USERPROFILE_TYPE, szStr, ARRAYSIZE(szStr));
307 column.pszText = szStr;
308 (void)ListView_InsertColumn(hwndListView, 2, &column);
309
310 column.fmt = LVCFMT_LEFT;
311 column.cx = (INT)((rect.right - rect.left) * 0.15);
312 column.iSubItem = 3;
313 LoadString(hApplet, IDS_USERPROFILE_STATUS, szStr, ARRAYSIZE(szStr));
314 column.pszText = szStr;
315 (void)ListView_InsertColumn(hwndListView, 3, &column);
316
317 column.fmt = LVCFMT_LEFT;
318 column.cx = (INT)((rect.right - rect.left) * 0.15) - GetSystemMetrics(SM_CYHSCROLL);
319 column.iSubItem = 4;
320 LoadString(hApplet, IDS_USERPROFILE_MODIFIED, szStr, ARRAYSIZE(szStr));
321 column.pszText = szStr;
322 (void)ListView_InsertColumn(hwndListView, 4, &column);
323 }
324
325
326 static
327 BOOL
328 GetProfileSize(
329 PWSTR pszProfilePath,
330 PULONGLONG pullProfileSize)
331 {
332 HANDLE hFile = INVALID_HANDLE_VALUE;
333 WIN32_FIND_DATA FindData;
334 DWORD dwProfilePathLength;
335 ULARGE_INTEGER Size;
336 BOOL bResult = TRUE;
337
338 dwProfilePathLength = wcslen(pszProfilePath);
339
340 wcscat(pszProfilePath, L"\\*.*");
341
342 hFile = FindFirstFileW(pszProfilePath, &FindData);
343 if (hFile == INVALID_HANDLE_VALUE)
344 {
345 if ((GetLastError() != ERROR_FILE_NOT_FOUND) &&
346 (GetLastError() != ERROR_PATH_NOT_FOUND))
347 bResult = FALSE;
348
349 goto done;
350 }
351
352 do
353 {
354 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
355 {
356 if ((_wcsicmp(FindData.cFileName, L".") == 0) ||
357 (_wcsicmp(FindData.cFileName, L"..") == 0))
358 continue;
359
360 pszProfilePath[dwProfilePathLength + 1] = UNICODE_NULL;
361 wcscat(pszProfilePath, FindData.cFileName);
362
363 if (!GetProfileSize(pszProfilePath, pullProfileSize))
364 {
365 bResult = FALSE;
366 goto done;
367 }
368 }
369 else
370 {
371 Size.u.LowPart = FindData.nFileSizeLow;
372 Size.u.HighPart = FindData.nFileSizeHigh;
373 *pullProfileSize += Size.QuadPart;
374 }
375 }
376 while (FindNextFile(hFile, &FindData));
377
378 done:
379 pszProfilePath[dwProfilePathLength] = UNICODE_NULL;
380
381 if (hFile != INVALID_HANDLE_VALUE)
382 FindClose(hFile);
383
384 return bResult;
385 }
386
387
388 static
389 BOOL
390 GetProfileName(
391 _In_ PSID pProfileSid,
392 _In_ DWORD dwNameBufferSize,
393 _Out_ PWSTR pszNameBuffer)
394 {
395 WCHAR szAccountName[128], szDomainName[128];
396 DWORD dwAccountNameSize, dwDomainNameSize;
397 SID_NAME_USE Use;
398
399 dwAccountNameSize = ARRAYSIZE(szAccountName);
400 dwDomainNameSize = ARRAYSIZE(szDomainName);
401 if (!LookupAccountSidW(NULL,
402 pProfileSid,
403 szAccountName,
404 &dwAccountNameSize,
405 szDomainName,
406 &dwDomainNameSize,
407 &Use))
408 {
409 /* Unknown account */
410 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, pszNameBuffer, dwNameBufferSize);
411 }
412 else
413 {
414 /* Show only the user accounts */
415 if (Use != SidTypeUser)
416 return FALSE;
417
418 if (szAccountName[0] == UNICODE_NULL)
419 {
420 /* Deleted account */
421 LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, pszNameBuffer, dwNameBufferSize);
422 }
423 else
424 {
425 /* Normal account */
426 wsprintf(pszNameBuffer, L"%s\\%s", szDomainName, szAccountName);
427 }
428 }
429
430 return TRUE;
431 }
432
433
434 static
435 VOID
436 FormatProfileSize(LPWSTR Buffer, double size)
437 {
438 const LPWSTR units[] = {L"MB", L"GB", L"TB"};
439 int i = 0, j;
440
441 size /= 1024;
442 size /= 1024;
443
444 while (size >= 1024 && i < 3)
445 {
446 size /= 1024;
447 i++;
448 }
449
450 if (size < 10)
451 j = 2;
452 else if (size < 100)
453 j = 1;
454 else
455 j = 0;
456
457 swprintf(Buffer, L"%.*f %s", j, size, units[i]);
458 }
459
460
461 static VOID
462 AddUserProfile(
463 _In_ HWND hwndListView,
464 _In_ PSID pProfileSid,
465 _In_ HKEY hProfileKey)
466 {
467 WCHAR szTempProfilePath[MAX_PATH], szProfilePath[MAX_PATH];
468 WCHAR szNameBuffer[256];
469 PPROFILEDATA pProfileData = NULL;
470 DWORD dwProfileData, dwSize, dwType, dwState = 0, dwRefCount = 0;
471 DWORD dwProfilePathLength;
472 PWSTR ptr;
473 INT nId, iItem;
474 LV_ITEM lvi;
475 WIN32_FIND_DATA FindData;
476 HANDLE hFile;
477 SYSTEMTIME SystemTime;
478 ULONGLONG ullProfileSize;
479 DWORD dwError;
480
481 /* Get the profile path */
482 dwSize = MAX_PATH * sizeof(WCHAR);
483 dwError = RegQueryValueExW(hProfileKey,
484 L"ProfileImagePath",
485 NULL,
486 &dwType,
487 (LPBYTE)szTempProfilePath,
488 &dwSize);
489 if (dwError != ERROR_SUCCESS)
490 return;
491
492 /* Expand it */
493 ExpandEnvironmentStringsW(szTempProfilePath,
494 szProfilePath,
495 MAX_PATH);
496
497 /* Check if the profile path exists */
498 hFile = FindFirstFileW(szProfilePath, &FindData);
499 if (hFile == INVALID_HANDLE_VALUE)
500 return;
501
502 FindClose(hFile);
503
504 /* Get the length of the profile path */
505 dwProfilePathLength = wcslen(szProfilePath);
506
507 /* Check for the ntuser.dat file */
508 wcscat(szProfilePath, L"\\ntuser.dat");
509 hFile = FindFirstFileW(szProfilePath, &FindData);
510 if (hFile == INVALID_HANDLE_VALUE)
511 return;
512
513 FindClose(hFile);
514 szProfilePath[dwProfilePathLength] = UNICODE_NULL;
515
516 /* Get the profile size */
517 ullProfileSize = 0ULL;
518 GetProfileSize(szProfilePath, &ullProfileSize);
519
520 /* Get the profile name */
521 if (!GetProfileName(pProfileSid, ARRAYSIZE(szNameBuffer), szNameBuffer))
522 return;
523
524 /* Get the profile state value */
525 dwSize = sizeof(dwState);
526 if (RegQueryValueExW(hProfileKey,
527 L"State",
528 NULL,
529 &dwType,
530 (LPBYTE)&dwState,
531 &dwSize) != ERROR_SUCCESS)
532 {
533 dwState = 0;
534 }
535
536 /* Get the profile reference counter */
537 dwSize = sizeof(dwRefCount);
538 if (RegQueryValueExW(hProfileKey,
539 L"RefCount",
540 NULL,
541 &dwType,
542 (LPBYTE)&dwRefCount,
543 &dwSize) != ERROR_SUCCESS)
544 {
545 dwRefCount = 0;
546 }
547
548 /* Create and fill the profile data entry */
549 dwProfileData = sizeof(PROFILEDATA) +
550 ((wcslen(szNameBuffer) + 1) * sizeof(WCHAR));
551 pProfileData = HeapAlloc(GetProcessHeap(),
552 HEAP_ZERO_MEMORY,
553 dwProfileData);
554 if (pProfileData == NULL)
555 return;
556
557 pProfileData->dwRefCount = dwRefCount;
558 pProfileData->dwState = dwState;
559
560 ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA));
561 pProfileData->pszFullName = ptr;
562
563 wcscpy(pProfileData->pszFullName, szNameBuffer);
564
565 /* Add the profile and set its name */
566 memset(&lvi, 0x00, sizeof(lvi));
567 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
568 lvi.pszText = pProfileData->pszFullName;
569 lvi.state = 0;
570 lvi.lParam = (LPARAM)pProfileData;
571 iItem = ListView_InsertItem(hwndListView, &lvi);
572
573 /* Set the profile size */
574 FormatProfileSize(szNameBuffer, (double)ullProfileSize);
575 ListView_SetItemText(hwndListView, iItem, 1, szNameBuffer);
576
577 /* Set the profile type */
578 if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
579 nId = IDS_USERPROFILE_ROAMING;
580 else
581 nId = IDS_USERPROFILE_LOCAL;
582
583 LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
584
585 ListView_SetItemText(hwndListView, iItem, 2, szNameBuffer);
586
587 /* FIXME: Set the profile status */
588 if (dwState & 0x0001) // PROFILE_MANDATORY
589 nId = IDS_USERPROFILE_MANDATORY;
590 else if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
591 nId = IDS_USERPROFILE_ROAMING;
592 else
593 nId = IDS_USERPROFILE_LOCAL;
594
595 LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
596
597 ListView_SetItemText(hwndListView, iItem, 3, szNameBuffer);
598
599 /* Set the profile modified time */
600 FileTimeToSystemTime(&FindData.ftLastWriteTime,
601 &SystemTime);
602
603 GetDateFormatW(LOCALE_USER_DEFAULT,
604 DATE_SHORTDATE,
605 &SystemTime,
606 NULL,
607 szNameBuffer,
608 ARRAYSIZE(szNameBuffer));
609
610 ListView_SetItemText(hwndListView, iItem, 4, szNameBuffer);
611 }
612
613
614 static VOID
615 UpdateButtonState(
616 _In_ HWND hwndDlg,
617 _In_ HWND hwndListView)
618 {
619 LVITEM Item;
620 INT iSelected;
621 BOOL bChange = FALSE;
622 BOOL bCopy = FALSE;
623 BOOL bDelete = FALSE;
624
625 iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
626 if (iSelected != -1)
627 {
628 Item.mask = LVIF_PARAM;
629 Item.iItem = iSelected;
630 Item.iSubItem = 0;
631 if (ListView_GetItem(hwndListView, &Item))
632 {
633 if (Item.lParam != 0)
634 {
635 bCopy = (((PPROFILEDATA)Item.lParam)->dwRefCount == 0);
636 bDelete = (((PPROFILEDATA)Item.lParam)->dwRefCount == 0);
637 }
638 }
639
640 bChange = TRUE;
641 }
642 else
643 {
644 bChange = FALSE;
645 bCopy = FALSE;
646 bDelete = FALSE;
647 }
648
649 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), bChange);
650 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bDelete);
651 EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bCopy);
652 }
653
654
655 static VOID
656 AddUserProfiles(
657 _In_ HWND hwndDlg,
658 _In_ HWND hwndListView,
659 _In_ BOOL bAdmin)
660 {
661 HKEY hKeyUserProfiles = INVALID_HANDLE_VALUE;
662 HKEY hProfileKey;
663 DWORD dwIndex;
664 WCHAR szProfileSid[64];
665 DWORD dwSidLength;
666 FILETIME ftLastWrite;
667 DWORD dwSize;
668 HANDLE hToken = NULL;
669 PTOKEN_USER pTokenUser = NULL;
670 PSID pProfileSid;
671 PWSTR pszProfileSid;
672
673 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
674 return;
675
676 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
677 if (dwSize == 0)
678 goto done;
679
680 pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwSize);
681 if (pTokenUser == NULL)
682 goto done;
683
684 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
685 goto done;
686
687 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
688 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
689 0,
690 KEY_READ,
691 &hKeyUserProfiles))
692 goto done;
693
694 if (bAdmin)
695 {
696 for (dwIndex = 0; ; dwIndex++)
697 {
698 dwSidLength = ARRAYSIZE(szProfileSid);
699 if (RegEnumKeyExW(hKeyUserProfiles,
700 dwIndex,
701 szProfileSid,
702 &dwSidLength,
703 NULL,
704 NULL,
705 NULL,
706 &ftLastWrite))
707 break;
708
709 if (RegOpenKeyExW(hKeyUserProfiles,
710 szProfileSid,
711 0,
712 KEY_READ,
713 &hProfileKey) == ERROR_SUCCESS)
714 {
715 if (ConvertStringSidToSid(szProfileSid, &pProfileSid))
716 {
717 AddUserProfile(hwndListView,
718 pProfileSid,
719 hProfileKey);
720 LocalFree(pProfileSid);
721 }
722
723 RegCloseKey(hProfileKey);
724 }
725 }
726 }
727 else
728 {
729 if (ConvertSidToStringSidW(pTokenUser->User.Sid, &pszProfileSid))
730 {
731 if (RegOpenKeyExW(hKeyUserProfiles,
732 pszProfileSid,
733 0,
734 KEY_READ,
735 &hProfileKey) == ERROR_SUCCESS)
736 {
737 AddUserProfile(hwndListView,
738 pTokenUser->User.Sid,
739 hProfileKey);
740 RegCloseKey(hProfileKey);
741 }
742
743 LocalFree(pszProfileSid);
744 }
745 }
746
747 if (ListView_GetItemCount(hwndListView) != 0)
748 ListView_SetItemState(hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
749
750 UpdateButtonState(hwndDlg, hwndListView);
751
752 done:
753 if (hKeyUserProfiles != INVALID_HANDLE_VALUE)
754 RegCloseKey(hKeyUserProfiles);
755
756 if (pTokenUser != NULL)
757 HeapFree(GetProcessHeap(), 0, pTokenUser);
758
759 if (hToken != NULL)
760 CloseHandle(hToken);
761 }
762
763
764 static VOID
765 OnInitUserProfileDialog(HWND hwndDlg)
766 {
767 BOOL bAdmin;
768
769 bAdmin = IsUserAdmin();
770
771 /* Initialize the list view control */
772 SetListViewColumns(GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST));
773
774 /* Hide the delete and copy buttons for non-admins */
775 ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bAdmin ? SW_SHOW : SW_HIDE);
776 ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bAdmin ? SW_SHOW : SW_HIDE);
777
778 /* Add the profiles to the list view */
779 AddUserProfiles(hwndDlg, GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST), bAdmin);
780 }
781
782
783 static
784 VOID
785 OnDestroy(
786 _In_ HWND hwndDlg)
787 {
788 HWND hwndList;
789 INT nItems, i;
790 LVITEM Item;
791
792 hwndList = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
793
794 nItems = ListView_GetItemCount(hwndList);
795 for (i = 0; i < nItems; i++)
796 {
797 Item.iItem = i;
798 Item.iSubItem = 0;
799 if (ListView_GetItem(hwndList, &Item))
800 {
801 if (Item.lParam != 0)
802 HeapFree(GetProcessHeap(), 0, (PVOID)Item.lParam);
803 }
804 }
805 }
806
807
808 static
809 VOID
810 OnNotify(
811 _In_ HWND hwndDlg,
812 _In_ NMHDR *nmhdr)
813 {
814 if (nmhdr->idFrom == IDC_USERACCOUNT_LINK && nmhdr->code == NM_CLICK)
815 {
816 ShellExecuteW(hwndDlg, NULL, L"usrmgr.cpl", NULL, NULL, 0);
817 }
818 else if (nmhdr->idFrom == IDC_USERPROFILE_LIST && nmhdr->code == LVN_ITEMCHANGED)
819 {
820 UpdateButtonState(hwndDlg, nmhdr->hwndFrom);
821 }
822 }
823
824
825 /* Property page dialog callback */
826 INT_PTR CALLBACK
827 UserProfileDlgProc(HWND hwndDlg,
828 UINT uMsg,
829 WPARAM wParam,
830 LPARAM lParam)
831 {
832 switch (uMsg)
833 {
834 case WM_INITDIALOG:
835 OnInitUserProfileDialog(hwndDlg);
836 return TRUE;
837
838 case WM_DESTROY:
839 OnDestroy(hwndDlg);
840 break;
841
842 case WM_COMMAND:
843 switch (LOWORD(wParam))
844 {
845 case IDOK:
846 case IDCANCEL:
847 EndDialog(hwndDlg,
848 LOWORD(wParam));
849 return TRUE;
850
851 case IDC_USERPROFILE_CHANGE:
852 ChangeUserProfileType(hwndDlg);
853 break;
854
855 case IDC_USERPROFILE_DELETE:
856 DeleteUserProfile(hwndDlg);
857 break;
858
859 case IDC_USERPROFILE_COPY:
860 CopyUserProfile(hwndDlg);
861 break;
862 }
863 break;
864
865 case WM_NOTIFY:
866 OnNotify(hwndDlg, (NMHDR *)lParam);
867 break;
868 }
869
870 return FALSE;
871 }