From 15436e184a4b3e3bf716561d6bd8fa6b4e572afa Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Fri, 1 Jul 2005 23:33:34 +0000 Subject: [PATCH] initial (not yet complete) implementation of the checklist control for the permissions editor svn path=/trunk/; revision=16374 --- reactos/lib/aclui/aclui.c | 166 ++++--- reactos/lib/aclui/aclui.xml | 2 + reactos/lib/aclui/aclui_De.rc | 7 +- reactos/lib/aclui/aclui_En.rc | 7 +- reactos/lib/aclui/aclui_Sv.rc | 7 +- reactos/lib/aclui/acluilib.h | 36 ++ reactos/lib/aclui/checklist.c | 785 ++++++++++++++++++++++++++++++++++ reactos/lib/aclui/misc.c | 43 ++ reactos/lib/aclui/resource.h | 3 + 9 files changed, 994 insertions(+), 62 deletions(-) create mode 100644 reactos/lib/aclui/checklist.c diff --git a/reactos/lib/aclui/aclui.c b/reactos/lib/aclui/aclui.c index 2c2c3d62e62..710e7d9af8d 100644 --- a/reactos/lib/aclui/aclui.c +++ b/reactos/lib/aclui/aclui.c @@ -30,32 +30,6 @@ HINSTANCE hDllInstance; -static LPARAM -ListViewGetSelectedItemData(IN HWND hwnd) -{ - int Index; - - Index = ListView_GetNextItem(hwnd, - -1, - LVNI_SELECTED); - if (Index != -1) - { - LVITEM li; - - li.mask = LVIF_PARAM; - li.iItem = Index; - li.iSubItem = 0; - - if (ListView_GetItem(hwnd, - &li)) - { - return li.lParam; - } - } - - return 0; -} - static VOID DestroySecurityPage(IN PSECURITY_PAGE sp) { @@ -363,6 +337,38 @@ ReloadUsersGroupsList(IN PSECURITY_PAGE sp) } } +static INT +AddAceListEntry(IN PSECURITY_PAGE sp, + IN PACE_LISTITEM AceListItem, + IN INT Index, + IN BOOL Selected) +{ + LVITEM li; + + li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + li.iItem = Index; + li.iSubItem = 0; + li.state = (Selected ? LVIS_SELECTED : 0); + li.stateMask = LVIS_SELECTED; + li.pszText = (AceListItem->DisplayString != NULL ? AceListItem->DisplayString : AceListItem->AccountName); + switch (AceListItem->SidNameUse) + { + case SidTypeUser: + li.iImage = 0; + break; + case SidTypeGroup: + li.iImage = 1; + break; + default: + li.iImage = -1; + break; + } + li.lParam = (LPARAM)AceListItem; + + return ListView_InsertItem(sp->hWndAceList, + &li); +} + static VOID FillUsersGroupsList(IN PSECURITY_PAGE sp) { @@ -382,30 +388,10 @@ FillUsersGroupsList(IN PSECURITY_PAGE sp) CurItem != NULL; CurItem = CurItem->Next) { - LVITEM li; - - li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - li.iItem = -1; - li.iSubItem = 0; - li.state = (CurItem == (PACE_LISTITEM)SelLParam ? LVIS_SELECTED : 0); - li.stateMask = LVIS_SELECTED; - li.pszText = (CurItem->DisplayString != NULL ? CurItem->DisplayString : CurItem->AccountName); - switch (CurItem->SidNameUse) - { - case SidTypeUser: - li.iImage = 0; - break; - case SidTypeGroup: - li.iImage = 1; - break; - default: - li.iImage = -1; - break; - } - li.lParam = (LPARAM)CurItem; - - ListView_InsertItem(sp->hWndAceList, - &li); + AddAceListEntry(sp, + CurItem, + -1, + (SelLParam == (LPARAM)CurItem)); } EnableRedrawWindow(sp->hWndAceList); @@ -417,6 +403,15 @@ FillUsersGroupsList(IN PSECURITY_PAGE sp) rcLvClient.right); } +static VOID +UpdateControlStates(IN PSECURITY_PAGE sp) +{ + BOOL UserOrGroupSelected; + + UserOrGroupSelected = (ListViewGetSelectedItemData(sp->hWndAceList) != 0); + + EnableWindow(sp->hBtnRemove, UserOrGroupSelected); +} static UINT CALLBACK SecurityPageCallback(IN HWND hwnd, @@ -434,6 +429,7 @@ SecurityPageCallback(IN HWND hwnd, case PSPCB_RELEASE: { DestroySecurityPage(sp); + UnregisterCheckListControl(); return FALSE; } } @@ -441,6 +437,29 @@ SecurityPageCallback(IN HWND hwnd, return FALSE; } +static VOID +SetAceCheckListColumns(IN HWND hAceCheckList, + IN UINT Button, + IN HWND hLabel) +{ + POINT pt; + RECT rcLabel; + + GetWindowRect(hLabel, + &rcLabel); + pt.y = 0; + pt.x = (rcLabel.right - rcLabel.left) / 2; + MapWindowPoints(hLabel, + hAceCheckList, + &pt, + 1); + + SendMessage(hAceCheckList, + CLM_SETCHECKBOXCOLUMN, + Button, + pt.x); +} + static INT_PTR CALLBACK SecurityPageProc(IN HWND hwndDlg, @@ -452,6 +471,28 @@ SecurityPageProc(IN HWND hwndDlg, switch(uMsg) { + case WM_NOTIFY: + { + NMHDR *pnmh = (NMHDR*)lParam; + if (pnmh->idFrom == IDC_ACELIST) + { + sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg, + DWL_USER); + if (sp != NULL) + { + switch(pnmh->code) + { + case LVN_ITEMCHANGED: + { + UpdateControlStates(sp); + break; + } + } + } + } + break; + } + case WM_INITDIALOG: { sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam; @@ -462,6 +503,8 @@ SecurityPageProc(IN HWND hwndDlg, sp->hWnd = hwndDlg; sp->hWndAceList = GetDlgItem(hwndDlg, IDC_ACELIST); + sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_ACELIST_REMOVE); + sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST); /* save the pointer to the structure */ SetWindowLongPtr(hwndDlg, @@ -491,6 +534,17 @@ SecurityPageProc(IN HWND hwndDlg, ListView_InsertColumn(sp->hWndAceList, 0, &lvc); FillUsersGroupsList(sp); + + ListViewSelectItem(sp->hWndAceList, + 0); + + /* calculate the columns of the allow/deny checkboxes */ + SetAceCheckListColumns(sp->hAceCheckList, + CLB_ALLOW, + GetDlgItem(hwndDlg, IDC_LABEL_ALLOW)); + SetAceCheckListColumns(sp->hAceCheckList, + CLB_DENY, + GetDlgItem(hwndDlg, IDC_LABEL_DENY)); /* FIXME - hide controls in case the flags aren't present */ } @@ -530,7 +584,13 @@ CreateSecurityPage(IN LPSECURITYINFO psi) { SetLastError(hRet); - DPRINT("CreateSecurityPage() failed!\n"); + DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n"); + return NULL; + } + + if (!RegisterCheckListControl(hDllInstance)) + { + DPRINT("Registering the CHECKLIST_ACLUI class failed!\n"); return NULL; } @@ -555,7 +615,7 @@ CreateSecurityPage(IN LPSECURITYINFO psi) psp.lParam = (LPARAM)sPage; psp.pfnCallback = SecurityPageCallback; - if((ObjectInfo.dwFlags & SI_PAGE_TITLE) != 0 && + if((ObjectInfo.dwFlags & SI_PAGE_TITLE) && ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0') { /* Set the page title if the flag is present and the string isn't empty */ @@ -618,7 +678,7 @@ EditSecurity(IN HWND hwndOwner, psh.dwFlags = PSH_DEFAULT; psh.hwndParent = hwndOwner; psh.hInstance = hDllInstance; - if((ObjectInfo.dwFlags & SI_PAGE_TITLE) != 0 && + if((ObjectInfo.dwFlags & SI_PAGE_TITLE) && ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0') { /* Set the page title if the flag is present and the string isn't empty */ diff --git a/reactos/lib/aclui/aclui.xml b/reactos/lib/aclui/aclui.xml index 04bc6e50faf..25fab155acc 100644 --- a/reactos/lib/aclui/aclui.xml +++ b/reactos/lib/aclui/aclui.xml @@ -10,8 +10,10 @@ ntdll kernel32 user32 + gdi32 comctl32 aclui.c + checklist.c misc.c aclui.rc acluilib.h diff --git a/reactos/lib/aclui/aclui_De.rc b/reactos/lib/aclui/aclui_De.rc index e82ac1a2c4b..0e8d48ba36e 100644 --- a/reactos/lib/aclui/aclui_De.rc +++ b/reactos/lib/aclui/aclui_De.rc @@ -1,7 +1,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Sicherheit" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -9,8 +9,9 @@ BEGIN CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "&Hinzufügen...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Entfernen", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "Erlauben", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Verbieten", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "Erlauben", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Verbieten", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END STRINGTABLE DISCARDABLE diff --git a/reactos/lib/aclui/aclui_En.rc b/reactos/lib/aclui/aclui_En.rc index c32fa631c96..d19f0d56bde 100644 --- a/reactos/lib/aclui/aclui_En.rc +++ b/reactos/lib/aclui/aclui_En.rc @@ -1,7 +1,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Security" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -9,8 +9,9 @@ BEGIN CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "A&dd...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Remove", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "Allow", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Deny", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "Allow", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Deny", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END STRINGTABLE DISCARDABLE diff --git a/reactos/lib/aclui/aclui_Sv.rc b/reactos/lib/aclui/aclui_Sv.rc index 45c0867a587..0a663e809ab 100644 --- a/reactos/lib/aclui/aclui_Sv.rc +++ b/reactos/lib/aclui/aclui_Sv.rc @@ -19,7 +19,7 @@ LANGUAGE LANG_SWEDISH, SUBLANG_DEFAULT IDD_SECPAGE DIALOGEX 0, 0, 227, 215 -STYLE WS_CHILD | WS_VISIBLE | WS_CAPTION +STYLE DS_NOFAILCREATE | DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_CAPTION CAPTION "Säkerhet" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN @@ -27,8 +27,9 @@ BEGIN CONTROL "", IDC_ACELIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 7, 17, 213, 66, WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE PUSHBUTTON "&Lägg till...", IDC_ACELIST_ADD, 116, 87, 50, 14 PUSHBUTTON "&Ta bort", IDC_ACELIST_REMOVE, 170, 87, 50, 14 - LTEXT "Tillåt", -1, 135, 107, 32, 8, SS_CENTER - LTEXT "Neka", -1, 176, 107, 32, 8, SS_CENTER + LTEXT "Tillåt", IDC_LABEL_ALLOW, 135, 107, 32, 8, SS_CENTER + LTEXT "Neka", IDC_LABEL_DENY, 176, 107, 32, 8, SS_CENTER + CONTROL "", IDC_ACE_CHECKLIST, "CHECKLIST_ACLUI", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 117, 213, 72, WS_EX_CLIENTEDGE END STRINGTABLE DISCARDABLE diff --git a/reactos/lib/aclui/acluilib.h b/reactos/lib/aclui/acluilib.h index 97588eee0d0..34fa450e92b 100644 --- a/reactos/lib/aclui/acluilib.h +++ b/reactos/lib/aclui/acluilib.h @@ -33,6 +33,8 @@ typedef struct _ACE_LISTITEM typedef struct _SECURITY_PAGE { HWND hWnd; + HWND hBtnRemove; + HWND hAceCheckList; /* Main ACE List */ HWND hWndAceList; @@ -44,6 +46,8 @@ typedef struct _SECURITY_PAGE SI_OBJECT_INFO ObjectInfo; } SECURITY_PAGE, *PSECURITY_PAGE; +/* MISC ***********************************************************************/ + BOOL OpenLSAPolicyHandle(IN WCHAR *SystemName, IN ACCESS_MASK DesiredAccess, @@ -55,4 +59,36 @@ LoadAndFormatString(IN HINSTANCE hInstance, OUT LPWSTR *lpTarget, ...); +LPARAM +ListViewGetSelectedItemData(IN HWND hwnd); + +BOOL +ListViewSelectItem(IN HWND hwnd, + IN INT Index); + +/* CHECKLIST CONTROL **********************************************************/ + +#define CIS_DISABLED (0x2) +#define CIS_ENABLED (0x0) +#define CIS_ALLOW (0x1) +#define CIS_DENY (0x0) + +#define CLB_ALLOW (0x1) +#define CLB_DENY (0x0) + +#define CIS_MASK (CIS_DISABLED | CIS_ALLOW | CIS_DENY) + +#define CLM_ADDITEM (WM_USER + 1) +#define CLM_DELITEM (WM_USER + 2) +#define CLM_GETITEMCOUNT (WM_USER + 3) +#define CLM_CLEAR (WM_USER + 4) +#define CLM_SETCHECKBOXCOLUMN (WM_USER + 5) +#define CLM_GETCHECKBOXCOLUMN (WM_USER + 6) + +BOOL +RegisterCheckListControl(HINSTANCE hInstance); + +VOID +UnregisterCheckListControl(VOID); + /* EOF */ diff --git a/reactos/lib/aclui/checklist.c b/reactos/lib/aclui/checklist.c new file mode 100644 index 00000000000..2e04f6b82a3 --- /dev/null +++ b/reactos/lib/aclui/checklist.c @@ -0,0 +1,785 @@ +/* + * ReactOS Access Control List Editor + * Copyright (C) 2004 ReactOS Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* $Id$ + * + * PROJECT: ReactOS Access Control List Editor + * FILE: lib/aclui/checklist.c + * PURPOSE: Access Control List Editor + * PROGRAMMER: Thomas Weidenmueller + * + * UPDATE HISTORY: + * 08/10/2004 Created + */ +#include "acluilib.h" + +typedef struct _CHECKITEM +{ + struct _CHECKITEM *Next; + DWORD State; + WCHAR Name[1]; +} CHECKITEM, *PCHECKITEM; + +typedef struct _CHECKLISTWND +{ + HWND hSelf; + HWND hNotify; + DWORD Style; + HFONT hFont; + + PCHECKITEM CheckItemListHead; + UINT CheckItemCount; + + INT ItemHeight; + BOOL HasFocus; + + COLORREF TextColor[2]; + UINT CheckBoxLeft[2]; +} CHECKLISTWND, *PCHECKLISTWND; + +static PCHECKITEM +FindCheckItemByIndex(IN PCHECKLISTWND infoPtr, + IN UINT Index) +{ + PCHECKITEM Item, Found = NULL; + + for (Item = infoPtr->CheckItemListHead; + Item != NULL; + Item = Item->Next) + { + if (Index == 0) + { + Found = Item; + break; + } + + Index--; + } + + return Found; +} + +static VOID +ClearCheckItems(IN PCHECKLISTWND infoPtr) +{ + PCHECKITEM CurItem, NextItem; + + CurItem = infoPtr->CheckItemListHead; + while (CurItem != NULL) + { + NextItem = CurItem->Next; + HeapFree(GetProcessHeap(), + 0, + CurItem); + CurItem = NextItem; + } + + infoPtr->CheckItemListHead = NULL; + infoPtr->CheckItemCount = 0; +} + +static BOOL +DeleteCheckItem(IN PCHECKLISTWND infoPtr, + IN PCHECKITEM Item) +{ + PCHECKITEM CurItem; + PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; + + for (CurItem = infoPtr->CheckItemListHead; + CurItem != NULL; + CurItem = CurItem->Next) + { + if (CurItem == Item) + { + *PrevPtr = CurItem->Next; + HeapFree(GetProcessHeap(), + 0, + CurItem); + infoPtr->CheckItemCount--; + return TRUE; + } + + PrevPtr = &CurItem->Next; + } + + return FALSE; +} + +static PCHECKITEM +AddCheckItem(IN PCHECKLISTWND infoPtr, + IN LPWSTR Name, + IN DWORD State) +{ + PCHECKITEM CurItem; + PCHECKITEM *PrevPtr = &infoPtr->CheckItemListHead; + PCHECKITEM Item = HeapAlloc(GetProcessHeap(), + 0, + sizeof(CHECKITEM) + (wcslen(Name) * sizeof(WCHAR))); + if (Item != NULL) + { + for (CurItem = infoPtr->CheckItemListHead; + CurItem != NULL; + CurItem = CurItem->Next) + { + PrevPtr = &CurItem->Next; + } + + Item->Next = NULL; + Item->State = State & CIS_MASK; + wcscpy(Item->Name, + Name); + + *PrevPtr = Item; + infoPtr->CheckItemCount++; + } + + return Item; +} + +static VOID +UpdateControl(IN PCHECKLISTWND infoPtr, + IN BOOL AllowChangeStyle) +{ + RECT rcClient; + SCROLLINFO ScrollInfo; + + GetClientRect(infoPtr->hSelf, + &rcClient); + + ScrollInfo.cbSize = sizeof(ScrollInfo); + ScrollInfo.fMask = SIF_PAGE | SIF_RANGE; + ScrollInfo.nMin = 0; + ScrollInfo.nMax = infoPtr->CheckItemCount; + ScrollInfo.nPage = ((rcClient.bottom - rcClient.top) + infoPtr->ItemHeight - 1) / infoPtr->ItemHeight; + ScrollInfo.nPos = 0; + ScrollInfo.nTrackPos = 0; + + if (AllowChangeStyle) + { + /* determine whether the vertical scrollbar has to be visible or not */ + if (ScrollInfo.nMax > ScrollInfo.nPage && + !(infoPtr->Style & WS_VSCROLL)) + { + SetWindowLong(infoPtr->hSelf, + GWL_STYLE, + infoPtr->Style | WS_VSCROLL); + } + else if (ScrollInfo.nMax < ScrollInfo.nPage && + infoPtr->Style & WS_VSCROLL) + { + SetWindowLong(infoPtr->hSelf, + GWL_STYLE, + infoPtr->Style & ~WS_VSCROLL); + } + } + + SetScrollInfo(infoPtr->hSelf, + SB_VERT, + &ScrollInfo, + TRUE); + + RedrawWindow(infoPtr->hSelf, + NULL, + NULL, + RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); +} + +static UINT +GetIdealItemHeight(IN PCHECKLISTWND infoPtr) +{ + HDC hdc = GetDC(infoPtr->hSelf); + if(hdc != NULL) + { + UINT height; + TEXTMETRIC tm; + HGDIOBJ hOldFont = SelectObject(hdc, + infoPtr->hFont); + + if(GetTextMetrics(hdc, + &tm)) + { + height = tm.tmHeight; + } + else + { + height = 0; + } + + SelectObject(hdc, + hOldFont); + + ReleaseDC(infoPtr->hSelf, + hdc); + + return height; + } + return 0; +} + +static HFONT +RetChangeControlFont(IN PCHECKLISTWND infoPtr, + IN HFONT hFont, + IN BOOL Redraw) +{ + HFONT hOldFont = infoPtr->hFont; + infoPtr->hFont = hFont; + + if (hOldFont != hFont) + { + infoPtr->ItemHeight = 4 + GetIdealItemHeight(infoPtr); + } + + UpdateControl(infoPtr, + TRUE); + + return hOldFont; +} + +static VOID +PaintControl(IN PCHECKLISTWND infoPtr, + IN HDC hDC, + IN PRECT rcUpdate) +{ + INT ScrollPos; + PCHECKITEM FirstItem, Item; + RECT rcClient; + UINT VisibleFirstIndex = rcUpdate->top / infoPtr->ItemHeight; + UINT LastTouchedIndex = rcUpdate->bottom / infoPtr->ItemHeight; + + FillRect(hDC, + rcUpdate, + (HBRUSH)(COLOR_WINDOW + 1)); + + GetClientRect(infoPtr->hSelf, &rcClient); + + if (infoPtr->Style & WS_VSCROLL) + { + ScrollPos = GetScrollPos(infoPtr->hSelf, + SB_VERT); + } + else + { + ScrollPos = 0; + } + + FirstItem = FindCheckItemByIndex(infoPtr, + ScrollPos + VisibleFirstIndex); + if (FirstItem != NULL) + { + RECT TextRect, ItemRect; + HFONT hOldFont; + DWORD CurrentIndex; + COLORREF OldTextColor; + BOOL Enabled, PrevEnabled; + POINT ptOld; + + Enabled = IsWindowEnabled(infoPtr->hSelf); + PrevEnabled = Enabled; + + ItemRect.left = 0; + ItemRect.right = rcClient.right; + ItemRect.top = VisibleFirstIndex * infoPtr->ItemHeight; + + TextRect.left = ItemRect.left + 6; + TextRect.right = ItemRect.right - 6; + TextRect.top = ItemRect.top + 2; + + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + ItemRect.top, + &ptOld); + + OldTextColor = SetTextColor(hDC, + infoPtr->TextColor[Enabled]); + + hOldFont = SelectObject(hDC, + infoPtr->hFont); + + for (Item = FirstItem, CurrentIndex = VisibleFirstIndex; + Item != NULL && CurrentIndex <= LastTouchedIndex; + Item = Item->Next, CurrentIndex++) + { + TextRect.bottom = TextRect.top + infoPtr->ItemHeight; + + if (Enabled && PrevEnabled != ((Item->State & CIS_DISABLED) == 0)) + { + PrevEnabled = ((Item->State & CIS_DISABLED) == 0); + + SetTextColor(hDC, + infoPtr->TextColor[PrevEnabled]); + } + + DrawText(hDC, + Item->Name, + -1, + &TextRect, + DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); + + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + TextRect.top - 6, + NULL); + LineTo(hDC, + infoPtr->CheckBoxLeft[CLB_ALLOW], + TextRect.bottom - 6); + MoveToEx(hDC, + infoPtr->CheckBoxLeft[CLB_DENY], + TextRect.top - 6, + NULL); + LineTo(hDC, + infoPtr->CheckBoxLeft[CLB_DENY], + TextRect.bottom - 6); + + TextRect.top += infoPtr->ItemHeight; + } + + SelectObject(hDC, + hOldFont); + + SetTextColor(hDC, + OldTextColor); + + MoveToEx(hDC, + ptOld.x, + ptOld.y, + NULL); + } +} + +LRESULT CALLBACK +CheckListWndProc(IN HWND hwnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PCHECKLISTWND infoPtr; + LRESULT Ret; + + infoPtr = (PCHECKLISTWND)GetWindowLongPtr(hwnd, + 0); + + if (infoPtr == NULL && uMsg != WM_CREATE) + { + return DefWindowProc(hwnd, + uMsg, + wParam, + lParam); + } + + Ret = 0; + + switch (uMsg) + { + case WM_PAINT: + { + HDC hdc; + RECT rcUpdate; + PAINTSTRUCT ps; + + if (GetUpdateRect(hwnd, + &rcUpdate, + FALSE)) + { + hdc = (wParam != 0 ? (HDC)wParam : BeginPaint(hwnd, &ps)); + + PaintControl(infoPtr, + hdc, + &rcUpdate); + + if (wParam == 0) + { + EndPaint(hwnd, + &ps); + } + } + break; + } + + case WM_VSCROLL: + { + SCROLLINFO ScrollInfo; + + ScrollInfo.cbSize = sizeof(ScrollInfo); + ScrollInfo.fMask = SIF_PAGE | SIF_RANGE | SIF_POS | SIF_TRACKPOS; + + if (GetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo)) + { + INT OldPos = ScrollInfo.nPos; + + switch (LOWORD(wParam)) + { + case SB_BOTTOM: + ScrollInfo.nPos = ScrollInfo.nMax; + break; + + case SB_LINEDOWN: + if (ScrollInfo.nPos < ScrollInfo.nMax) + { + ScrollInfo.nPos++; + } + break; + + case SB_LINEUP: + if (ScrollInfo.nPos > 0) + { + ScrollInfo.nPos--; + } + break; + + case SB_PAGEDOWN: + if (ScrollInfo.nPos + ScrollInfo.nPage <= ScrollInfo.nMax) + { + ScrollInfo.nPos += ScrollInfo.nPage; + } + else + { + ScrollInfo.nPos = ScrollInfo.nMax; + } + break; + + case SB_PAGEUP: + if (ScrollInfo.nPos >= ScrollInfo.nPage) + { + ScrollInfo.nPos -= ScrollInfo.nPage; + } + else + { + ScrollInfo.nPos = 0; + } + break; + + case SB_THUMBPOSITION: + { + ScrollInfo.nPos = HIWORD(wParam); + break; + } + + case SB_THUMBTRACK: + { + ScrollInfo.nPos = ScrollInfo.nTrackPos; + break; + } + + case SB_TOP: + ScrollInfo.nPos = 0; + break; + } + + if (OldPos != ScrollInfo.nPos) + { + ScrollInfo.fMask = SIF_POS; + + ScrollInfo.nPos = SetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo, + TRUE); + + if (OldPos != ScrollInfo.nPos) + { + ScrollWindowEx(hwnd, + 0, + (OldPos - ScrollInfo.nPos) * infoPtr->ItemHeight, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + + RedrawWindow(hwnd, + NULL, + NULL, + RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); + } + } + } + break; + } + + case CLM_ADDITEM: + { + Ret = (AddCheckItem(infoPtr, + (LPWSTR)lParam, + (DWORD)wParam) != NULL); + if (Ret) + { + UpdateControl(infoPtr, + TRUE); + } + break; + } + + case CLM_DELITEM: + { + PCHECKITEM Item = FindCheckItemByIndex(infoPtr, + wParam); + if (Item != NULL) + { + Ret = DeleteCheckItem(infoPtr, + Item); + if (Ret) + { + UpdateControl(infoPtr, + TRUE); + } + } + else + { + Ret = FALSE; + } + break; + } + + case CLM_GETITEMCOUNT: + { + Ret = infoPtr->CheckItemCount; + break; + } + + case CLM_CLEAR: + { + ClearCheckItems(infoPtr); + UpdateControl(infoPtr, + TRUE); + break; + } + + case CLM_SETCHECKBOXCOLUMN: + { + infoPtr->CheckBoxLeft[wParam != CLB_DENY] = (UINT)lParam; + Ret = 1; + break; + } + + case CLM_GETCHECKBOXCOLUMN: + { + Ret = (LRESULT)infoPtr->CheckBoxLeft[wParam != CLB_DENY]; + break; + } + + case WM_SETFONT: + { + Ret = (LRESULT)RetChangeControlFont(infoPtr, + (HFONT)wParam, + (BOOL)lParam); + break; + } + + case WM_GETFONT: + { + Ret = (LRESULT)infoPtr->hFont; + break; + } + + case WM_STYLECHANGED: + { + LPSTYLESTRUCT Style = (LPSTYLESTRUCT)lParam; + + if (wParam == GWL_STYLE) + { + infoPtr->Style = Style->styleNew; + UpdateControl(infoPtr, + FALSE); + } + break; + } + + case WM_MOUSEWHEEL: + { + SHORT ScrollDelta; + UINT ScrollLines = 3; + + SystemParametersInfo(SPI_GETWHEELSCROLLLINES, + 0, + &ScrollLines, + 0); + ScrollDelta = 0 - (SHORT)HIWORD(wParam); + + if (ScrollLines != 0 && + abs(ScrollDelta) >= WHEEL_DELTA) + { + SCROLLINFO ScrollInfo; + + ScrollInfo.cbSize = sizeof(ScrollInfo); + ScrollInfo.fMask = SIF_RANGE | SIF_POS; + + if (GetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo)) + { + INT OldPos = ScrollInfo.nPos; + + ScrollInfo.nPos += (ScrollDelta / WHEEL_DELTA) * ScrollLines; + if (ScrollInfo.nPos < 0) + ScrollInfo.nPos = 0; + else if (ScrollInfo.nPos > ScrollInfo.nMax) + ScrollInfo.nPos = ScrollInfo.nMax; + + if (OldPos != ScrollInfo.nPos) + { + ScrollInfo.fMask = SIF_POS; + + ScrollInfo.nPos = SetScrollInfo(hwnd, + SB_VERT, + &ScrollInfo, + TRUE); + + if (OldPos != ScrollInfo.nPos) + { + ScrollWindowEx(hwnd, + 0, + (OldPos - ScrollInfo.nPos) * infoPtr->ItemHeight, + NULL, + NULL, + NULL, + NULL, + SW_INVALIDATE); + + RedrawWindow(hwnd, + NULL, + NULL, + RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN); + } + } + } + } + break; + } + + case WM_SETFOCUS: + { + infoPtr->HasFocus = TRUE; + break; + } + + case WM_KILLFOCUS: + { + infoPtr->HasFocus = FALSE; + break; + } + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: + { + if (!infoPtr->HasFocus && IsWindowEnabled(hwnd)) + { + SetFocus(hwnd); + } + break; + } + + case WM_SYSCOLORCHANGE: + { + infoPtr->TextColor[0] = GetSysColor(COLOR_GRAYTEXT); + infoPtr->TextColor[1] = GetSysColor(COLOR_WINDOWTEXT); + break; + } + + case WM_CREATE: + { + infoPtr = HeapAlloc(GetProcessHeap(), + 0, + sizeof(CHECKLISTWND)); + if (infoPtr != NULL) + { + RECT rcClient; + + infoPtr->hSelf = hwnd; + infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; + infoPtr->Style = ((LPCREATESTRUCTW)lParam)->style; + + SetWindowLongPtr(hwnd, + 0, + (DWORD_PTR)infoPtr); + + infoPtr->CheckItemListHead = NULL; + infoPtr->CheckItemCount = 0; + + infoPtr->ItemHeight = 10; + + infoPtr->HasFocus = FALSE; + + infoPtr->TextColor[0] = GetSysColor(COLOR_GRAYTEXT); + infoPtr->TextColor[1] = GetSysColor(COLOR_WINDOWTEXT); + + GetClientRect(hwnd, &rcClient); + + infoPtr->CheckBoxLeft[0] = rcClient.right - 30; + infoPtr->CheckBoxLeft[1] = rcClient.right - 15; + } + else + { + Ret = -1; + } + break; + } + + case WM_DESTROY: + { + ClearCheckItems(infoPtr); + + HeapFree(GetProcessHeap(), + 0, + infoPtr); + SetWindowLongPtr(hwnd, + 0, + (DWORD_PTR)NULL); + break; + } + + default: + { + Ret = DefWindowProc(hwnd, + uMsg, + wParam, + lParam); + break; + } + } + + return Ret; +} + +BOOL +RegisterCheckListControl(HINSTANCE hInstance) +{ + WNDCLASS wc; + + ZeroMemory(&wc, sizeof(WNDCLASS)); + + wc.style = 0; + wc.lpfnWndProc = CheckListWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(PCHECKLISTWND); + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(0, (LPWSTR)IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = L"CHECKLIST_ACLUI"; + + return RegisterClass(&wc) != 0; +} + +VOID +UnregisterCheckListControl(VOID) +{ + UnregisterClass(L"CHECKLIST_ACLUI", + NULL); +} diff --git a/reactos/lib/aclui/misc.c b/reactos/lib/aclui/misc.c index 868253faabe..e79fd843762 100644 --- a/reactos/lib/aclui/misc.c +++ b/reactos/lib/aclui/misc.c @@ -161,3 +161,46 @@ OpenLSAPolicyHandle(IN WCHAR *SystemName, return TRUE; } + +LPARAM +ListViewGetSelectedItemData(IN HWND hwnd) +{ + int Index; + + Index = ListView_GetNextItem(hwnd, + -1, + LVNI_SELECTED); + if (Index != -1) + { + LVITEM li; + + li.mask = LVIF_PARAM; + li.iItem = Index; + li.iSubItem = 0; + + if (ListView_GetItem(hwnd, + &li)) + { + return li.lParam; + } + } + + return 0; +} + +BOOL +ListViewSelectItem(IN HWND hwnd, + IN INT Index) +{ + LVITEM li; + + li.mask = LVIF_STATE; + li.iItem = Index; + li.iSubItem = 0; + li.state = LVIS_SELECTED; + li.stateMask = LVIS_SELECTED; + + return ListView_SetItem(hwnd, + &li); +} + diff --git a/reactos/lib/aclui/resource.h b/reactos/lib/aclui/resource.h index f1d2934f37c..2441eaa36a0 100644 --- a/reactos/lib/aclui/resource.h +++ b/reactos/lib/aclui/resource.h @@ -6,6 +6,9 @@ #define IDC_ACELIST 1001 #define IDC_ACELIST_ADD 1002 #define IDC_ACELIST_REMOVE 1003 +#define IDC_ACE_CHECKLIST 1004 +#define IDC_LABEL_ALLOW 1005 +#define IDC_LABEL_DENY 1006 #define IDI_DEVMGR 100