reactos/dll/cpl/sysdm/userprofile.c
Eric Kohl ba783adf1e [SYSDM] Improve the user profile dialog
- Currently used profiles cannot be copied or deleted.
- Unknown profiles cannot be copied.
- A double click on a profile opens the change profile type dialog.
2020-01-04 14:54:30 +01:00

900 lines
23 KiB
C

/*
* PROJECT: ReactOS System Control Panel Applet
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/cpl/sysdm/userprofile.c
* PURPOSE: Computer settings for networking
* COPYRIGHT: Copyright Thomas Weidenmueller <w3seek@reactos.org>
* Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
*
*/
#include "precomp.h"
#include <sddl.h>
#include <winnls.h>
#include <debug.h>
typedef struct _PROFILEDATA
{
DWORD dwRefCount;
DWORD dwState;
BOOL bUnknownProfile;
PWSTR pszFullName;
PWSTR pszProfilePath;
} PROFILEDATA, *PPROFILEDATA;
static
BOOL
OnProfileTypeInit(
_In_ HWND hwndDlg,
_In_ PPROFILEDATA pProfileData)
{
PWSTR pszRawBuffer = NULL, pszCookedBuffer = NULL;
INT nLength;
nLength = LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, (PWSTR)&pszRawBuffer, 0);
pszRawBuffer = NULL;
if (nLength == 0)
return FALSE;
pszRawBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(WCHAR));
if (pszRawBuffer == NULL)
return FALSE;
LoadStringW(hApplet, IDS_USERPROFILE_TYPE_TEXT, pszRawBuffer, nLength + 1);
pszCookedBuffer = HeapAlloc(GetProcessHeap(), 0, (nLength + wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR));
if (pszCookedBuffer == NULL)
goto done;
swprintf(pszCookedBuffer, pszRawBuffer, pProfileData->pszFullName);
/* Set the full text */
SetDlgItemText(hwndDlg, IDC_USERPROFILE_TYPE_TEXT, pszCookedBuffer);
/* FIXME: Right now, we support local user profiles only! */
EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_ROAMING), FALSE);
Button_SetCheck(GetDlgItem(hwndDlg, IDC_USERPROFILE_TYPE_LOCAL), BST_CHECKED);
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
done:
if (pszCookedBuffer != NULL)
HeapFree(GetProcessHeap(), 0, pszCookedBuffer);
if (pszRawBuffer != NULL)
HeapFree(GetProcessHeap(), 0, pszRawBuffer);
return TRUE;
}
static
INT_PTR
CALLBACK
UserProfileTypeDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
OnProfileTypeInit(hwndDlg, (PPROFILEDATA)lParam);
return TRUE;
case WM_DESTROY:
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwndDlg,
LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
static
BOOL
ChangeUserProfileType(
_In_ HWND hwndDlg)
{
HWND hwndListView;
LVITEM Item;
INT iSelected;
DPRINT("ChangeUserProfileType(%p)\n", hwndDlg);
hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
if (hwndListView == NULL)
return FALSE;
iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
if (iSelected == -1)
return FALSE;
ZeroMemory(&Item, sizeof(LVITEM));
Item.mask = LVIF_PARAM;
Item.iItem = iSelected;
Item.iSubItem = 0;
if (!ListView_GetItem(hwndListView, &Item))
return FALSE;
if (Item.lParam == 0)
return FALSE;
if (DialogBoxParam(hApplet,
MAKEINTRESOURCE(IDD_USERPROFILE_TYPE),
hwndDlg,
UserProfileTypeDlgProc,
(LPARAM)Item.lParam) == IDOK)
{
/* FIXME: Update the profile list view */
return TRUE;
}
return FALSE;
}
static
BOOL
DeleteUserProfile(
_In_ HWND hwndDlg)
{
WCHAR szTitle[64], szRawText[128], szCookedText[256];
HWND hwndListView;
LVITEM Item;
INT iSelected;
PPROFILEDATA pProfileData;
DPRINT("DeleteUserProfile()\n");
hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
if (hwndListView == NULL)
return FALSE;
iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
if (iSelected == -1)
return FALSE;
ZeroMemory(&Item, sizeof(LVITEM));
Item.mask = LVIF_PARAM;
Item.iItem = iSelected;
Item.iSubItem = 0;
if (!ListView_GetItem(hwndListView, &Item))
return FALSE;
if (Item.lParam == 0)
return FALSE;
pProfileData = (PPROFILEDATA)Item.lParam;
if (pProfileData->dwRefCount != 0)
return FALSE;
LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE_TITLE, szTitle, ARRAYSIZE(szTitle));
LoadStringW(hApplet, IDS_USERPROFILE_CONFIRM_DELETE, szRawText, ARRAYSIZE(szRawText));
swprintf(szCookedText, szRawText, pProfileData->pszFullName);
if (MessageBoxW(hwndDlg,
szCookedText,
szTitle,
MB_ICONQUESTION | MB_YESNO) == IDYES)
{
/* FIXME: Delete the profile here! */
return TRUE;
}
return FALSE;
}
static
INT_PTR
CALLBACK
CopyUserProfileDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_DESTROY:
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwndDlg,
LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
static
BOOL
CopyUserProfile(
_In_ HWND hwndDlg)
{
HWND hwndListView;
LVITEM Item;
INT iSelected;
DPRINT("CopyUserProfile()\n");
hwndListView = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
if (hwndListView == NULL)
return FALSE;
iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
if (iSelected == -1)
return FALSE;
ZeroMemory(&Item, sizeof(LVITEM));
Item.mask = LVIF_PARAM;
Item.iItem = iSelected;
Item.iSubItem = 0;
if (!ListView_GetItem(hwndListView, &Item))
return FALSE;
if (Item.lParam == 0)
return FALSE;
if (DialogBoxParam(hApplet,
MAKEINTRESOURCE(IDD_USERPROFILE_COPY),
hwndDlg,
CopyUserProfileDlgProc,
(LPARAM)Item.lParam) == IDOK)
{
/* FIXME: Update the profile list view */
return TRUE;
}
return FALSE;
}
static VOID
SetListViewColumns(
_In_ HWND hwndListView)
{
LV_COLUMN column;
RECT rect;
TCHAR szStr[32];
GetClientRect(hwndListView, &rect);
SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
memset(&column, 0x00, sizeof(column));
column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
column.fmt = LVCFMT_LEFT;
column.cx = (INT)((rect.right - rect.left) * 0.40);
column.iSubItem = 0;
LoadString(hApplet, IDS_USERPROFILE_NAME, szStr, ARRAYSIZE(szStr));
column.pszText = szStr;
(void)ListView_InsertColumn(hwndListView, 0, &column);
column.fmt = LVCFMT_RIGHT;
column.cx = (INT)((rect.right - rect.left) * 0.15);
column.iSubItem = 1;
LoadString(hApplet, IDS_USERPROFILE_SIZE, szStr, ARRAYSIZE(szStr));
column.pszText = szStr;
(void)ListView_InsertColumn(hwndListView, 1, &column);
column.fmt = LVCFMT_LEFT;
column.cx = (INT)((rect.right - rect.left) * 0.15);
column.iSubItem = 2;
LoadString(hApplet, IDS_USERPROFILE_TYPE, szStr, ARRAYSIZE(szStr));
column.pszText = szStr;
(void)ListView_InsertColumn(hwndListView, 2, &column);
column.fmt = LVCFMT_LEFT;
column.cx = (INT)((rect.right - rect.left) * 0.15);
column.iSubItem = 3;
LoadString(hApplet, IDS_USERPROFILE_STATUS, szStr, ARRAYSIZE(szStr));
column.pszText = szStr;
(void)ListView_InsertColumn(hwndListView, 3, &column);
column.fmt = LVCFMT_LEFT;
column.cx = (INT)((rect.right - rect.left) * 0.15) - GetSystemMetrics(SM_CYHSCROLL);
column.iSubItem = 4;
LoadString(hApplet, IDS_USERPROFILE_MODIFIED, szStr, ARRAYSIZE(szStr));
column.pszText = szStr;
(void)ListView_InsertColumn(hwndListView, 4, &column);
}
static
BOOL
GetProfileSize(
_In_ PWSTR pszProfilePath,
_Inout_ PULONGLONG pullProfileSize)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA FindData;
DWORD dwProfilePathLength;
ULARGE_INTEGER Size;
BOOL bResult = TRUE;
dwProfilePathLength = wcslen(pszProfilePath);
wcscat(pszProfilePath, L"\\*.*");
hFile = FindFirstFileW(pszProfilePath, &FindData);
if (hFile == INVALID_HANDLE_VALUE)
{
if ((GetLastError() != ERROR_FILE_NOT_FOUND) &&
(GetLastError() != ERROR_PATH_NOT_FOUND))
bResult = FALSE;
goto done;
}
do
{
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((_wcsicmp(FindData.cFileName, L".") == 0) ||
(_wcsicmp(FindData.cFileName, L"..") == 0))
continue;
pszProfilePath[dwProfilePathLength + 1] = UNICODE_NULL;
wcscat(pszProfilePath, FindData.cFileName);
if (!GetProfileSize(pszProfilePath, pullProfileSize))
{
bResult = FALSE;
goto done;
}
}
else
{
Size.u.LowPart = FindData.nFileSizeLow;
Size.u.HighPart = FindData.nFileSizeHigh;
*pullProfileSize += Size.QuadPart;
}
}
while (FindNextFile(hFile, &FindData));
done:
pszProfilePath[dwProfilePathLength] = UNICODE_NULL;
if (hFile != INVALID_HANDLE_VALUE)
FindClose(hFile);
return bResult;
}
static
BOOL
GetProfileName(
_In_ PSID pProfileSid,
_In_ DWORD dwNameBufferSize,
_Out_ PWSTR pszNameBuffer,
_Out_ PBOOL pbUnknownProfile)
{
WCHAR szAccountName[128], szDomainName[128];
DWORD dwAccountNameSize, dwDomainNameSize;
SID_NAME_USE Use;
dwAccountNameSize = ARRAYSIZE(szAccountName);
dwDomainNameSize = ARRAYSIZE(szDomainName);
if (!LookupAccountSidW(NULL,
pProfileSid,
szAccountName,
&dwAccountNameSize,
szDomainName,
&dwDomainNameSize,
&Use))
{
/* Unknown account */
LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_UNKNOWN, pszNameBuffer, dwNameBufferSize);
*pbUnknownProfile = TRUE;
}
else
{
/* Show only the user accounts */
if (Use != SidTypeUser)
return FALSE;
if (szAccountName[0] == UNICODE_NULL)
{
/* Deleted account */
LoadStringW(hApplet, IDS_USERPROFILE_ACCOUNT_DELETED, pszNameBuffer, dwNameBufferSize);
}
else
{
/* Normal account */
wsprintf(pszNameBuffer, L"%s\\%s", szDomainName, szAccountName);
}
*pbUnknownProfile = FALSE;
}
return TRUE;
}
static
VOID
FormatProfileSize(
_Out_ LPWSTR Buffer,
_In_ double size)
{
const LPWSTR units[] = {L"MB", L"GB", L"TB"};
int i = 0, j;
size /= 1024;
size /= 1024;
while (size >= 1024 && i < 3)
{
size /= 1024;
i++;
}
if (size < 10)
j = 2;
else if (size < 100)
j = 1;
else
j = 0;
swprintf(Buffer, L"%.*f %s", j, size, units[i]);
}
static VOID
AddUserProfile(
_In_ HWND hwndListView,
_In_ PSID pProfileSid,
_In_ HKEY hProfileKey)
{
WCHAR szTempProfilePath[MAX_PATH], szProfilePath[MAX_PATH];
WCHAR szNameBuffer[256];
PPROFILEDATA pProfileData = NULL;
DWORD dwProfileData, dwSize, dwType, dwState = 0, dwRefCount = 0;
DWORD dwProfilePathLength;
PWSTR ptr;
INT nId, iItem;
LV_ITEM lvi;
WIN32_FIND_DATA FindData;
HANDLE hFile;
SYSTEMTIME SystemTime;
ULONGLONG ullProfileSize;
BOOL bUnknownProfile;
DWORD dwError;
/* Get the profile path */
dwSize = MAX_PATH * sizeof(WCHAR);
dwError = RegQueryValueExW(hProfileKey,
L"ProfileImagePath",
NULL,
&dwType,
(LPBYTE)szTempProfilePath,
&dwSize);
if (dwError != ERROR_SUCCESS)
return;
/* Expand it */
ExpandEnvironmentStringsW(szTempProfilePath,
szProfilePath,
MAX_PATH);
/* Check if the profile path exists */
hFile = FindFirstFileW(szProfilePath, &FindData);
if (hFile == INVALID_HANDLE_VALUE)
return;
FindClose(hFile);
/* Get the length of the profile path */
dwProfilePathLength = wcslen(szProfilePath);
/* Check for the ntuser.dat file */
wcscat(szProfilePath, L"\\ntuser.dat");
hFile = FindFirstFileW(szProfilePath, &FindData);
if (hFile == INVALID_HANDLE_VALUE)
return;
FindClose(hFile);
szProfilePath[dwProfilePathLength] = UNICODE_NULL;
/* Get the profile size */
ullProfileSize = 0ULL;
GetProfileSize(szProfilePath, &ullProfileSize);
/* Get the profile name */
if (!GetProfileName(pProfileSid,
ARRAYSIZE(szNameBuffer),
szNameBuffer,
&bUnknownProfile))
return;
/* Get the profile state value */
dwSize = sizeof(dwState);
if (RegQueryValueExW(hProfileKey,
L"State",
NULL,
&dwType,
(LPBYTE)&dwState,
&dwSize) != ERROR_SUCCESS)
{
dwState = 0;
}
/* Get the profile reference counter */
dwSize = sizeof(dwRefCount);
if (RegQueryValueExW(hProfileKey,
L"RefCount",
NULL,
&dwType,
(LPBYTE)&dwRefCount,
&dwSize) != ERROR_SUCCESS)
{
dwRefCount = 0;
}
/* Create and fill the profile data entry */
dwProfileData = sizeof(PROFILEDATA) +
((wcslen(szNameBuffer) + 1) * sizeof(WCHAR)) +
((wcslen(szProfilePath) + 1) * sizeof(WCHAR));
pProfileData = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwProfileData);
if (pProfileData == NULL)
return;
pProfileData->dwRefCount = dwRefCount;
pProfileData->dwState = dwState;
pProfileData->bUnknownProfile = bUnknownProfile;
ptr = (PWSTR)((ULONG_PTR)pProfileData + sizeof(PROFILEDATA));
pProfileData->pszFullName = ptr;
wcscpy(pProfileData->pszFullName, szNameBuffer);
ptr = (PWSTR)((ULONG_PTR)ptr + ((wcslen(pProfileData->pszFullName) + 1) * sizeof(WCHAR)));
pProfileData->pszProfilePath = ptr;
wcscpy(pProfileData->pszProfilePath, szProfilePath);
/* Add the profile and set its name */
memset(&lvi, 0x00, sizeof(lvi));
lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
lvi.pszText = pProfileData->pszFullName;
lvi.state = 0;
lvi.lParam = (LPARAM)pProfileData;
iItem = ListView_InsertItem(hwndListView, &lvi);
/* Set the profile size */
FormatProfileSize(szNameBuffer, (double)ullProfileSize);
ListView_SetItemText(hwndListView, iItem, 1, szNameBuffer);
/* Set the profile type */
if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
nId = IDS_USERPROFILE_ROAMING;
else
nId = IDS_USERPROFILE_LOCAL;
LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
ListView_SetItemText(hwndListView, iItem, 2, szNameBuffer);
/* FIXME: Set the profile status */
if (dwState & 0x0001) // PROFILE_MANDATORY
nId = IDS_USERPROFILE_MANDATORY;
else if (dwState & 0x0010) // PROFILE_UPDATE_CENTRAL
nId = IDS_USERPROFILE_ROAMING;
else
nId = IDS_USERPROFILE_LOCAL;
LoadStringW(hApplet, nId, szNameBuffer, ARRAYSIZE(szNameBuffer));
ListView_SetItemText(hwndListView, iItem, 3, szNameBuffer);
/* Set the profile modified time */
FileTimeToSystemTime(&FindData.ftLastWriteTime,
&SystemTime);
GetDateFormatW(LOCALE_USER_DEFAULT,
DATE_SHORTDATE,
&SystemTime,
NULL,
szNameBuffer,
ARRAYSIZE(szNameBuffer));
ListView_SetItemText(hwndListView, iItem, 4, szNameBuffer);
}
static VOID
UpdateButtonState(
_In_ HWND hwndDlg,
_In_ HWND hwndListView)
{
LVITEM Item;
INT iSelected;
BOOL bChange = FALSE;
BOOL bCopy = FALSE;
BOOL bDelete = FALSE;
PPROFILEDATA pProfileData;
if (ListView_GetSelectedCount(hwndListView) != 0)
{
iSelected = ListView_GetNextItem(hwndListView, -1, LVNI_SELECTED);
if (iSelected != -1)
{
Item.mask = LVIF_PARAM;
Item.iItem = iSelected;
Item.iSubItem = 0;
if (ListView_GetItem(hwndListView, &Item))
{
if (Item.lParam != 0)
{
pProfileData = (PPROFILEDATA)Item.lParam;
if (pProfileData->bUnknownProfile)
{
bDelete = TRUE;
bCopy = FALSE;
}
else
{
bDelete = (pProfileData->dwRefCount == 0);
bCopy = (pProfileData->dwRefCount == 0);
}
}
}
bChange = TRUE;
}
}
EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_CHANGE), bChange);
EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bDelete);
EnableWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bCopy);
}
static VOID
AddUserProfiles(
_In_ HWND hwndDlg,
_In_ HWND hwndListView,
_In_ BOOL bAdmin)
{
HKEY hKeyUserProfiles = INVALID_HANDLE_VALUE;
HKEY hProfileKey;
DWORD dwIndex;
WCHAR szProfileSid[64];
DWORD dwSidLength;
FILETIME ftLastWrite;
DWORD dwSize;
HANDLE hToken = NULL;
PTOKEN_USER pTokenUser = NULL;
PSID pProfileSid;
PWSTR pszProfileSid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return;
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
if (dwSize == 0)
goto done;
pTokenUser = HeapAlloc(GetProcessHeap(), 0, dwSize);
if (pTokenUser == NULL)
goto done;
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
goto done;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
0,
KEY_READ,
&hKeyUserProfiles))
goto done;
if (bAdmin)
{
for (dwIndex = 0; ; dwIndex++)
{
dwSidLength = ARRAYSIZE(szProfileSid);
if (RegEnumKeyExW(hKeyUserProfiles,
dwIndex,
szProfileSid,
&dwSidLength,
NULL,
NULL,
NULL,
&ftLastWrite))
break;
if (RegOpenKeyExW(hKeyUserProfiles,
szProfileSid,
0,
KEY_READ,
&hProfileKey) == ERROR_SUCCESS)
{
if (ConvertStringSidToSid(szProfileSid, &pProfileSid))
{
AddUserProfile(hwndListView,
pProfileSid,
hProfileKey);
LocalFree(pProfileSid);
}
RegCloseKey(hProfileKey);
}
}
}
else
{
if (ConvertSidToStringSidW(pTokenUser->User.Sid, &pszProfileSid))
{
if (RegOpenKeyExW(hKeyUserProfiles,
pszProfileSid,
0,
KEY_READ,
&hProfileKey) == ERROR_SUCCESS)
{
AddUserProfile(hwndListView,
pTokenUser->User.Sid,
hProfileKey);
RegCloseKey(hProfileKey);
}
LocalFree(pszProfileSid);
}
}
if (ListView_GetItemCount(hwndListView) != 0)
ListView_SetItemState(hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
UpdateButtonState(hwndDlg, hwndListView);
done:
if (hKeyUserProfiles != INVALID_HANDLE_VALUE)
RegCloseKey(hKeyUserProfiles);
if (pTokenUser != NULL)
HeapFree(GetProcessHeap(), 0, pTokenUser);
if (hToken != NULL)
CloseHandle(hToken);
}
static VOID
OnInitUserProfileDialog(HWND hwndDlg)
{
BOOL bAdmin;
bAdmin = IsUserAdmin();
/* Initialize the list view control */
SetListViewColumns(GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST));
/* Hide the delete and copy buttons for non-admins */
ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_DELETE), bAdmin ? SW_SHOW : SW_HIDE);
ShowWindow(GetDlgItem(hwndDlg, IDC_USERPROFILE_COPY), bAdmin ? SW_SHOW : SW_HIDE);
/* Add the profiles to the list view */
AddUserProfiles(hwndDlg, GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST), bAdmin);
}
static
VOID
OnDestroy(
_In_ HWND hwndDlg)
{
HWND hwndList;
INT nItems, i;
LVITEM Item;
hwndList = GetDlgItem(hwndDlg, IDC_USERPROFILE_LIST);
nItems = ListView_GetItemCount(hwndList);
for (i = 0; i < nItems; i++)
{
Item.iItem = i;
Item.iSubItem = 0;
if (ListView_GetItem(hwndList, &Item))
{
if (Item.lParam != 0)
HeapFree(GetProcessHeap(), 0, (PVOID)Item.lParam);
}
}
}
static
VOID
OnNotify(
_In_ HWND hwndDlg,
_In_ NMHDR *nmhdr)
{
if (nmhdr->idFrom == IDC_USERACCOUNT_LINK && nmhdr->code == NM_CLICK)
{
ShellExecuteW(hwndDlg, NULL, L"usrmgr.cpl", NULL, NULL, 0);
}
else if (nmhdr->idFrom == IDC_USERPROFILE_LIST)
{
if (nmhdr->code == LVN_ITEMCHANGED)
UpdateButtonState(hwndDlg, nmhdr->hwndFrom);
else if (nmhdr->code == NM_DBLCLK)
ChangeUserProfileType(hwndDlg);
}
}
/* Property page dialog callback */
INT_PTR CALLBACK
UserProfileDlgProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
OnInitUserProfileDialog(hwndDlg);
return TRUE;
case WM_DESTROY:
OnDestroy(hwndDlg);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
EndDialog(hwndDlg,
LOWORD(wParam));
return TRUE;
case IDC_USERPROFILE_CHANGE:
ChangeUserProfileType(hwndDlg);
break;
case IDC_USERPROFILE_DELETE:
DeleteUserProfile(hwndDlg);
break;
case IDC_USERPROFILE_COPY:
CopyUserProfile(hwndDlg);
break;
}
break;
case WM_NOTIFY:
OnNotify(hwndDlg, (NMHDR *)lParam);
break;
}
return FALSE;
}