xref: /reactos/dll/cpl/usrmgr/groupprops.c (revision 8532f187)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS User Manager Control Panel
4  * FILE:            dll/cpl/usrmgr/groupprops.c
5  * PURPOSE:         Group property sheet
6  *
7  * PROGRAMMERS:     Eric Kohl
8  */
9 
10 #include "usrmgr.h"
11 
12 typedef struct _GENERAL_GROUP_DATA
13 {
14     TCHAR szGroupName[1];
15 } GENERAL_GROUP_DATA, *PGENERAL_GROUP_DATA;
16 
17 
18 static VOID
GetTextSid(PSID pSid,LPTSTR pTextSid)19 GetTextSid(PSID pSid,
20            LPTSTR pTextSid)
21 {
22     PSID_IDENTIFIER_AUTHORITY psia;
23     DWORD dwSubAuthorities;
24     DWORD dwSidRev = SID_REVISION;
25     DWORD dwCounter;
26     DWORD dwSidSize;
27 
28     psia = GetSidIdentifierAuthority(pSid);
29 
30     dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
31 
32     dwSidSize = wsprintf(pTextSid, TEXT("S-%lu-"), dwSidRev);
33 
34     if ((psia->Value[0] != 0) || (psia->Value[1] != 0))
35     {
36         dwSidSize += wsprintf(pTextSid + lstrlen(pTextSid),
37                               TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
38                               (USHORT)psia->Value[0],
39                               (USHORT)psia->Value[1],
40                               (USHORT)psia->Value[2],
41                               (USHORT)psia->Value[3],
42                               (USHORT)psia->Value[4],
43                               (USHORT)psia->Value[5]);
44     }
45     else
46     {
47         dwSidSize += wsprintf(pTextSid + lstrlen(pTextSid),
48                               TEXT("%lu"),
49                               (ULONG)(psia->Value[5]) +
50                               (ULONG)(psia->Value[4] <<  8) +
51                               (ULONG)(psia->Value[3] << 16) +
52                               (ULONG)(psia->Value[2] << 24));
53     }
54 
55     for (dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++)
56     {
57         dwSidSize += wsprintf(pTextSid + dwSidSize, TEXT("-%lu"),
58                               *GetSidSubAuthority(pSid, dwCounter));
59     }
60 }
61 
62 
63 static VOID
InitGroupMembersList(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)64 InitGroupMembersList(HWND hwndDlg,
65                      PGENERAL_GROUP_DATA pGroupData)
66 {
67     HWND hwndLV;
68     LV_COLUMN column;
69     RECT rect;
70     TCHAR szStr[32];
71     HIMAGELIST hImgList;
72     HICON hIcon;
73 
74     NET_API_STATUS netStatus;
75     PUSER_INFO_20 pUserBuffer;
76     DWORD entriesread;
77     DWORD totalentries;
78     DWORD resume_handle = 0;
79     DWORD i;
80     LV_ITEM lvi;
81     INT iItem;
82 
83     hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST);
84     GetClientRect(hwndLV, &rect);
85 
86     hImgList = ImageList_Create(16,16,ILC_COLOR32 | ILC_MASK,5,5);
87     hIcon = LoadImage(hApplet,MAKEINTRESOURCE(IDI_GROUP),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
88     ImageList_AddIcon(hImgList,hIcon);
89     DestroyIcon(hIcon);
90     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
91     ImageList_AddIcon(hImgList, hIcon);
92     DestroyIcon(hIcon);
93     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOCKED_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
94     ImageList_AddIcon(hImgList, hIcon);
95     DestroyIcon(hIcon);
96 
97     (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
98     (void)ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT);
99 
100     memset(&column, 0x00, sizeof(column));
101     column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
102     column.fmt = LVCFMT_LEFT;
103     column.cx = (INT)((rect.right - rect.left) * 0.40);
104     column.iSubItem = 0;
105     LoadString(hApplet, IDS_NAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
106     column.pszText = szStr;
107     (void)ListView_InsertColumn(hwndLV, 0, &column);
108 
109     column.cx = (INT)((rect.right - rect.left) * 0.60);
110     column.iSubItem = 1;
111     LoadString(hApplet, IDS_DESCRIPTION, szStr, sizeof(szStr) / sizeof(szStr[0]));
112     column.pszText = szStr;
113     (void)ListView_InsertColumn(hwndLV, 1, &column);
114 
115     /* TODO: Enumerate global groups and add them to the list! */
116 
117     for (;;)
118     {
119         netStatus = NetUserEnum(NULL, 20, FILTER_NORMAL_ACCOUNT,
120                                 (LPBYTE*)&pUserBuffer,
121                                 1024, &entriesread,
122                                 &totalentries, &resume_handle);
123         if (netStatus != NERR_Success && netStatus != ERROR_MORE_DATA)
124             break;
125 
126         for (i = 0; i < entriesread; i++)
127         {
128            memset(&lvi, 0x00, sizeof(lvi));
129            lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
130            lvi.pszText = pUserBuffer[i].usri20_name;
131            lvi.state = 0;
132            lvi.iImage = (pUserBuffer[i].usri20_flags & UF_ACCOUNTDISABLE) ? 2 : 1;
133            iItem = ListView_InsertItem(hwndLV, &lvi);
134 
135            ListView_SetItemText(hwndLV, iItem, 1,
136                                 pUserBuffer[i].usri20_full_name);
137 
138            ListView_SetItemText(hwndLV, iItem, 2,
139                                 pUserBuffer[i].usri20_comment);
140         }
141 
142         NetApiBufferFree(pUserBuffer);
143 
144         /* No more data left */
145         if (netStatus != ERROR_MORE_DATA)
146             break;
147     }
148 }
149 
150 
151 static BOOL
AddSelectedUsersToGroup(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)152 AddSelectedUsersToGroup(HWND hwndDlg,
153                         PGENERAL_GROUP_DATA pGroupData)
154 {
155     HWND hwndLV;
156     INT nSelectedItems;
157     INT nItem;
158     TCHAR szUserName[UNLEN + 1];
159     BOOL bResult = FALSE;
160     LOCALGROUP_MEMBERS_INFO_3 memberInfo;
161     NET_API_STATUS status;
162 
163     hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST);
164 
165     nSelectedItems = ListView_GetSelectedCount(hwndLV);
166     if (nSelectedItems > 0)
167     {
168         nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
169         while (nItem != -1)
170         {
171             /* Get the new user name */
172             ListView_GetItemText(hwndLV,
173                                  nItem, 0,
174                                  szUserName,
175                                  UNLEN + 1);
176             TRACE("Selected user: %s", dbgstrx(szUserName));
177 
178             memberInfo.lgrmi3_domainandname = szUserName;
179 
180             status = NetLocalGroupAddMembers(NULL, pGroupData->szGroupName, 3,
181                                              (LPBYTE)&memberInfo, 1);
182             if (status != NERR_Success && status != ERROR_MEMBER_IN_ALIAS)
183             {
184                 TCHAR szText[256];
185                 wsprintf(szText, TEXT("Error: %u"), status);
186                 MessageBox(NULL, szText, TEXT("NetLocalGroupAddMembers"), MB_ICONERROR | MB_OK);
187             }
188             else
189             {
190                 bResult = TRUE;
191             }
192 
193             nItem = ListView_GetNextItem(hwndLV, nItem, LVNI_SELECTED);
194         }
195     }
196 
197     return bResult;
198 }
199 
200 
201 INT_PTR CALLBACK
AddUsersToGroupDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)202 AddUsersToGroupDlgProc(HWND hwndDlg,
203                       UINT uMsg,
204                       WPARAM wParam,
205                       LPARAM lParam)
206 {
207     PGENERAL_GROUP_DATA pGroupData;
208 
209     UNREFERENCED_PARAMETER(wParam);
210 
211     pGroupData = (PGENERAL_GROUP_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
212 
213     switch (uMsg)
214     {
215         case WM_INITDIALOG:
216             pGroupData = (PGENERAL_GROUP_DATA)lParam;
217             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pGroupData);
218             InitGroupMembersList(hwndDlg, pGroupData);
219             break;
220 
221         case WM_COMMAND:
222             switch (LOWORD(wParam))
223             {
224                 case IDOK:
225                     if (AddSelectedUsersToGroup(hwndDlg, pGroupData))
226                         EndDialog(hwndDlg, IDOK);
227                     else
228                         EndDialog(hwndDlg, IDCANCEL);
229                     break;
230 
231                 case IDCANCEL:
232                     EndDialog(hwndDlg, IDCANCEL);
233                     break;
234             }
235             break;
236 
237         default:
238             return FALSE;
239     }
240 
241     return TRUE;
242 }
243 
244 
245 static VOID
AddUsersToGroup(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)246 AddUsersToGroup(HWND hwndDlg,
247                 PGENERAL_GROUP_DATA pGroupData)
248 {
249     HWND hwndLV;
250 //    NET_API_STATUS status;
251     PLOCALGROUP_MEMBERS_INFO_1 membersInfo = NULL;
252     DWORD dwRead;
253     DWORD dwTotal;
254     DWORD_PTR resumeHandle = 0;
255     DWORD i;
256     LV_ITEM lvi;
257     TCHAR szGroupName[256];
258 
259     if (DialogBoxParam(hApplet,
260                        MAKEINTRESOURCE(IDD_USER_ADD_MEMBERSHIP),
261                        hwndDlg,
262                        AddUsersToGroupDlgProc,
263                        (LPARAM)pGroupData) == IDOK)
264     {
265         hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS);
266 
267         (void)ListView_DeleteAllItems(hwndLV);
268 
269 //        DebugPrintf(_T("Removed all users from the list!"));
270 
271         /* Set group members */
272         NetLocalGroupGetMembers(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&membersInfo,
273                                 MAX_PREFERRED_LENGTH, &dwRead, &dwTotal,
274                                 &resumeHandle);
275 
276         for (i = 0; i < dwRead; i++)
277         {
278             ZeroMemory(&lvi, sizeof(lvi));
279             lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
280             lvi.pszText = membersInfo[i].lgrmi1_name;
281             lvi.state = 0;
282             lvi.iImage = (membersInfo[i].lgrmi1_sidusage == SidTypeGroup ||
283                           membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup) ? 1 : 0;
284 
285             if (membersInfo[i].lgrmi1_sidusage == SidTypeWellKnownGroup)
286             {
287                 TCHAR szSid[256];
288 
289                 GetTextSid(membersInfo[i].lgrmi1_sid, szSid);
290 
291                 wsprintf(szGroupName,
292                          TEXT("%s (%s)"),
293                          membersInfo[i].lgrmi1_name,
294                          szSid);
295 
296                 lvi.pszText = szGroupName;
297             }
298 
299 
300             (void)ListView_InsertItem(hwndLV, &lvi);
301         }
302 
303         NetApiBufferFree(membersInfo);
304     }
305 }
306 
307 
308 static VOID
RemoveUserFromGroup(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)309 RemoveUserFromGroup(HWND hwndDlg,
310                     PGENERAL_GROUP_DATA pGroupData)
311 {
312     TCHAR szUserName[UNLEN + 1];
313     TCHAR szText[256];
314     LOCALGROUP_MEMBERS_INFO_3 memberInfo;
315     HWND hwndLV;
316     INT nItem;
317     NET_API_STATUS status;
318 
319     hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS);
320     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
321     if (nItem == -1)
322         return;
323 
324     /* Get the new user name */
325     ListView_GetItemText(hwndLV,
326                          nItem, 0,
327                          szUserName,
328                          UNLEN + 1);
329 
330     /* Display a warning message because the remove operation cannot be reverted */
331     wsprintf(szText, TEXT("Do you really want to remove the user \"%s\" from the group \"%s\"?"),
332              szUserName, pGroupData->szGroupName);
333     if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO)
334         return;
335 
336     memberInfo.lgrmi3_domainandname = szUserName;
337 
338     status = NetLocalGroupDelMembers(NULL, pGroupData->szGroupName,
339                                      3, (LPBYTE)&memberInfo, 1);
340     if (status != NERR_Success)
341     {
342         TCHAR szText[256];
343         wsprintf(szText, TEXT("Error: %u"), status);
344         MessageBox(NULL, szText, TEXT("NetLocalGroupDelMembers"), MB_ICONERROR | MB_OK);
345         return;
346     }
347 
348     (void)ListView_DeleteItem(hwndLV, nItem);
349 
350     if (ListView_GetItemCount(hwndLV) == 0)
351         EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), FALSE);
352 }
353 
354 
355 static BOOL
OnGroupPropSheetNotify(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData,LPARAM lParam)356 OnGroupPropSheetNotify(HWND hwndDlg,
357                        PGENERAL_GROUP_DATA pGroupData,
358                        LPARAM lParam)
359 {
360     LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
361 
362     switch (((LPNMHDR)lParam)->idFrom)
363     {
364         case IDC_GROUP_GENERAL_MEMBERS:
365             switch (((LPNMHDR)lParam)->code)
366             {
367                 case NM_CLICK:
368                     EnableWindow(GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_REMOVE), (lpnmlv->iItem != -1));
369                     break;
370 
371                 case LVN_KEYDOWN:
372                     if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
373                     {
374                         RemoveUserFromGroup(hwndDlg, pGroupData);
375                     }
376                     break;
377 
378             }
379             break;
380     }
381 
382     return FALSE;
383 }
384 
385 
386 static VOID
GetGeneralGroupData(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)387 GetGeneralGroupData(HWND hwndDlg,
388                     PGENERAL_GROUP_DATA pGroupData)
389 {
390     PLOCALGROUP_INFO_1 groupInfo = NULL;
391     PLOCALGROUP_MEMBERS_INFO_2 membersInfo = NULL;
392     DWORD dwRead;
393     DWORD dwTotal;
394     DWORD_PTR resumeHandle = 0;
395     DWORD i;
396     LV_ITEM lvi;
397     HWND hwndLV;
398     LV_COLUMN column;
399     RECT rect;
400     HIMAGELIST hImgList;
401     HICON hIcon;
402     TCHAR szGroupName[256];
403 
404 
405     hwndLV = GetDlgItem(hwndDlg, IDC_GROUP_GENERAL_MEMBERS);
406 
407     /* Create the image list */
408     hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 5);
409     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_GROUP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
410     ImageList_AddIcon(hImgList, hIcon);
411     DestroyIcon(hIcon);
412     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
413     ImageList_AddIcon(hImgList, hIcon);
414     DestroyIcon(hIcon);
415 
416     (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
417 
418     /* Set the list column */
419     GetClientRect(hwndLV, &rect);
420 
421     memset(&column, 0x00, sizeof(column));
422     column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
423     column.fmt = LVCFMT_LEFT;
424     column.cx = (INT)(rect.right - rect.left);
425     column.iSubItem = 0;
426     (void)ListView_InsertColumn(hwndLV, 0, &column);
427 
428     /* Set group name */
429     SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_NAME, pGroupData->szGroupName);
430 
431     /* Set group description */
432     NetLocalGroupGetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE*)&groupInfo);
433     SetDlgItemText(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION, groupInfo->lgrpi1_comment);
434     NetApiBufferFree(groupInfo);
435 
436     /* Set group members */
437     NetLocalGroupGetMembers(NULL, pGroupData->szGroupName, 2, (LPBYTE*)&membersInfo,
438                             MAX_PREFERRED_LENGTH, &dwRead, &dwTotal,
439                             &resumeHandle);
440 
441     for (i = 0; i < dwRead; i++)
442     {
443         ZeroMemory(&lvi, sizeof(lvi));
444         lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
445         lvi.state = 0;
446         if (membersInfo[i].lgrmi2_sidusage == SidTypeGroup ||
447             membersInfo[i].lgrmi2_sidusage == SidTypeWellKnownGroup)
448         {
449             lvi.iImage = 0;
450         }
451         else if (membersInfo[i].lgrmi2_sidusage == SidTypeUser)
452         {
453             /* FIXME: handle locked user properly! */
454             lvi.iImage = 1;
455         }
456 
457         if (membersInfo[i].lgrmi2_sidusage == SidTypeWellKnownGroup)
458         {
459             TCHAR szSid[256];
460 
461             GetTextSid(membersInfo[i].lgrmi2_sid, szSid);
462 
463             wsprintf(szGroupName,
464                      TEXT("%s (%s)"),
465                      membersInfo[i].lgrmi2_domainandname,
466                      szSid);
467 
468             lvi.pszText = szGroupName;
469         }
470         else
471         {
472             LPWSTR ptr;
473 
474             ptr = wcschr(membersInfo[i].lgrmi2_domainandname, L'\\');
475             if (ptr != NULL)
476             {
477                 lvi.pszText = ++ptr;
478             }
479             else
480             {
481                 lvi.pszText = membersInfo[i].lgrmi2_domainandname;
482             }
483         }
484 
485         (void)ListView_InsertItem(hwndLV, &lvi);
486     }
487 
488     NetApiBufferFree(membersInfo);
489 }
490 
491 
492 static BOOL
SetGeneralGroupData(HWND hwndDlg,PGENERAL_GROUP_DATA pGroupData)493 SetGeneralGroupData(HWND hwndDlg,
494                     PGENERAL_GROUP_DATA pGroupData)
495 {
496     LOCALGROUP_INFO_1 groupInfo;
497     NET_API_STATUS status;
498     DWORD dwIndex;
499 
500     /* Get the group description */
501     groupInfo.lgrpi1_comment = GetDlgItemTextAlloc(hwndDlg, IDC_GROUP_GENERAL_DESCRIPTION);
502 
503     status = NetLocalGroupSetInfo(NULL, pGroupData->szGroupName, 1, (LPBYTE)&groupInfo, &dwIndex);
504     if (status != NERR_Success)
505     {
506         ERR("NetLocalGroupSetInfo failed. Status: %lu  Index: %lu", status, dwIndex);
507     }
508 
509     HeapFree(GetProcessHeap(), 0, groupInfo.lgrpi1_comment);
510 
511     return TRUE;
512 }
513 
514 
515 INT_PTR CALLBACK
GroupGeneralPageProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)516 GroupGeneralPageProc(HWND hwndDlg,
517                      UINT uMsg,
518                      WPARAM wParam,
519                      LPARAM lParam)
520 {
521     PGENERAL_GROUP_DATA pGroupData;
522 
523     UNREFERENCED_PARAMETER(lParam);
524     UNREFERENCED_PARAMETER(wParam);
525     UNREFERENCED_PARAMETER(hwndDlg);
526 
527     pGroupData= (PGENERAL_GROUP_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
528 
529     switch (uMsg)
530     {
531         case WM_INITDIALOG:
532             pGroupData = (PGENERAL_GROUP_DATA)HeapAlloc(GetProcessHeap(),
533                                                         HEAP_ZERO_MEMORY,
534                                                         sizeof(GENERAL_GROUP_DATA) +
535                                                         lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR));
536             lstrcpy(pGroupData->szGroupName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam);
537 
538             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pGroupData);
539 
540             GetGeneralGroupData(hwndDlg,
541                                 pGroupData);
542             break;
543 
544         case WM_COMMAND:
545             switch (LOWORD(wParam))
546             {
547                 case IDC_GROUP_GENERAL_DESCRIPTION:
548                     if (HIWORD(wParam) == EN_CHANGE)
549                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
550                     break;
551 
552                 case IDC_GROUP_GENERAL_ADD:
553                     AddUsersToGroup(hwndDlg, pGroupData);
554                     break;
555 
556                 case IDC_GROUP_GENERAL_REMOVE:
557                     RemoveUserFromGroup(hwndDlg, pGroupData);
558                     break;
559             }
560             break;
561 
562         case WM_NOTIFY:
563             if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY)
564             {
565                 SetGeneralGroupData(hwndDlg, pGroupData);
566                 return TRUE;
567             }
568             else
569             {
570                 return OnGroupPropSheetNotify(hwndDlg, pGroupData, lParam);
571             }
572             break;
573 
574         case WM_DESTROY:
575             HeapFree(GetProcessHeap(), 0, pGroupData);
576             break;
577     }
578 
579     return FALSE;
580 }
581 
582 
583 static VOID
InitGroupPropSheetPage(PROPSHEETPAGE * psp,WORD idDlg,DLGPROC DlgProc,LPTSTR pszGroup)584 InitGroupPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc, LPTSTR pszGroup)
585 {
586     ZeroMemory(psp, sizeof(PROPSHEETPAGE));
587     psp->dwSize = sizeof(PROPSHEETPAGE);
588     psp->dwFlags = PSP_DEFAULT;
589     psp->hInstance = hApplet;
590     psp->pszTemplate = MAKEINTRESOURCE(idDlg);
591     psp->pfnDlgProc = DlgProc;
592     psp->lParam = (LPARAM)pszGroup;
593 }
594 
595 
596 BOOL
GroupProperties(HWND hwndDlg)597 GroupProperties(HWND hwndDlg)
598 {
599     PROPSHEETPAGE psp[1];
600     PROPSHEETHEADER psh;
601     TCHAR szGroupName[UNLEN + 1];
602     INT nItem;
603     HWND hwndLV;
604 
605     hwndLV = GetDlgItem(hwndDlg, IDC_GROUPS_LIST);
606     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
607     if (nItem == -1)
608         return FALSE;
609 
610     /* Get the new user name */
611     ListView_GetItemText(hwndLV,
612                          nItem, 0,
613                          szGroupName,
614                          UNLEN + 1);
615 
616     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
617     psh.dwSize = sizeof(PROPSHEETHEADER);
618     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE;
619     psh.hwndParent = hwndDlg;
620     psh.hInstance = hApplet;
621     psh.hIcon = NULL;
622     psh.pszCaption = szGroupName;
623     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
624     psh.nStartPage = 0;
625     psh.ppsp = psp;
626 
627     InitGroupPropSheetPage(&psp[0], IDD_GROUP_GENERAL, GroupGeneralPageProc, szGroupName);
628 
629     return (PropertySheet(&psh) == IDOK);
630 }
631