xref: /reactos/dll/cpl/usrmgr/users.c (revision 53221834)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS User Manager Control Panel
4  * FILE:            dll/cpl/usrmgr/users.c
5  * PURPOSE:         Users property page
6  *
7  * PROGRAMMERS:     Eric Kohl
8  */
9 
10 /*
11  * TODO:
12  *  - Add new user to the users group.
13  *  - Remove a user from all groups.
14  *  - Use localized messages.
15  */
16 
17 #include "usrmgr.h"
18 
19 typedef struct _USER_DATA
20 {
21     HMENU hPopupMenu;
22 
23     INT iCurrentItem;
24 
25 } USER_DATA, *PUSER_DATA;
26 
27 
28 
29 static BOOL
30 CheckPasswords(HWND hwndDlg,
31                INT nIdDlgItem1,
32                INT nIdDlgItem2)
33 {
34     TCHAR szPassword1[PWLEN];
35     TCHAR szPassword2[PWLEN];
36     UINT uLen1;
37     UINT uLen2;
38 
39     uLen1 = GetDlgItemText(hwndDlg, nIdDlgItem1, szPassword1, PWLEN);
40     uLen2 = GetDlgItemText(hwndDlg, nIdDlgItem2, szPassword2, PWLEN);
41 
42     /* Check the passwords */
43     if (uLen1 != uLen2 || _tcscmp(szPassword1, szPassword2) != 0)
44     {
45         MessageBox(hwndDlg,
46                    TEXT("The passwords you entered are not the same!"),
47                    TEXT("ERROR"),
48                    MB_OK | MB_ICONERROR);
49         return FALSE;
50     }
51 
52     return TRUE;
53 }
54 
55 
56 INT_PTR CALLBACK
57 ChangePasswordDlgProc(HWND hwndDlg,
58                       UINT uMsg,
59                       WPARAM wParam,
60                       LPARAM lParam)
61 {
62     PUSER_INFO_1003 userInfo;
63     INT nLength;
64 
65     UNREFERENCED_PARAMETER(wParam);
66 
67     userInfo = (PUSER_INFO_1003)GetWindowLongPtr(hwndDlg, DWLP_USER);
68 
69     switch (uMsg)
70     {
71         case WM_INITDIALOG:
72             userInfo = (PUSER_INFO_1003)lParam;
73             SetWindowLongPtr(hwndDlg, DWLP_USER, lParam);
74             break;
75 
76         case WM_COMMAND:
77             switch (LOWORD(wParam))
78             {
79                 case IDOK:
80                     if (CheckPasswords(hwndDlg, IDC_EDIT_PASSWORD1, IDC_EDIT_PASSWORD2))
81                     {
82 
83                         /* Store the password */
84                         nLength = SendDlgItemMessage(hwndDlg, IDC_EDIT_PASSWORD1, WM_GETTEXTLENGTH, 0, 0);
85                         if (nLength > 0)
86                         {
87                             userInfo->usri1003_password = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
88                             GetDlgItemText(hwndDlg, IDC_EDIT_PASSWORD1, userInfo->usri1003_password, nLength + 1);
89                         }
90 
91                         EndDialog(hwndDlg, IDOK);
92                     }
93                     break;
94 
95                 case IDCANCEL:
96                     EndDialog(hwndDlg, IDCANCEL);
97                     break;
98             }
99             break;
100 
101         default:
102             return FALSE;
103     }
104 
105     return TRUE;
106 }
107 
108 
109 static VOID
110 UserChangePassword(HWND hwndDlg)
111 {
112     TCHAR szUserName[UNLEN + 1];
113     USER_INFO_1003 user;
114     INT nItem;
115     HWND hwndLV;
116     NET_API_STATUS status;
117 
118     ZeroMemory(&user, sizeof(USER_INFO_1003));
119 
120     hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
121     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
122     if (nItem == -1)
123         return;
124 
125     /* Get the new user name */
126     ListView_GetItemText(hwndLV,
127                          nItem, 0,
128                          szUserName,
129                          UNLEN + 1);
130 
131     if (DialogBoxParam(hApplet,
132                        MAKEINTRESOURCE(IDD_CHANGE_PASSWORD),
133                        hwndDlg,
134                        ChangePasswordDlgProc,
135                        (LPARAM)&user) == IDOK)
136     {
137         status = NetUserSetInfo(NULL,
138                                 szUserName,
139                                 1003,
140                                 (LPBYTE)&user,
141                                 NULL);
142         if (status != NERR_Success)
143         {
144             TCHAR szText[256];
145             wsprintf(szText, TEXT("Error: %u"), status);
146             MessageBox(NULL, szText, TEXT("NetUserSetInfo"), MB_ICONERROR | MB_OK);
147         }
148     }
149 
150     if (user.usri1003_password)
151         HeapFree(GetProcessHeap(), 0, user.usri1003_password);
152 }
153 
154 
155 static VOID
156 UpdateNewUserOptions(HWND hwndDlg,
157                      PUSER_INFO_3 userInfo,
158                      BOOL bInit)
159 {
160     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_CANNOT_CHANGE),
161                  !userInfo->usri3_password_expired);
162     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_NEVER_EXPIRES),
163                  !userInfo->usri3_password_expired);
164 
165     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_FORCE_CHANGE),
166                  (userInfo->usri3_flags & (UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD)) == 0);
167 
168     if (bInit)
169     {
170         CheckDlgButton(hwndDlg, IDC_USER_NEW_FORCE_CHANGE,
171                        userInfo->usri3_password_expired ? BST_CHECKED : BST_UNCHECKED);
172 
173         CheckDlgButton(hwndDlg, IDC_USER_NEW_CANNOT_CHANGE,
174                        (userInfo->usri3_flags & UF_PASSWD_CANT_CHANGE) ? BST_CHECKED : BST_UNCHECKED);
175 
176         CheckDlgButton(hwndDlg, IDC_USER_NEW_NEVER_EXPIRES,
177                        (userInfo->usri3_flags & UF_DONT_EXPIRE_PASSWD) ? BST_CHECKED : BST_UNCHECKED);
178 
179         CheckDlgButton(hwndDlg, IDC_USER_NEW_DISABLED,
180                        (userInfo->usri3_flags & UF_ACCOUNTDISABLE) ? BST_CHECKED : BST_UNCHECKED);
181     }
182 }
183 
184 
185 INT_PTR CALLBACK
186 NewUserDlgProc(HWND hwndDlg,
187                UINT uMsg,
188                WPARAM wParam,
189                LPARAM lParam)
190 {
191     PUSER_INFO_3 userInfo;
192     INT nLength;
193 
194     UNREFERENCED_PARAMETER(wParam);
195 
196     userInfo = (PUSER_INFO_3)GetWindowLongPtr(hwndDlg, DWLP_USER);
197 
198     switch (uMsg)
199     {
200         case WM_INITDIALOG:
201             userInfo = (PUSER_INFO_3)lParam;
202             SetWindowLongPtr(hwndDlg, DWLP_USER, lParam);
203             SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, EM_SETLIMITTEXT, 20, 0);
204             UpdateNewUserOptions(hwndDlg, userInfo, TRUE);
205             break;
206 
207         case WM_COMMAND:
208             switch (LOWORD(wParam))
209             {
210                 case IDC_USER_NEW_NAME:
211                     if (HIWORD(wParam) == EN_CHANGE)
212                     {
213                         nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, WM_GETTEXTLENGTH, 0, 0);
214                         EnableWindow(GetDlgItem(hwndDlg, IDOK), (nLength > 0));
215                     }
216                     break;
217 
218                 case IDC_USER_NEW_FORCE_CHANGE:
219                     userInfo->usri3_password_expired = !userInfo->usri3_password_expired;
220                     UpdateNewUserOptions(hwndDlg, userInfo, FALSE);
221                     break;
222 
223                 case IDC_USER_NEW_CANNOT_CHANGE:
224                     userInfo->usri3_flags ^= UF_PASSWD_CANT_CHANGE;
225                     UpdateNewUserOptions(hwndDlg, userInfo, FALSE);
226                     break;
227 
228                 case IDC_USER_NEW_NEVER_EXPIRES:
229                     userInfo->usri3_flags ^= UF_DONT_EXPIRE_PASSWD;
230                     UpdateNewUserOptions(hwndDlg, userInfo, FALSE);
231                     break;
232 
233                 case IDC_USER_NEW_DISABLED:
234                     userInfo->usri3_flags ^= UF_ACCOUNTDISABLE;
235                     break;
236 
237                 case IDOK:
238                     if (!CheckAccountName(hwndDlg, IDC_USER_NEW_NAME, NULL))
239                     {
240                         SetFocus(GetDlgItem(hwndDlg, IDC_USER_NEW_NAME));
241                         SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, EM_SETSEL, 0, -1);
242                         break;
243                     }
244 
245                     if (!CheckPasswords(hwndDlg, IDC_USER_NEW_PASSWORD1, IDC_USER_NEW_PASSWORD2))
246                     {
247                         SetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD1, TEXT(""));
248                         SetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD2, TEXT(""));
249                         break;
250                     }
251 
252                     /* Store the user name */
253                     nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, WM_GETTEXTLENGTH, 0, 0);
254                     if (nLength > 0)
255                     {
256                         userInfo->usri3_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
257                         GetDlgItemText(hwndDlg, IDC_USER_NEW_NAME, userInfo->usri3_name, nLength + 1);
258                     }
259 
260                     /* Store the full user name */
261                     nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_FULL_NAME, WM_GETTEXTLENGTH, 0, 0);
262                     if (nLength > 0)
263                     {
264                         userInfo->usri3_full_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
265                         GetDlgItemText(hwndDlg, IDC_USER_NEW_FULL_NAME, userInfo->usri3_full_name, nLength + 1);
266                     }
267 
268                     /* Store the description */
269                     nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_DESCRIPTION, WM_GETTEXTLENGTH, 0, 0);
270                     if (nLength > 0)
271                     {
272                         userInfo->usri3_comment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
273                         GetDlgItemText(hwndDlg, IDC_USER_NEW_DESCRIPTION, userInfo->usri3_comment, nLength + 1);
274                     }
275 
276                     /* Store the password */
277                     nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_PASSWORD1, WM_GETTEXTLENGTH, 0, 0);
278                     if (nLength > 0)
279                     {
280                         userInfo->usri3_password = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
281                         GetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD1, userInfo->usri3_password, nLength + 1);
282                     }
283 
284                     EndDialog(hwndDlg, IDOK);
285                     break;
286 
287                 case IDCANCEL:
288                     EndDialog(hwndDlg, IDCANCEL);
289                     break;
290             }
291             break;
292 
293         default:
294             return FALSE;
295     }
296 
297     return TRUE;
298 }
299 
300 
301 static VOID
302 UserNew(HWND hwndDlg)
303 {
304     USER_INFO_3 user;
305     NET_API_STATUS status;
306     LV_ITEM lvi;
307     INT iItem;
308     HWND hwndLV;
309 
310     ZeroMemory(&user, sizeof(USER_INFO_3));
311 
312     user.usri3_priv = USER_PRIV_USER;
313     user.usri3_flags = UF_SCRIPT;
314     user.usri3_acct_expires = TIMEQ_FOREVER;
315     user.usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
316     user.usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
317 
318     user.usri3_password_expired = TRUE;
319 
320     if (DialogBoxParam(hApplet,
321                        MAKEINTRESOURCE(IDD_USER_NEW),
322                        hwndDlg,
323                        NewUserDlgProc,
324                        (LPARAM)&user) == IDOK)
325     {
326         status = NetUserAdd(NULL,
327                             3,
328                             (LPBYTE)&user,
329                             NULL);
330         if (status != NERR_Success)
331         {
332             TCHAR szText[256];
333             wsprintf(szText, TEXT("Error: %u"), status);
334             MessageBox(NULL, szText, TEXT("NetUserAdd"), MB_ICONERROR | MB_OK);
335             return;
336         }
337 
338         hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
339 
340         ZeroMemory(&lvi, sizeof(lvi));
341         lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
342         lvi.pszText = user.usri3_name;
343         lvi.state = 0;
344         lvi.iImage = (user.usri3_flags & UF_ACCOUNTDISABLE) ? 1 : 0;
345         iItem = ListView_InsertItem(hwndLV, &lvi);
346 
347         ListView_SetItemText(hwndLV, iItem, 1,
348                              user.usri3_full_name);
349 
350         ListView_SetItemText(hwndLV, iItem, 2,
351                              user.usri3_comment);
352     }
353 
354     if (user.usri3_name)
355         HeapFree(GetProcessHeap(), 0, user.usri3_name);
356 
357     if (user.usri3_full_name)
358         HeapFree(GetProcessHeap(), 0, user.usri3_full_name);
359 
360     if (user.usri3_comment)
361         HeapFree(GetProcessHeap(), 0, user.usri3_comment);
362 
363     if (user.usri3_password)
364         HeapFree(GetProcessHeap(), 0, user.usri3_password);
365 }
366 
367 
368 static VOID
369 UserRename(HWND hwndDlg)
370 {
371     HWND hwndLV;
372     INT nItem;
373 
374     hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
375     if (hwndLV == NULL)
376         return;
377 
378     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
379     if (nItem != -1)
380     {
381         (void)ListView_EditLabel(hwndLV, nItem);
382     }
383 }
384 
385 
386 static BOOL
387 UserDelete(HWND hwndDlg)
388 {
389     TCHAR szUserName[UNLEN + 1];
390     TCHAR szText[256];
391     INT nItem;
392     HWND hwndLV;
393     NET_API_STATUS status;
394 
395     hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
396     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
397     if (nItem == -1)
398         return FALSE;
399 
400     /* Get the new user name */
401     ListView_GetItemText(hwndLV,
402                          nItem, 0,
403                          szUserName,
404                          UNLEN + 1);
405 
406     /* Display a warning message because the delete operation cannot be reverted */
407     wsprintf(szText, TEXT("Do you really want to delete the user \"%s\"?"), szUserName);
408     if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO)
409         return FALSE;
410 
411     /* Delete the user */
412     status = NetUserDel(NULL, szUserName);
413     if (status != NERR_Success)
414     {
415         TCHAR szText[256];
416         wsprintf(szText, TEXT("Error: %u"), status);
417         MessageBox(NULL, szText, TEXT("NetUserDel"), MB_ICONERROR | MB_OK);
418         return FALSE;
419     }
420 
421     /* Delete the user from the list */
422     (void)ListView_DeleteItem(hwndLV, nItem);
423 
424     return TRUE;
425 }
426 
427 
428 static VOID
429 SetUsersListColumns(HWND hwndListView)
430 {
431     LV_COLUMN column;
432     RECT rect;
433     TCHAR szStr[32];
434 
435     GetClientRect(hwndListView, &rect);
436 
437     memset(&column, 0x00, sizeof(column));
438     column.mask=LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
439     column.fmt=LVCFMT_LEFT;
440     column.cx = (INT)((rect.right - rect.left) * 0.25);
441     column.iSubItem = 0;
442     LoadString(hApplet, IDS_NAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
443     column.pszText = szStr;
444     (void)ListView_InsertColumn(hwndListView, 0, &column);
445 
446     column.cx = (INT)((rect.right - rect.left) * 0.50);
447     column.iSubItem = 1;
448     LoadString(hApplet, IDS_FULLNAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
449     column.pszText = szStr;
450     (void)ListView_InsertColumn(hwndListView, 1, &column);
451 
452     column.cx = (INT)((rect.right - rect.left) * 0.25);
453     column.iSubItem = 2;
454     LoadString(hApplet, IDS_DESCRIPTION, szStr, sizeof(szStr) / sizeof(szStr[0]));
455     column.pszText = szStr;
456     (void)ListView_InsertColumn(hwndListView, 2, &column);
457 }
458 
459 
460 static VOID
461 UpdateUsersList(HWND hwndListView)
462 {
463     NET_API_STATUS netStatus;
464     PUSER_INFO_20 pBuffer;
465     DWORD entriesread;
466     DWORD totalentries;
467     DWORD resume_handle = 0;
468     DWORD i;
469     LV_ITEM lvi;
470     INT iItem;
471 
472     for (;;)
473     {
474         netStatus = NetUserEnum(NULL, 20, FILTER_NORMAL_ACCOUNT,
475                                 (LPBYTE*)&pBuffer,
476                                 1024, &entriesread,
477                                 &totalentries, &resume_handle);
478         if (netStatus != NERR_Success && netStatus != ERROR_MORE_DATA)
479             break;
480 
481         for (i = 0; i < entriesread; i++)
482         {
483            memset(&lvi, 0x00, sizeof(lvi));
484            lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
485            lvi.pszText = pBuffer[i].usri20_name;
486            lvi.state = 0;
487            lvi.iImage = (pBuffer[i].usri20_flags & UF_ACCOUNTDISABLE) ? 1 : 0;
488            iItem = ListView_InsertItem(hwndListView, &lvi);
489 
490            if (pBuffer[i].usri20_full_name != NULL)
491                ListView_SetItemText(hwndListView, iItem, 1,
492                                     pBuffer[i].usri20_full_name);
493 
494            if (pBuffer[i].usri20_comment != NULL)
495                ListView_SetItemText(hwndListView, iItem, 2,
496                                     pBuffer[i].usri20_comment);
497         }
498 
499         NetApiBufferFree(pBuffer);
500 
501         /* No more data left */
502         if (netStatus != ERROR_MORE_DATA)
503             break;
504     }
505 }
506 
507 
508 static VOID
509 OnInitDialog(HWND hwndDlg)
510 {
511     HWND hwndListView;
512     HIMAGELIST hImgList;
513     HICON hIcon;
514 
515     /* Create the image list */
516     hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 5);
517     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
518     ImageList_AddIcon(hImgList, hIcon);
519     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOCKED_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
520     ImageList_AddIcon(hImgList, hIcon);
521     DestroyIcon(hIcon);
522 
523     hwndListView = GetDlgItem(hwndDlg, IDC_USERS_LIST);
524 
525     (VOID)ListView_SetImageList(hwndListView, hImgList, LVSIL_SMALL);
526 
527     (void)ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT);
528 
529     SetUsersListColumns(hwndListView);
530 
531     UpdateUsersList(hwndListView);
532 }
533 
534 
535 static BOOL
536 OnBeginLabelEdit(LPNMLVDISPINFO pnmv)
537 {
538     HWND hwndEdit;
539 
540     hwndEdit = ListView_GetEditControl(pnmv->hdr.hwndFrom);
541     if (hwndEdit == NULL)
542         return TRUE;
543 
544     SendMessage(hwndEdit, EM_SETLIMITTEXT, 20, 0);
545 
546     return FALSE;
547 }
548 
549 
550 static BOOL
551 OnEndLabelEdit(LPNMLVDISPINFO pnmv)
552 {
553     TCHAR szOldUserName[UNLEN + 1];
554     TCHAR szNewUserName[UNLEN + 1];
555     USER_INFO_0 useri0;
556     NET_API_STATUS status;
557 
558     /* Leave, if there is no valid listview item */
559     if (pnmv->item.iItem == -1)
560         return FALSE;
561 
562     /* Get the new user name */
563     ListView_GetItemText(pnmv->hdr.hwndFrom,
564                          pnmv->item.iItem, 0,
565                          szOldUserName,
566                          UNLEN + 1);
567 
568     /* Leave, if the user canceled the edit action */
569     if (pnmv->item.pszText == NULL)
570         return FALSE;
571 
572     /* Get the new user name */
573     lstrcpy(szNewUserName, pnmv->item.pszText);
574 
575     /* Leave, if the user name was not changed */
576     if (lstrcmp(szOldUserName, szNewUserName) == 0)
577         return FALSE;
578 
579     /* Check the user name for illegal characters */
580     if (!CheckAccountName(NULL, 0, szNewUserName))
581         return FALSE;
582 
583     /* Change the user name */
584     useri0.usri0_name = szNewUserName;
585 
586     status = NetUserSetInfo(NULL, szOldUserName, 0, (LPBYTE)&useri0, NULL);
587     if (status != NERR_Success)
588     {
589         TCHAR szText[256];
590         wsprintf(szText, TEXT("Error: %u"), status);
591         MessageBox(NULL, szText, TEXT("NetUserSetInfo"), MB_ICONERROR | MB_OK);
592         return FALSE;
593     }
594 
595     /* Update the listview item */
596     ListView_SetItemText(pnmv->hdr.hwndFrom,
597                          pnmv->item.iItem, 0,
598                          szNewUserName);
599 
600     return TRUE;
601 }
602 
603 
604 static BOOL
605 OnNotify(HWND hwndDlg, PUSER_DATA pUserData, NMHDR *phdr)
606 {
607     LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)phdr;
608 
609     switch (phdr->idFrom)
610     {
611         case IDC_USERS_LIST:
612             switch(phdr->code)
613             {
614                 case NM_CLICK:
615                     pUserData->iCurrentItem = lpnmlv->iItem;
616                     break;
617 
618                 case NM_DBLCLK:
619                     if (lpnmlv->iItem != -1)
620                     {
621                         UINT uItem;
622 
623                         uItem =  GetMenuDefaultItem(GetSubMenu(pUserData->hPopupMenu, 1),
624                                                     FALSE, 0);
625                         if (uItem != (UINT)-1)
626                             SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(uItem, 0), 0);
627                     }
628                     break;
629 
630                 case NM_RCLICK:
631                     ClientToScreen(GetDlgItem(hwndDlg, IDC_USERS_LIST), &lpnmlv->ptAction);
632                     TrackPopupMenu(GetSubMenu(pUserData->hPopupMenu, (lpnmlv->iItem == -1) ? 0 : 1),
633                                    TPM_LEFTALIGN, lpnmlv->ptAction.x, lpnmlv->ptAction.y, 0, hwndDlg, NULL);
634                     break;
635 
636                 case LVN_BEGINLABELEDIT:
637                     return OnBeginLabelEdit((LPNMLVDISPINFO)phdr);
638 
639                 case LVN_ENDLABELEDIT:
640                     return OnEndLabelEdit((LPNMLVDISPINFO)phdr);
641             }
642             break;
643     }
644 
645     return FALSE;
646 }
647 
648 
649 static VOID
650 UpdateUserProperties(HWND hwndDlg)
651 {
652     TCHAR szUserName[UNLEN + 1];
653     INT iItem;
654     HWND hwndLV;
655     PUSER_INFO_2 pUserInfo = NULL;
656     LV_ITEM lvi;
657 
658     hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
659     iItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
660     if (iItem == -1)
661         return;
662 
663     /* Get the new user name */
664     ListView_GetItemText(hwndLV,
665                          iItem, 0,
666                          szUserName,
667                          UNLEN + 1);
668 
669     NetUserGetInfo(NULL, szUserName, 2, (LPBYTE*)&pUserInfo);
670 
671     memset(&lvi, 0x00, sizeof(lvi));
672     lvi.iItem = iItem;
673     lvi.iSubItem = 0;
674     lvi.mask = LVIF_IMAGE;
675     lvi.iImage = (pUserInfo->usri2_flags & UF_ACCOUNTDISABLE) ? 1 : 0;
676     (void)ListView_SetItem(hwndLV, &lvi);
677 
678     ListView_SetItemText(hwndLV, iItem, 1,
679                          pUserInfo->usri2_full_name);
680 
681     ListView_SetItemText(hwndLV, iItem, 2,
682                          pUserInfo->usri2_comment);
683 
684     NetApiBufferFree(pUserInfo);
685 }
686 
687 
688 INT_PTR CALLBACK
689 UsersPageProc(HWND hwndDlg,
690               UINT uMsg,
691               WPARAM wParam,
692               LPARAM lParam)
693 {
694     PUSER_DATA pUserData;
695 
696     UNREFERENCED_PARAMETER(wParam);
697 
698     pUserData = (PUSER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
699 
700     switch (uMsg)
701     {
702         case WM_INITDIALOG:
703             pUserData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USER_DATA));
704             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pUserData);
705 
706             pUserData->hPopupMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDM_POPUP_USER));
707 
708             OnInitDialog(hwndDlg);
709             SetMenuDefaultItem(GetSubMenu(pUserData->hPopupMenu, 1),
710                                IDM_USER_PROPERTIES,
711                                FALSE);
712             break;
713 
714         case WM_COMMAND:
715             switch (LOWORD(wParam))
716             {
717                 case IDM_USER_CHANGE_PASSWORD:
718                     UserChangePassword(hwndDlg);
719                     break;
720 
721                 case IDM_USER_RENAME:
722                     UserRename(hwndDlg);
723                     break;
724 
725                 case IDM_USER_NEW:
726                 case IDC_USERS_ADD:
727                     UserNew(hwndDlg);
728                     break;
729 
730                 case IDM_USER_DELETE:
731                 case IDC_USERS_REMOVE:
732                     UserDelete(hwndDlg);
733                     break;
734 
735                 case IDM_USER_PROPERTIES:
736                 case IDC_USERS_PROPERTIES:
737                     if (UserProperties(hwndDlg))
738                     {
739                         UpdateUserProperties(hwndDlg);
740                     }
741                     break;
742             }
743             break;
744 
745         case WM_NOTIFY:
746             return OnNotify(hwndDlg, pUserData, (NMHDR *)lParam);
747 
748         case WM_DESTROY:
749             DestroyMenu(pUserData->hPopupMenu);
750             HeapFree(GetProcessHeap(), 0, pUserData);
751             break;
752     }
753 
754     return FALSE;
755 }
756