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