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