├── Icons ├── .gitignore ├── Resources.Icon.Add.rc ├── Resources.Icon.Up.rc ├── Resources.Icon.Down.rc ├── Resources.Icon.Choose.rc ├── Resources.Icon.Delete.rc ├── Resources.Icon.Verify.rc ├── Resources.Icon.Catalogue.rc ├── SearchBox.res ├── Resources.Icon.UserPicker.rc ├── SearchBox.Clear.ico ├── SearchBox.Search.ico ├── SearchBox.Typing.ico ├── Resources.Icon.Add.ico ├── Resources.Icon.Add.res ├── Resources.Icon.Up.RES ├── Resources.Icon.Up.ico ├── Resources.Icon.Choose.ico ├── Resources.Icon.Choose.res ├── Resources.Icon.Delete.ico ├── Resources.Icon.Delete.res ├── Resources.Icon.Down.ico ├── Resources.Icon.Down.res ├── Resources.Icon.Verify.ico ├── Resources.Icon.Verify.res ├── Resources.Icon.Catalogue.ico ├── Resources.Icon.Catalogue.res ├── Resources.Icon.UserPicker.ico ├── Resources.Icon.UserPicker.res ├── SearchBox.rc ├── Resources.Icon.Up.pas ├── Resources.Icon.Add.pas ├── Resources.Icon.Down.pas ├── Resources.Icon.Choose.pas ├── Resources.Icon.Delete.pas ├── Resources.Icon.Verify.pas ├── Resources.Icon.Catalogue.pas └── Resources.Icon.UserPicker.pas ├── .gitattributes ├── Prototypes ├── NtUiFrame.dfm ├── NtUiFrame.Guid.dfm ├── NtUiCommon.PageHost.dfm ├── NtUiFrame.Hex.Edit.dfm ├── NtUiDialog.FrameHost.dfm ├── NtUiFrame.AppContainer.Edit.dfm ├── NtUiFrame.Ace.Condition.dfm ├── NtUiFrame.AppContainer.ListAllUsers.dfm ├── NtUiFrame.Search.dfm ├── NtUiFrame.Security.OwnerGroup.dfm ├── NtUiFrame.Sids.Hierarchy.pas ├── NtUiFrame.Sids.WellKnown.pas ├── NtUiFrame.Sids.Abbreviations.pas ├── NtUiFrame.Sids.Logon.pas ├── UI.Prototypes.Sid.Edit.dfm ├── NtUiFrame.Security.pas ├── NtUiFrame.Sid.Integrity.dfm ├── NtUiFrame.Sids.Sam.pas ├── NtUiFrame.AppContainer.View.dfm ├── NtUiFrame.AppContainer.View.pas ├── NtUiFrame.Guid.pas ├── NtUiFrame.Security.Acl.dfm ├── NtUiFrame.pas ├── NtUiFrame.Sids.Capabilities.dfm ├── UI.Prototypes.Groups.dfm ├── NtUiFrame.AppContainer.Edit.pas ├── NtUiFrame.Hex.Edit.pas ├── NtUiFrame.Sids.Abbreviations.dfm ├── NtUiFrame.Bits.dfm ├── NtUiFrame.Sid.Trust.dfm ├── NtUiFrame.UserProfiles.pas ├── UI.Prototypes.Privileges.dfm ├── NtUiFrame.Sids.Hierarchy.dfm ├── NtUiFrame.Sids.Logon.dfm ├── NtUiFrame.Sids.Sam.dfm ├── NtUiFrame.Sids.WellKnown.dfm ├── NtUiFrame.UserProfiles.dfm ├── NtUiFrame.Sids.Capabilities.pas ├── NtUiFrame.Ace.Condition.pas ├── NtUiFrame.AppContainer.List.dfm ├── NtUiFrame.AppContainer.ListAllUsers.pas ├── NtUiFrame.AppContainer.List.pas ├── NtUiFrame.Sid.Integrity.pas ├── NtUiCommon.PageHost.pas ├── UI.Prototypes.Sid.Edit.pas ├── NtUiDialog.FrameHost.pas ├── NtUiFrame.Security.OwnerGroup.pas ├── NtUiFrame.Acl.pas └── NtUiFrame.Bits.pas ├── Readme.md ├── .gitmodules ├── Common ├── NtUiBackend.Sids.pas ├── NtUiCommon.Exceptions.pas ├── NtUiCommon.Colors.pas ├── NtUiCommon.Icons.pas ├── NtUiCommon.Forms.pas ├── NtUiBackend.Sids.Abbreviations.pas ├── NtUiBackend.HexView.pas ├── NtUiBackend.UserProfiles.pas ├── NtUiBackend.Sids.WellKnown.pas ├── NtUiCommon.Prototypes.pas ├── NtUiCommon.Helpers.pas ├── NtUiBackend.Sids.Logon.pas └── NtUiBackend.Sids.Capabilities.pas ├── Components ├── VirtualTreesExtension.dpk └── VirtualTreesEx.DefaultMenu.pas └── .gitignore /Icons/.gitignore: -------------------------------------------------------------------------------- 1 | # Include compiled icons 2 | !*.res 3 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Add.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Add ICON Resources.Icon.Add.ico 2 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Up.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Up ICON Resources.Icon.Up.ico 2 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Down.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Down ICON Resources.Icon.Down.ico 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Choose.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Choose ICON Resources.Icon.Choose.ico 2 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Delete.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Delete ICON Resources.Icon.Delete.ico 2 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Verify.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Verify ICON Resources.Icon.Verify.ico 2 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Catalogue.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.Catalogue ICON Resources.Icon.Catalogue.ico 2 | -------------------------------------------------------------------------------- /Icons/SearchBox.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/SearchBox.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.UserPicker.rc: -------------------------------------------------------------------------------- 1 | Resources.Icon.UserPicker ICON Resources.Icon.UserPicker.ico 2 | -------------------------------------------------------------------------------- /Icons/SearchBox.Clear.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/SearchBox.Clear.ico -------------------------------------------------------------------------------- /Icons/SearchBox.Search.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/SearchBox.Search.ico -------------------------------------------------------------------------------- /Icons/SearchBox.Typing.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/SearchBox.Typing.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Add.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Add.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Add.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Add.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.Up.RES: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Up.RES -------------------------------------------------------------------------------- /Icons/Resources.Icon.Up.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Up.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Choose.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Choose.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Choose.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Choose.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.Delete.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Delete.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Delete.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Delete.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.Down.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Down.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Down.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Down.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.Verify.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Verify.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Verify.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Verify.res -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.dfm: -------------------------------------------------------------------------------- 1 | object BaseFrame: TBaseFrame 2 | ParentShowHint = False 3 | ShowHint = True 4 | end 5 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Catalogue.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Catalogue.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.Catalogue.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.Catalogue.res -------------------------------------------------------------------------------- /Icons/Resources.Icon.UserPicker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.UserPicker.ico -------------------------------------------------------------------------------- /Icons/Resources.Icon.UserPicker.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diversenok/NtUtilsUI/HEAD/Icons/Resources.Icon.UserPicker.res -------------------------------------------------------------------------------- /Icons/SearchBox.rc: -------------------------------------------------------------------------------- 1 | SearchBox.Search ICON SearchBox.Search.ico 2 | SearchBox.Clear ICON SearchBox.Clear.ico 3 | SearchBox.Typing ICON SearchBox.Typing.ico -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # NtUtilsUI 2 | 3 | A set of UI components for use with [NtUtilsLibrary](https://github.com/diversenok/NtUtilsLibrary) in UI applications. 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "NtUtils"] 2 | path = NtUtils 3 | url = https://github.com/diversenok/NtUtilsLibrary 4 | [submodule "VclEx"] 5 | path = VclEx 6 | url = https://github.com/diversenok/VclEx 7 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Up.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Up; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_UP = 'Resources.Icon.Up'; 7 | 8 | {$R Resources.Icon.Up.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Add.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Add; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_ADD = 'Resources.Icon.Add'; 7 | 8 | {$R Resources.Icon.Add.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Down.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Down; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_DOWN = 'Resources.Icon.Down'; 7 | 8 | {$R Resources.Icon.Down.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Choose.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Choose; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_CHOOSE = 'Resources.Icon.Choose'; 7 | 8 | {$R Resources.Icon.Choose.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Delete.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Delete; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_DELETE = 'Resources.Icon.Delete'; 7 | 8 | {$R Resources.Icon.Delete.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Verify.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Verify; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_VERIFY = 'Resources.Icon.Verify'; 7 | 8 | {$R Resources.Icon.Verify.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.Catalogue.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.Catalogue; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_CATALOGUE = 'Resources.Icon.Catalogue'; 7 | 8 | {$R Resources.Icon.Catalogue.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Icons/Resources.Icon.UserPicker.pas: -------------------------------------------------------------------------------- 1 | unit Resources.Icon.UserPicker; 2 | 3 | interface 4 | 5 | const 6 | RESOURCES_ICON_USER_PICKER = 'Resources.Icon.UserPicker'; 7 | 8 | {$R Resources.Icon.UserPicker.res} 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Common/NtUiBackend.Sids.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.Sids; 2 | 3 | interface 4 | 5 | uses 6 | DevirtualizedTree, NtUtils.Lsa.Sid; 7 | 8 | type 9 | ISidNode = interface (INodeProvider) 10 | ['{2366E5CA-95BF-4F5D-B412-5D733EB3B9F8}'] 11 | function GetSidName: TTranslatedName; 12 | property SidName: TTranslatedName read GetSidName; 13 | end; 14 | 15 | implementation 16 | 17 | end. 18 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Guid.dfm: -------------------------------------------------------------------------------- 1 | object GuidFrame: TGuidFrame 2 | Left = 0 3 | Top = 0 4 | Width = 600 5 | Height = 21 6 | Constraints.MinWidth = 224 7 | TabOrder = 0 8 | object tbxGuid: TEdit 9 | Left = 0 10 | Top = 0 11 | Width = 600 12 | Height = 21 13 | Align = alClient 14 | Enabled = False 15 | TabOrder = 0 16 | Text = '{00000000-0000-0000-0000-000000000000}' 17 | OnChange = tbxGuidChange 18 | OnExit = tbxGuidExit 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /Prototypes/NtUiCommon.PageHost.dfm: -------------------------------------------------------------------------------- 1 | object FramePages: TFramePages 2 | Left = 0 3 | Top = 0 4 | Width = 320 5 | Height = 240 6 | ParentShowHint = False 7 | ShowHint = True 8 | TabOrder = 0 9 | object PageControl: TPageControl 10 | Left = 0 11 | Top = 0 12 | Width = 320 13 | Height = 240 14 | Align = alClient 15 | MultiLine = True 16 | TabOrder = 0 17 | OnChange = PageControlChange 18 | end 19 | object ActionList: TActionList 20 | Left = 112 21 | Top = 96 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Hex.Edit.dfm: -------------------------------------------------------------------------------- 1 | object HexEditFrame: THexEditFrame 2 | Left = 0 3 | Top = 0 4 | Width = 600 5 | Height = 25 6 | ParentShowHint = False 7 | ShowHint = True 8 | TabOrder = 0 9 | object tbxHexString: TEdit 10 | AlignWithMargins = True 11 | Left = 0 12 | Top = 2 13 | Width = 600 14 | Height = 21 15 | Margins.Left = 0 16 | Margins.Top = 2 17 | Margins.Right = 0 18 | Margins.Bottom = 2 19 | Align = alClient 20 | TabOrder = 0 21 | TextHint = 'Binary data as hex: 00 80 FF ...' 22 | OnChange = tbxHexStringChange 23 | OnExit = tbxHexStringExit 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /Prototypes/NtUiDialog.FrameHost.dfm: -------------------------------------------------------------------------------- 1 | object FrameHostDialog: TFrameHostDialog 2 | Left = 0 3 | Top = 0 4 | ClientHeight = 473 5 | ClientWidth = 614 6 | Color = clBtnFace 7 | DoubleBuffered = True 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Tahoma' 12 | Font.Style = [] 13 | KeyPreview = True 14 | Position = poOwnerFormCenter 15 | ShowHint = True 16 | OnKeyDown = FormKeyDown 17 | TextHeight = 13 18 | object btnClose: TButton 19 | Left = 3 20 | Top = 445 21 | Width = 75 22 | Height = 25 23 | Anchors = [akLeft, akBottom] 24 | Caption = 'Cancel' 25 | ModalResult = 8 26 | TabOrder = 0 27 | OnClick = btnCloseClick 28 | end 29 | object btnSelect: TButton 30 | Left = 536 31 | Top = 445 32 | Width = 75 33 | Height = 25 34 | Anchors = [akRight, akBottom] 35 | Caption = 'Select' 36 | Default = True 37 | TabOrder = 1 38 | OnClick = btnSelectClick 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /Components/VirtualTreesExtension.dpk: -------------------------------------------------------------------------------- 1 | package VirtualTreesExtension; 2 | 3 | {$R *.res} 4 | {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} 5 | {$ALIGN 8} 6 | {$ASSERTIONS ON} 7 | {$BOOLEVAL OFF} 8 | {$DEBUGINFO OFF} 9 | {$EXTENDEDSYNTAX ON} 10 | {$IMPORTEDDATA ON} 11 | {$IOCHECKS ON} 12 | {$LOCALSYMBOLS OFF} 13 | {$LONGSTRINGS ON} 14 | {$OPENSTRINGS ON} 15 | {$OPTIMIZATION ON} 16 | {$OVERFLOWCHECKS OFF} 17 | {$RANGECHECKS OFF} 18 | {$REFERENCEINFO OFF} 19 | {$SAFEDIVIDE OFF} 20 | {$STACKFRAMES OFF} 21 | {$TYPEDADDRESS OFF} 22 | {$VARSTRINGCHECKS ON} 23 | {$WRITEABLECONST OFF} 24 | {$MINENUMSIZE 1} 25 | {$IMAGEBASE $400000} 26 | {$DEFINE RELEASE} 27 | {$ENDIF IMPLICITBUILDING} 28 | {$IMPLICITBUILD ON} 29 | 30 | requires 31 | rtl, 32 | vcl, 33 | VirtualTreesDR; 34 | 35 | contains 36 | VirtualTreesEx.DefaultMenu in 'VirtualTreesEx.DefaultMenu.pas', 37 | VirtualTreesEx in 'VirtualTreesEx.pas', 38 | DevirtualizedTree.Provider in 'DevirtualizedTree.Provider.pas', 39 | DevirtualizedTree in 'DevirtualizedTree.pas'; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.Edit.dfm: -------------------------------------------------------------------------------- 1 | object AppContainerFieldFrame: TAppContainerFieldFrame 2 | Left = 0 3 | Top = 0 4 | Width = 375 5 | Height = 25 6 | Constraints.MinHeight = 25 7 | Constraints.MinWidth = 180 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object tbxMoniker: TEdit 12 | Left = 0 13 | Top = 2 14 | Width = 289 15 | Height = 21 16 | Anchors = [akLeft, akTop, akRight] 17 | TabOrder = 0 18 | TextHint = 'Moniker or SID' 19 | OnChange = tbxMonikerChange 20 | end 21 | object btnSelect: TButton 22 | Left = 295 23 | Top = 0 24 | Width = 80 25 | Height = 25 26 | Anchors = [akTop, akRight] 27 | Caption = 'Select...' 28 | DropDownMenu = pmMenu 29 | PopupMenu = pmMenu 30 | Style = bsSplitButton 31 | TabOrder = 1 32 | OnClick = btnSelectClick 33 | end 34 | object pmMenu: TPopupMenu 35 | Left = 200 36 | Top = 8 37 | object cmClear: TMenuItem 38 | Caption = 'Clear' 39 | OnClick = cmClearClick 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Ace.Condition.dfm: -------------------------------------------------------------------------------- 1 | inherited AceConditionFrame: TAceConditionFrame 2 | Width = 600 3 | Height = 25 4 | Constraints.MinHeight = 25 5 | Constraints.MinWidth = 200 6 | ParentShowHint = False 7 | ShowHint = True 8 | object tbxCondition: TEdit 9 | AlignWithMargins = True 10 | Left = 0 11 | Top = 2 12 | Width = 571 13 | Height = 21 14 | Margins.Left = 0 15 | Margins.Top = 2 16 | Margins.Right = 0 17 | Margins.Bottom = 2 18 | Align = alClient 19 | TabOrder = 0 20 | TextHint = 21 | 'Example: (Exists WIN://NOALLAPPPKG) || (APPID://PATH Contains "%' + 22 | 'WINDIR%\*")' 23 | OnChange = tbxConditionChange 24 | end 25 | object btnNormalize: TButton 26 | AlignWithMargins = True 27 | Left = 575 28 | Top = 0 29 | Width = 25 30 | Height = 25 31 | Hint = 'Normalize the condition' 32 | Margins.Left = 4 33 | Margins.Top = 0 34 | Margins.Right = 0 35 | Margins.Bottom = 0 36 | Align = alRight 37 | ImageAlignment = iaCenter 38 | TabOrder = 1 39 | OnClick = btnNormalizeClick 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.ListAllUsers.dfm: -------------------------------------------------------------------------------- 1 | object AppContainerListAllUsersFrame: TAppContainerListAllUsersFrame 2 | Left = 0 3 | Top = 0 4 | Width = 600 5 | Height = 440 6 | Constraints.MinHeight = 230 7 | Constraints.MinWidth = 300 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object lblUsers: TLabel 12 | Left = 3 13 | Top = 5 14 | Width = 59 15 | Height = 13 16 | Caption = 'User profile:' 17 | end 18 | object tbxUser: TEdit 19 | Left = 72 20 | Top = 2 21 | Width = 447 22 | Height = 21 23 | Anchors = [akLeft, akTop, akRight] 24 | ReadOnly = True 25 | TabOrder = 1 26 | Text = '(not selected)' 27 | end 28 | object btnSelectUser: TButton 29 | Left = 525 30 | Top = 0 31 | Width = 75 32 | Height = 25 33 | Anchors = [akTop, akRight] 34 | Caption = 'Change...' 35 | TabOrder = 2 36 | OnClick = btnSelectUserClick 37 | end 38 | inline AppContainersFrame: TAppContainerListFrame 39 | AlignWithMargins = True 40 | Left = 0 41 | Top = 29 42 | Width = 600 43 | Height = 411 44 | Margins.Left = 0 45 | Margins.Top = 29 46 | Margins.Right = 0 47 | Margins.Bottom = 0 48 | Align = alClient 49 | Constraints.MinHeight = 150 50 | Constraints.MinWidth = 300 51 | ParentShowHint = False 52 | ShowHint = True 53 | TabOrder = 0 54 | inherited Tree: TDevirtualizedTree 55 | Height = 385 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Search.dfm: -------------------------------------------------------------------------------- 1 | inherited SearchFrame: TSearchFrame 2 | Left = 0 3 | Top = 0 4 | Width = 436 5 | Height = 23 6 | Anchors = [akLeft, akTop, akRight] 7 | Constraints.MinHeight = 21 8 | Constraints.MinWidth = 240 9 | TabOrder = 0 10 | DoubleBuffered = True 11 | ParentDoubleBuffered = False 12 | object Splitter: TSplitter 13 | Left = 270 14 | Top = 0 15 | Width = 6 16 | Height = 23 17 | Align = alRight 18 | AutoSnap = False 19 | MinSize = 110 20 | ResizeStyle = rsUpdate 21 | end 22 | object tbxSearchBox: TButtonedEditEx 23 | Left = 0 24 | Top = 0 25 | Width = 270 26 | Height = 23 27 | Align = alClient 28 | TabOrder = 0 29 | TextHint = 'Search' 30 | OnKeyDown = tbxSearchBoxKeyDown 31 | OnKeyPress = tbxSearchBoxKeyPress 32 | OnRightButtonClick = tbxSearchBoxRightButtonClick 33 | OnDelayedChange = tbxSearchBoxChange 34 | OnTypingChange = tbxSearchBoxTypingChange 35 | end 36 | object cbxColumn: TComboBox 37 | Left = 276 38 | Top = 0 39 | Width = 160 40 | Height = 23 41 | Align = alRight 42 | Style = csDropDownList 43 | ExtendedUI = True 44 | ItemIndex = 0 45 | TabOrder = 1 46 | Text = 'All visible columns' 47 | OnChange = cbxColumnChange 48 | Items.Strings = ( 49 | 'All visible columns') 50 | end 51 | object ActionList: TActionList 52 | Left = 168 53 | object ActionSetFocus: TAction 54 | ShortCut = 16454 55 | OnExecute = ActionSetFocusExecute 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Security.OwnerGroup.dfm: -------------------------------------------------------------------------------- 1 | object OwnerGroupSecurityFrame: TOwnerGroupSecurityFrame 2 | Left = 0 3 | Top = 0 4 | Width = 600 5 | Height = 77 6 | Constraints.MinHeight = 77 7 | Constraints.MinWidth = 260 8 | TabOrder = 0 9 | inline SidEditor: TSidEditor 10 | Left = 0 11 | Top = 0 12 | Width = 600 13 | Height = 25 14 | Align = alTop 15 | ParentShowHint = False 16 | ShowHint = True 17 | TabOrder = 0 18 | end 19 | object GroupBox: TGroupBox 20 | Left = 0 21 | Top = 29 22 | Width = 435 23 | Height = 48 24 | Anchors = [akLeft, akTop, akRight] 25 | Caption = 'Control flags: ' 26 | TabOrder = 1 27 | object cbxDefaulted: TCheckBox 28 | Left = 11 29 | Top = 20 30 | Width = 80 31 | Height = 17 32 | Caption = 'Defaulted' 33 | TabOrder = 0 34 | end 35 | end 36 | object btnRefresh: TButton 37 | Left = 441 38 | Top = 45 39 | Width = 75 40 | Height = 25 41 | Anchors = [akTop, akRight] 42 | Caption = 'Refresh' 43 | TabOrder = 2 44 | OnClick = btnRefreshClick 45 | end 46 | object btnApply: TButton 47 | Left = 522 48 | Top = 45 49 | Width = 75 50 | Height = 25 51 | Anchors = [akTop, akRight] 52 | Caption = 'Apply' 53 | TabOrder = 3 54 | OnClick = btnApplyClick 55 | end 56 | object ActionList: TActionList 57 | Left = 312 58 | Top = 24 59 | object ActionRefresh: TAction 60 | Caption = 'ActionRefresh' 61 | ShortCut = 116 62 | OnExecute = btnRefreshClick 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Hierarchy.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.Hierarchy; 2 | 3 | { 4 | This module provides a frame for displaying tree hierarchy of known SIDs. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 12 | VirtualTreesEx, DevirtualizedTree, NtUiBackend.Sids.Hierarchy, NtUiFrame, 13 | NtUiFrame.Search, NtUiCommon.Interfaces; 14 | 15 | type 16 | TSidHierarchyFrame = class(TBaseFrame, ICanConsumeEscape, IObservesActivation, 17 | IHasDefaultCaption, IDelayedLoad) 18 | Tree: TDevirtualizedTree; 19 | SearchBox: TSearchFrame; 20 | private 21 | Backend: TTreeNodeInterfaceProvider; 22 | BackendRef: IUnknown; 23 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 24 | function GetDefaultCaption: String; 25 | protected 26 | procedure LoadedOnce; override; 27 | procedure DelayedLoad; 28 | public 29 | { Public declarations } 30 | end; 31 | 32 | implementation 33 | 34 | {$R *.dfm} 35 | 36 | { TSidHierarchyFrame } 37 | 38 | procedure TSidHierarchyFrame.DelayedLoad; 39 | begin 40 | NtUiLibAddSidHierarchyNodes(Backend); 41 | end; 42 | 43 | function TSidHierarchyFrame.GetDefaultCaption; 44 | begin 45 | Result := 'SID Hierarchy'; 46 | end; 47 | 48 | procedure TSidHierarchyFrame.LoadedOnce; 49 | begin 50 | inherited; 51 | SearchBox.AttachToTree(Tree); 52 | Backend := TTreeNodeInterfaceProvider.Create(Tree); 53 | BackendRef := Backend; // Make an owning reference 54 | end; 55 | 56 | end. 57 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Exceptions.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Exceptions; 2 | 3 | { 4 | This module allows configuring default exception handling for UI applications 5 | and adds support for capturing stack traces. 6 | } 7 | 8 | interface 9 | 10 | // Show NtUiLib exception dialog 11 | procedure ReportException(E: TObject); 12 | 13 | // Set NtUiLib exception dialog as the handler for Application.OnException 14 | procedure EnableNtUiLibExceptionHandling; 15 | 16 | implementation 17 | 18 | uses 19 | DelphiUtils.AutoObjects, DelphiUtils.AutoEvents, NtUiLib.Exceptions.Dialog, 20 | System.SysUtils, Vcl.Forms; 21 | 22 | { NtUiLib Exception Handler } 23 | 24 | procedure ReportException; 25 | begin 26 | ShowNtxException(Application.Handle, E); 27 | end; 28 | 29 | type 30 | TUIExceptionHandler = class 31 | procedure Display(Sender: TObject; E: Exception); 32 | class var Instance: IObject; 33 | end; 34 | 35 | procedure EnableNtUiLibExceptionHandling; 36 | begin 37 | // Cache the instance since we need a "procedure of object" 38 | if not Assigned(TUIExceptionHandler.Instance) then 39 | TUIExceptionHandler.Instance := Auto.CaptureObject(TUIExceptionHandler.Create); 40 | 41 | Application.OnException := TUIExceptionHandler.Instance.Self.Display; 42 | end; 43 | 44 | procedure TUIExceptionHandler.Display; 45 | begin 46 | ReportException(E); 47 | end; 48 | 49 | function ReportAutoEventsException( 50 | E: TObject 51 | ): Boolean; 52 | begin 53 | ReportException(E); 54 | Result := True; 55 | end; 56 | 57 | initialization 58 | // Enable exception handling for DelphiUtils.AutoEvents 59 | AutoExceptionHanlder := ReportAutoEventsException; 60 | end. 61 | 62 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.WellKnown.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.WellKnown; 2 | 3 | { 4 | This module provides a frame for displaying the well-known SID enumeration. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 12 | VirtualTreesEx, DevirtualizedTree, NtUiFrame, NtUiFrame.Search, 13 | NtUiCommon.Interfaces, NtUiBackend.Sids.WellKnown; 14 | 15 | type 16 | TWellKnownSidsFrame = class(TBaseFrame, ICanConsumeEscape, IObservesActivation, 17 | IHasDefaultCaption, IDelayedLoad) 18 | Tree: TDevirtualizedTree; 19 | SearchBox: TSearchFrame; 20 | private 21 | Backend: TTreeNodeInterfaceProvider; 22 | BackendRef: IUnknown; 23 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 24 | function GetDefaultCaption: String; 25 | protected 26 | procedure LoadedOnce; override; 27 | procedure DelayedLoad; 28 | end; 29 | 30 | implementation 31 | 32 | {$R *.dfm} 33 | 34 | { TWellKnownSidsFrame } 35 | 36 | procedure TWellKnownSidsFrame.DelayedLoad; 37 | var 38 | Provider: IWellKnownSidNode; 39 | begin 40 | Backend.BeginUpdateAuto; 41 | Backend.ClearItems; 42 | 43 | for Provider in NtUiLibMakeWellKnownSidNodes do 44 | Backend.AddItem(Provider); 45 | end; 46 | 47 | function TWellKnownSidsFrame.GetDefaultCaption; 48 | begin 49 | Result := 'Well-known SIDs'; 50 | end; 51 | 52 | procedure TWellKnownSidsFrame.LoadedOnce; 53 | begin 54 | inherited; 55 | SearchBox.AttachToTree(Tree); 56 | Backend := TTreeNodeInterfaceProvider.Create(Tree); 57 | BackendRef := Backend; // Make an owning reference 58 | end; 59 | 60 | end. 61 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Abbreviations.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.Abbreviations; 2 | 3 | { 4 | This module provides a frame for displaying the SDDL SID abbreviations. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 12 | VirtualTreesEx, DevirtualizedTree, NtUiFrame, NtUiFrame.Search, 13 | NtUiCommon.Interfaces; 14 | 15 | type 16 | TSidAbbreviationFrame = class(TBaseFrame, ICanConsumeEscape, IObservesActivation, 17 | IHasDefaultCaption, IDelayedLoad) 18 | Tree: TDevirtualizedTree; 19 | SearchBox: TSearchFrame; 20 | private 21 | Backend: TTreeNodeInterfaceProvider; 22 | BackendRef: IUnknown; 23 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 24 | function GetDefaultCaption: String; 25 | protected 26 | procedure LoadedOnce; override; 27 | procedure DelayedLoad; 28 | public 29 | { Public declarations } 30 | end; 31 | 32 | implementation 33 | 34 | uses 35 | NtUiBackend.Sids.Abbreviations; 36 | 37 | {$R *.dfm} 38 | 39 | { TSidAbbreviationFrame } 40 | 41 | procedure TSidAbbreviationFrame.DelayedLoad; 42 | var 43 | Provider: ISidAbbreviationNode; 44 | begin 45 | Backend.BeginUpdateAuto; 46 | Backend.ClearItems; 47 | 48 | for Provider in NtUiLibCollectSidAbbreviations do 49 | Backend.AddItem(Provider); 50 | end; 51 | 52 | function TSidAbbreviationFrame.GetDefaultCaption; 53 | begin 54 | Result := 'SDDL Abbreviations'; 55 | end; 56 | 57 | procedure TSidAbbreviationFrame.LoadedOnce; 58 | begin 59 | inherited; 60 | SearchBox.AttachToTree(Tree); 61 | Backend := TTreeNodeInterfaceProvider.Create(Tree); 62 | BackendRef := Backend; // Make an owning reference 63 | end; 64 | 65 | end. 66 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Colors.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Colors; 2 | 3 | interface 4 | 5 | uses 6 | Vcl.Graphics; 7 | 8 | type 9 | TColorSettings = record 10 | // Text background 11 | clBackgroundAllow: TColor; 12 | clBackgroundAllowAccent: TColor; 13 | clBackgroundDeny: TColor; 14 | clBackgroundDenyAccent: TColor; 15 | clBackgroundAlter: TColor; 16 | clBackgroundAlterAccent: TColor; 17 | clBackgroundError: TColor; 18 | clBackgroundInactive: TColor; 19 | clBackgroundUnsaved: TColor; 20 | clBackgroundSystem: TColor; 21 | clBackgroundUser: TColor; 22 | clBackgroundGuiThread: TColor; 23 | 24 | // Text foreground 25 | clForegroundError: TColor; 26 | clForegroundInactive: TColor; 27 | clForegroundLink: TColor; 28 | end; 29 | 30 | var 31 | ColorSettings: TColorSettings = ( 32 | clBackgroundAllow: $E0F0E0; // Light green 33 | clBackgroundAllowAccent: $C0F0C0; // Medium-light green 34 | clBackgroundDeny: $E0E0F0; // Light red 35 | clBackgroundDenyAccent: $D0D0F0; // Medium-light red 36 | clBackgroundAlter: $F0E0E0; // Light blue-gray 37 | clBackgroundAlterAccent: $F0C0C0; // Medium blue-gray 38 | clBackgroundError: $D0D0F0; // Medium-light red 39 | clBackgroundInactive: $E0E0E0; // Light gray 40 | clBackgroundUnsaved: $F5DCC2; // Light blue 41 | clBackgroundSystem: $FFDDBB; // Light blue 42 | clBackgroundUser: $AAFFFF; // Light yellow 43 | clBackgroundGuiThread: $77FFFF; // Light yellow 44 | 45 | clForegroundError: $0000F0; // Red 46 | clForegroundInactive: $808080; // Gray 47 | clForegroundLink: $D77800; // Blue 48 | ); 49 | 50 | implementation 51 | 52 | end. 53 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Logon.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.Logon; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, NtUiFrame, 8 | NtUiFrame.Search, VirtualTrees, VirtualTreesEx, DevirtualizedTree, 9 | NtUiCommon.Interfaces; 10 | 11 | type 12 | TLogonSidsFrame = class(TBaseFrame, ICanConsumeEscape, IObservesActivation, 13 | IHasDefaultCaption, IDelayedLoad) 14 | SearchBox: TSearchFrame; 15 | Tree: TDevirtualizedTree; 16 | private 17 | Backend: TTreeNodeInterfaceProvider; 18 | BackendRef: IUnknown; 19 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 20 | function GetDefaultCaption: String; 21 | protected 22 | procedure DelayedLoad; 23 | procedure LoadedOnce; override; 24 | public 25 | { Public declarations } 26 | end; 27 | 28 | implementation 29 | 30 | uses 31 | NtUtils, NtUiBackend.Sids.Logon; 32 | 33 | {$R *.dfm} 34 | 35 | { TLogonSidsFrame } 36 | 37 | procedure TLogonSidsFrame.DelayedLoad; 38 | var 39 | Status: TNtxStatus; 40 | Nodes: TArray; 41 | i: Integer; 42 | begin 43 | Status := NtUiLibCollectLogonSidNodes(Nodes); 44 | 45 | Backend.BeginUpdateAuto; 46 | Backend.ClearItems; 47 | 48 | if not Status.IsSuccess then 49 | begin 50 | Backend.SetStatus(Status); 51 | Exit; 52 | end; 53 | 54 | for i := 0 to High(Nodes) do 55 | Backend.AddItem(Nodes[i]); 56 | end; 57 | 58 | function TLogonSidsFrame.GetDefaultCaption; 59 | begin 60 | Result := 'Logon Sessions'; 61 | end; 62 | 63 | procedure TLogonSidsFrame.LoadedOnce; 64 | begin 65 | inherited; 66 | SearchBox.AttachToTree(Tree); 67 | Backend := TTreeNodeInterfaceProvider.Create(Tree); 68 | BackendRef := Backend; // Make an owning reference 69 | end; 70 | 71 | end. 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | *.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # Debug symbols 69 | *.dbg 70 | 71 | # Experimental data 72 | Experiments -------------------------------------------------------------------------------- /Prototypes/UI.Prototypes.Sid.Edit.dfm: -------------------------------------------------------------------------------- 1 | inherited SidEditor: TSidEditor 2 | Width = 600 3 | Height = 25 4 | Anchors = [akLeft, akTop, akRight] 5 | ParentShowHint = False 6 | ShowHint = True 7 | object tbxSid: TEdit 8 | AlignWithMargins = True 9 | Left = 0 10 | Top = 2 11 | Width = 513 12 | Height = 21 13 | Hint = 'Enter SID or press DOWN to show suggestions' 14 | Margins.Left = 0 15 | Margins.Top = 2 16 | Margins.Right = 0 17 | Margins.Bottom = 2 18 | Align = alClient 19 | TabOrder = 0 20 | TextHint = 'Enter SID or press DOWN to show suggestions' 21 | OnChange = tbxSidChange 22 | OnEnter = tbxSidEnter 23 | end 24 | object btnDsPicker: TButton 25 | AlignWithMargins = True 26 | Left = 575 27 | Top = 0 28 | Width = 25 29 | Height = 25 30 | Hint = 'Use the built-in dialog for selecting accounts' 31 | Margins.Left = 4 32 | Margins.Top = 0 33 | Margins.Right = 0 34 | Margins.Bottom = 0 35 | Align = alRight 36 | ImageAlignment = iaCenter 37 | ImageMargins.Left = 2 38 | TabOrder = 3 39 | OnClick = btnDsPickerClick 40 | end 41 | object btnCheatsheet: TButton 42 | AlignWithMargins = True 43 | Left = 546 44 | Top = 0 45 | Width = 25 46 | Height = 25 47 | Hint = 'Show SID abbreviation cheatsheet' 48 | Margins.Left = 4 49 | Margins.Top = 0 50 | Margins.Right = 0 51 | Margins.Bottom = 0 52 | Align = alRight 53 | ImageAlignment = iaCenter 54 | TabOrder = 2 55 | OnClick = btnCheatsheetClick 56 | end 57 | object btnChoice: TButton 58 | AlignWithMargins = True 59 | Left = 517 60 | Top = 0 61 | Width = 25 62 | Height = 25 63 | Margins.Left = 4 64 | Margins.Top = 0 65 | Margins.Right = 0 66 | Margins.Bottom = 0 67 | Align = alRight 68 | ImageAlignment = iaCenter 69 | TabOrder = 1 70 | Visible = False 71 | OnClick = btnChoiceClick 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Security.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Security; 2 | 3 | { 4 | This module provides entrypoints for showing the object security dialog. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | NtUiCommon.Prototypes; 11 | 12 | // Make an initializer for a security descriptor viewer frame 13 | function NtUiLibMakeSecurityFrame( 14 | const Context: TNtUiLibSecurityContext 15 | ): TFrameInitializer; 16 | 17 | implementation 18 | 19 | uses 20 | NtUiFrame.Security.Acl, NtUiFrame.Security.OwnerGroup, 21 | System.SysUtils, System.Classes, Vcl.Forms; 22 | 23 | function NtUiLibMakeSecurityFrame; 24 | begin 25 | if not Assigned(NtUiLibHostPages) then 26 | raise ENotSupportedException.Create('Page Host frame not available.'); 27 | 28 | Result := function (AOwner: TComponent): TFrame 29 | begin 30 | // Make a multi-page frame with ACLs and SIDs from the security descriptor 31 | Result := NtUiLibHostPages(AOwner, [ 32 | NtUiLibAclSecurityFrameInitializer(aiDacl, Context), 33 | NtUiLibSidSecurityFrameInitializer(dsOwner, Context), 34 | NtUiLibAclSecurityFrameInitializer(aiLabel, Context), 35 | NtUiLibAclSecurityFrameInitializer(aiTrust, Context), 36 | NtUiLibAclSecurityFrameInitializer(aiFilter, Context), 37 | NtUiLibAclSecurityFrameInitializer(aiAttribute, Context), 38 | NtUiLibAclSecurityFrameInitializer(aiScope, Context), 39 | NtUiLibAclSecurityFrameInitializer(aiSacl, Context), 40 | NtUiLibSidSecurityFrameInitializer(dsPrimaryGroup, Context) 41 | ], 'Object Security'); 42 | end; 43 | end; 44 | 45 | procedure NtUiLibShowSecurity( 46 | const Context: TNtUiLibSecurityContext 47 | ); 48 | begin 49 | if not Assigned(NtUiLibHostFrameShow) then 50 | raise ENotSupportedException.Create('Frame host not available'); 51 | 52 | NtUiLibHostFrameShow(NtUiLibMakeSecurityFrame(Context)); 53 | end; 54 | 55 | initialization 56 | NtUiCommon.Prototypes.NtUiLibShowSecurity := NtUiLibShowSecurity; 57 | end. 58 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sid.Integrity.dfm: -------------------------------------------------------------------------------- 1 | object FrameIntegrity: TFrameIntegrity 2 | Left = 0 3 | Top = 0 4 | Width = 268 5 | Height = 110 6 | Constraints.MinHeight = 110 7 | Constraints.MinWidth = 200 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object lblUntrusted: TLabel 12 | Left = 0 13 | Top = 91 14 | Width = 48 15 | Height = 13 16 | Caption = 'Untrusted' 17 | end 18 | object lblSystem: TLabel 19 | Left = 233 20 | Top = 91 21 | Width = 35 22 | Height = 13 23 | Alignment = taRightJustify 24 | Anchors = [akTop, akRight] 25 | Caption = 'System' 26 | end 27 | object lblMedium: TLabel 28 | Left = 116 29 | Top = 91 30 | Width = 36 31 | Height = 13 32 | Alignment = taCenter 33 | Anchors = [akTop] 34 | Caption = 'Medium' 35 | end 36 | object lblHigh: TLabel 37 | Left = 186 38 | Top = 31 39 | Width = 21 40 | Height = 13 41 | Alignment = taCenter 42 | Anchors = [akTop] 43 | Caption = 'High' 44 | end 45 | object lblLow: TLabel 46 | Left = 64 47 | Top = 31 48 | Width = 19 49 | Height = 13 50 | Alignment = taCenter 51 | Anchors = [akTop] 52 | Caption = 'Low' 53 | end 54 | object ComboBox: TComboBox 55 | Left = 0 56 | Top = 0 57 | Width = 268 58 | Height = 21 59 | Anchors = [akLeft, akTop, akRight] 60 | ItemIndex = 2 61 | TabOrder = 1 62 | Text = 'Medium (0x2000)' 63 | OnChange = ComboBoxChange 64 | Items.Strings = ( 65 | 'Untrusted (0x0000)' 66 | 'Low (0x1000)' 67 | 'Medium (0x2000)' 68 | 'Medium Plus (0x2100)' 69 | 'High (0x3000)' 70 | 'System (0x4000)' 71 | 'Protected (0x5000)') 72 | end 73 | object TrackBar: TTrackBar 74 | Left = 0 75 | Top = 50 76 | Width = 268 77 | Height = 35 78 | Anchors = [akLeft, akTop, akRight] 79 | LineSize = 512 80 | Max = 16384 81 | PageSize = 4096 82 | Frequency = 4096 83 | Position = 8192 84 | ShowSelRange = False 85 | TabOrder = 0 86 | TickMarks = tmBoth 87 | OnChange = TrackBarChange 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Sam.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.Sam; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 8 | VirtualTreesEx, DevirtualizedTree, NtUiFrame, NtUiFrame.Search, 9 | NtUiCommon.Interfaces; 10 | 11 | type 12 | TSamSidsFrame = class(TBaseFrame, ICanConsumeEscape, IObservesActivation, 13 | IHasDefaultCaption, IDelayedLoad) 14 | Tree: TDevirtualizedTree; 15 | SearchBox: TSearchFrame; 16 | private 17 | Backend: TTreeNodeInterfaceProvider; 18 | BackendRef: IUnknown; 19 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 20 | function GetDefaultCaption: String; 21 | protected 22 | procedure LoadedOnce; override; 23 | procedure DelayedLoad; 24 | public 25 | { Public declarations } 26 | end; 27 | 28 | implementation 29 | 30 | uses 31 | NtUtils, NtUiBackend.Sids.Sam; 32 | 33 | {$R *.dfm} 34 | 35 | { TSamSidFrame } 36 | 37 | procedure TSamSidsFrame.DelayedLoad; 38 | var 39 | Status: TNtxStatus; 40 | Nodes: TArray; 41 | i, j: Integer; 42 | begin 43 | Status := NtUiLibCollectSamNodes(Nodes); 44 | 45 | Backend.BeginUpdateAuto; 46 | Backend.ClearItems; 47 | 48 | if not Status.IsSuccess then 49 | begin 50 | Backend.SetStatus(Status); 51 | Exit; 52 | end; 53 | 54 | for i := 0 to High(Nodes) do 55 | begin 56 | // Domain 57 | Backend.AddItem(Nodes[i].Domain); 58 | 59 | // Groups 60 | for j := 0 to High(Nodes[i].Groups) do 61 | Backend.AddItem(Nodes[i].Groups[j], Nodes[i].Domain); 62 | 63 | // Aliases 64 | for j := 0 to High(Nodes[i].Aliases) do 65 | Backend.AddItem(Nodes[i].Aliases[j], Nodes[i].Domain); 66 | 67 | // Users 68 | for j := 0 to High(Nodes[i].Users) do 69 | Backend.AddItem(Nodes[i].Users[j], Nodes[i].Domain); 70 | end; 71 | end; 72 | 73 | function TSamSidsFrame.GetDefaultCaption; 74 | begin 75 | Result := 'SAM Accounts'; 76 | end; 77 | 78 | procedure TSamSidsFrame.LoadedOnce; 79 | begin 80 | inherited; 81 | SearchBox.AttachToTree(Tree); 82 | Backend := TTreeNodeInterfaceProvider.Create(Tree); 83 | BackendRef := Backend; // Make an owning reference 84 | end; 85 | 86 | end. 87 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.View.dfm: -------------------------------------------------------------------------------- 1 | object AppContainerViewFrame: TAppContainerViewFrame 2 | Left = 0 3 | Top = 0 4 | Width = 620 5 | Height = 200 6 | Constraints.MinHeight = 200 7 | Constraints.MinWidth = 300 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object Tree: TDevirtualizedTree 12 | Left = 0 13 | Top = 0 14 | Width = 620 15 | Height = 200 16 | Align = alClient 17 | ClipboardFormats.Strings = ( 18 | 'CSV' 19 | 'Plain text' 20 | 'Unicode text') 21 | Header.AutoSizeIndex = 1 22 | Header.DefaultHeight = 24 23 | Header.Height = 24 24 | Header.MainColumn = 1 25 | Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 26 | HintMode = hmTooltip 27 | TabOrder = 0 28 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 29 | TreeOptions.ExportMode = emSelected 30 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 31 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 32 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 33 | Touch.InteractiveGestures = [igPan, igPressAndTap] 34 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 35 | Columns = < 36 | item 37 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 38 | Position = 0 39 | Text = 'Property' 40 | Width = 120 41 | end 42 | item 43 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 44 | Position = 1 45 | Text = 'Value' 46 | Width = 500 47 | end> 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.View.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.AppContainer.View; 2 | 3 | { 4 | This module provides a dialog for viewing an AppContainer profile. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, 11 | Vcl.Forms, Vcl.Dialogs, VirtualTrees, VirtualTreesEx, DevirtualizedTree, 12 | NtUiBackend.AppContainers, NtUiCommon.Interfaces; 13 | 14 | type 15 | TAppContainerViewFrame = class(TFrame, IHasDefaultCaption) 16 | Tree: TDevirtualizedTree; 17 | private 18 | FInfo: TRtlxAppContainerInfo; 19 | procedure InspectMenu(Node: PVirtualNode); 20 | protected 21 | procedure Loaded; override; 22 | public 23 | function GetDefaultCaption: String; 24 | procedure LoadFor(const Info: TRtlxAppContainerInfo); 25 | end; 26 | 27 | implementation 28 | 29 | uses 30 | NtUiCommon.Prototypes; 31 | 32 | {$R *.dfm} 33 | 34 | { TAppContainerViewFrame } 35 | 36 | function TAppContainerViewFrame.GetDefaultCaption; 37 | begin 38 | Result := 'AppContainer Information'; 39 | end; 40 | 41 | procedure TAppContainerViewFrame.InspectMenu; 42 | begin 43 | if FInfo.IsChild and Assigned(Tree.FocusedNode) then 44 | UiLibInspectAppContainerProperty(FInfo, Tree.FocusedNode.Index); 45 | end; 46 | 47 | procedure TAppContainerViewFrame.Loaded; 48 | begin 49 | inherited; 50 | Tree.OnMainAction := InspectMenu; 51 | end; 52 | 53 | procedure TAppContainerViewFrame.LoadFor; 54 | begin 55 | FInfo := Info; 56 | UiLibMakeAppContainerPropertyNodes(Tree, Info); 57 | end; 58 | 59 | { Integration } 60 | 61 | function Initializer(const Info: TRtlxAppContainerInfo): TFrameInitializer; 62 | begin 63 | Result := function (AOwner: TComponent): TFrame 64 | var 65 | Frame: TAppContainerViewFrame absolute Result; 66 | begin 67 | Frame := TAppContainerViewFrame.Create(AOwner); 68 | try 69 | Frame.LoadFor(Info); 70 | except 71 | Frame.Free; 72 | raise; 73 | end; 74 | end; 75 | end; 76 | 77 | procedure NtUiLibShowAppContainer(const Info: TRtlxAppContainerInfo); 78 | begin 79 | if not Assigned(NtUiLibHostFramePick) then 80 | raise ENotSupportedException.Create('Frame host not available'); 81 | 82 | NtUiLibHostFrameShow(Initializer(Info)); 83 | end; 84 | 85 | initialization 86 | NtUiCommon.Prototypes.NtUiLibShowAppContainer := NtUiLibShowAppContainer; 87 | end. 88 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Guid.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Guid; 2 | 3 | { 4 | This module provides a control for specifying GUIDs. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, NtUtils; 12 | 13 | type 14 | TGuidFrame = class(TFrame) 15 | tbxGuid: TEdit; 16 | procedure tbxGuidChange(Sender: TObject); 17 | procedure tbxGuidExit(Sender: TObject); 18 | private 19 | FGuid: TGuid; 20 | FGuidValid: Boolean; 21 | function GetGuid: TGuid; 22 | procedure SetGuid(const Value: TGuid); 23 | protected 24 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 25 | public 26 | function TryGetGuid(out Value: TGuid): TNtxStatus; 27 | property Guid: TGuid read GetGuid write SetGuid; 28 | end; 29 | 30 | implementation 31 | 32 | uses 33 | NtUtils.SysUtils, NtUiCommon.Colors; 34 | 35 | {$R *.dfm} 36 | 37 | { TGuidFrame } 38 | 39 | procedure TGuidFrame.FrameEnabledChanged; 40 | begin 41 | inherited; 42 | tbxGuid.Enabled := Enabled; 43 | end; 44 | 45 | function TGuidFrame.GetGuid; 46 | begin 47 | TryGetGuid(Result).RaiseOnError; 48 | end; 49 | 50 | procedure TGuidFrame.SetGuid; 51 | var 52 | OnChangeReverter: IDeferredOperation; 53 | begin 54 | // Prevent recursion 55 | tbxGuid.OnChange := nil; 56 | OnChangeReverter := Auto.Defer( 57 | procedure 58 | begin 59 | tbxGuid.OnChange := tbxGuidChange; 60 | end 61 | ); 62 | 63 | FGuid := Value; 64 | FGuidValid := True; 65 | tbxGuid.Text := RtlxGuidToString(Value); 66 | tbxGuid.Color := clWindow; 67 | end; 68 | 69 | procedure TGuidFrame.tbxGuidChange; 70 | begin 71 | FGuidValid := False; 72 | TryGetGuid(FGuid); 73 | end; 74 | 75 | procedure TGuidFrame.tbxGuidExit; 76 | begin 77 | if not FGuidValid then 78 | SetGuid(Default(TGuid)); 79 | end; 80 | 81 | function TGuidFrame.TryGetGuid; 82 | begin 83 | if FGuidValid then 84 | begin 85 | Value := FGuid; 86 | Exit(NtxSuccess); 87 | end; 88 | 89 | Result := RtlxStringToGuid(tbxGuid.Text, FGuid); 90 | FGuidValid := Result.IsSuccess; 91 | 92 | if FGuidValid then 93 | begin 94 | Value := FGuid; 95 | tbxGuid.Color := clWindow; 96 | end 97 | else 98 | tbxGuid.Color := ColorSettings.clBackgroundError; 99 | end; 100 | 101 | end. 102 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Security.Acl.dfm: -------------------------------------------------------------------------------- 1 | object AclSecurityFrame: TAclSecurityFrame 2 | Left = 0 3 | Top = 0 4 | Width = 620 5 | Height = 300 6 | Constraints.MinHeight = 235 7 | Constraints.MinWidth = 400 8 | TabOrder = 0 9 | inline AclFrame: TAclFrame 10 | Left = 0 11 | Top = 0 12 | Width = 620 13 | Height = 230 14 | Anchors = [akLeft, akTop, akRight, akBottom] 15 | Constraints.MinHeight = 165 16 | Constraints.MinWidth = 320 17 | ParentShowHint = False 18 | ShowHint = True 19 | TabOrder = 0 20 | end 21 | object btnRefresh: TButton 22 | Left = 545 23 | Top = 241 24 | Width = 75 25 | Height = 25 26 | Anchors = [akRight, akBottom] 27 | Caption = 'Refresh' 28 | TabOrder = 2 29 | OnClick = btnRefreshClick 30 | end 31 | object btnApply: TButton 32 | Left = 545 33 | Top = 272 34 | Width = 75 35 | Height = 25 36 | Anchors = [akRight, akBottom] 37 | Caption = 'Apply' 38 | TabOrder = 3 39 | OnClick = btnApplyClick 40 | end 41 | object GroupBox: TGroupBox 42 | Left = 0 43 | Top = 234 44 | Width = 539 45 | Height = 66 46 | Anchors = [akLeft, akRight, akBottom] 47 | Caption = 'Control flags: ' 48 | TabOrder = 1 49 | object cbxInherited: TCheckBox 50 | Left = 224 51 | Top = 20 52 | Width = 140 53 | Height = 17 54 | Anchors = [akTop] 55 | Caption = 'Auto-inherited' 56 | TabOrder = 2 57 | end 58 | object cbxProtected: TCheckBox 59 | Left = 447 60 | Top = 20 61 | Width = 80 62 | Height = 17 63 | Anchors = [akTop, akRight] 64 | Caption = 'Protected' 65 | TabOrder = 4 66 | end 67 | object cbxInheritReq: TCheckBox 68 | Left = 224 69 | Top = 41 70 | Width = 140 71 | Height = 17 72 | Anchors = [akTop] 73 | Caption = 'Auto-inherit required' 74 | TabOrder = 3 75 | end 76 | object cbxDefaulted: TCheckBox 77 | Left = 8 78 | Top = 20 79 | Width = 80 80 | Height = 17 81 | Caption = 'Defaulted' 82 | TabOrder = 0 83 | end 84 | object cbxPresent: TCheckBox 85 | Left = 8 86 | Top = 41 87 | Width = 80 88 | Height = 17 89 | Caption = 'Present' 90 | TabOrder = 1 91 | OnClick = cbxPresentClick 92 | end 93 | end 94 | object ActionList: TActionList 95 | Left = 440 96 | Top = 104 97 | object ActionRefresh: TAction 98 | ShortCut = 116 99 | OnExecute = btnRefreshClick 100 | end 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Icons.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Icons; 2 | 3 | { This module provides storage for icons extracted from executable files. Once 4 | obtained, the icon is cached in an ImageList and can be used in the UI. } 5 | 6 | interface 7 | 8 | uses 9 | System.SysUtils, System.Generics.Collections, Vcl.Controls; 10 | 11 | type 12 | TProcessIcons = class abstract 13 | private 14 | class var Images: TImageList; 15 | class var Mapping: TDictionary; 16 | public 17 | class constructor Create; 18 | class destructor Destroy; 19 | class property ImageList: TImageList read Images; 20 | class function GetIcon(FileName: String): Integer; static; 21 | class function GetIconByPid(PID: NativeUInt): Integer; static; 22 | end; 23 | 24 | implementation 25 | 26 | uses 27 | Vcl.ImgList, Vcl.Graphics, Ntapi.WinUser, Ntapi.ShellApi, Ntapi.WinNt, 28 | Ntapi.ntpebteb, NtUtils, NtUtils.Files, NtUtils.Processes.Info; 29 | 30 | { TProcessIcons } 31 | 32 | class constructor TProcessIcons.Create; 33 | begin 34 | Mapping := TDictionary.Create; 35 | 36 | Images := TImageList.Create(nil); 37 | Images.ColorDepth := cd32Bit; 38 | Images.AllocBy := 32; 39 | 40 | // Add default fallback icon 41 | GetIcon(USER_SHARED_DATA.NtSystemRoot + '\system32\user32.dll'); 42 | end; 43 | 44 | class destructor TProcessIcons.Destroy; 45 | begin 46 | Images.Free; 47 | Mapping.Free; 48 | end; 49 | 50 | class function TProcessIcons.GetIcon; 51 | var 52 | ObjIcon: TIcon; 53 | SmallHIcon: THIcon; 54 | begin 55 | // Start with the default icon 56 | Result := 0; 57 | 58 | // Unknown filename means default icon 59 | if FileName = '' then 60 | Exit; 61 | 62 | // Check if the icon for this file is already here 63 | if Mapping.TryGetValue(FileName, Result) then 64 | Exit; 65 | 66 | SmallHIcon := 0; 67 | 68 | // Try to query the icon 69 | if (ExtractIconExW(PWideChar(FileName), 0, nil, @SmallHIcon, 1) <> 0) and 70 | (SmallHIcon <> 0) then 71 | begin 72 | // Save it to our ImageList 73 | ObjIcon := TIcon.Create; 74 | ObjIcon.Handle := SmallHIcon; 75 | Result := Images.AddIcon(ObjIcon); 76 | 77 | ObjIcon.Free; 78 | DestroyIcon(SmallHIcon); 79 | end; 80 | 81 | // Save the icon index for future use 82 | Mapping.Add(FileName, Result); 83 | end; 84 | 85 | class function TProcessIcons.GetIconByPid; 86 | var 87 | NtImageName: String; 88 | begin 89 | // Querying NT filename almost never fails 90 | if NtxQueryImageNameProcessId(PID, NtImageName).IsSuccess then 91 | NtImageName := RtlxNativePathToDosPath(NtImageName) 92 | else 93 | NtImageName := ''; 94 | 95 | Result := GetIcon(NtImageName); 96 | end; 97 | 98 | end. 99 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame; 2 | 3 | { 4 | This file defines the base class for frames with extended functionality. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Vcl.Forms, Vcl.Controls; 11 | 12 | type 13 | TResourceIconChange = procedure (ImageList: TImageList; ImageIndex: Integer) of object; 14 | 15 | TResourceIcon = record 16 | IconName: String; 17 | Callback: TResourceIconChange; 18 | end; 19 | 20 | TBaseFrame = class (TFrame) 21 | private 22 | FLoaded: Boolean; 23 | FResourceIcons: TArray; 24 | protected 25 | FImages: TImageList; 26 | procedure Loaded; override; 27 | procedure LoadedOnce; virtual; 28 | procedure ChangeScale(M, D: Integer; isDpiChange: Boolean); override; 29 | procedure ReloadResourceIcons; 30 | procedure RegisterResourceIcon(const IconName: String; Callback: TResourceIconChange); 31 | end; 32 | 33 | implementation 34 | 35 | uses 36 | Vcl.Graphics, Vcl.ImgList, DelphiUtils.AutoObjects; 37 | 38 | {$R *.dfm} 39 | 40 | { TBaseFrame } 41 | 42 | procedure TBaseFrame.ChangeScale(M, D: Integer; isDpiChange: Boolean); 43 | begin 44 | inherited; 45 | 46 | if isDpiChange and FLoaded then 47 | ReloadResourceIcons; 48 | end; 49 | 50 | procedure TBaseFrame.Loaded; 51 | begin 52 | inherited; 53 | 54 | if FLoaded then 55 | Exit; 56 | 57 | FLoaded := True; 58 | FImages := TImageList.Create(Self); 59 | FImages.ColorDepth := cd32Bit; 60 | 61 | LoadedOnce; 62 | ReloadResourceIcons; 63 | end; 64 | 65 | procedure TBaseFrame.LoadedOnce; 66 | begin 67 | ; 68 | end; 69 | 70 | procedure TBaseFrame.RegisterResourceIcon; 71 | begin 72 | SetLength(FResourceIcons, Length(FResourceIcons) + 1); 73 | FResourceIcons[High(FResourceIcons)].IconName := IconName; 74 | FResourceIcons[High(FResourceIcons)].Callback := Callback; 75 | end; 76 | 77 | procedure TBaseFrame.ReloadResourceIcons; 78 | var 79 | i: Integer; 80 | Icon: TIcon; 81 | IconIndex: Integer; 82 | begin 83 | // Reset all icons on subscribers 84 | for i := 0 to High(FResourceIcons) do 85 | FResourceIcons[i].Callback(nil, -1); 86 | 87 | // Adjust the desired resolution 88 | FImages.Clear; 89 | FImages.Width := 16 * CurrentPPI div 96; 90 | FImages.Height := 16 * CurrentPPI div 96; 91 | 92 | for i := 0 to High(FResourceIcons) do 93 | begin 94 | Icon := Auto.CaptureObject(TIcon.Create).Self; 95 | Icon.LoadFromResourceName(HInstance, FResourceIcons[i].IconName); 96 | IconIndex := FImages.AddIcon(Icon); 97 | 98 | if IconIndex >= 0 then 99 | FResourceIcons[i].Callback(FImages, IconIndex); 100 | end; 101 | end; 102 | 103 | end. 104 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Forms.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Forms; 2 | 3 | { 4 | This module provides base classes for forms. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, System.Classes, Vcl.Controls, Vcl.Forms, 11 | DelphiUtils.AutoObjects, DelphiUtils.AutoEvents, VclEx.Form; 12 | 13 | type 14 | TMainForm = class abstract (TFormEx) 15 | private 16 | class var FInstance: TMainForm; 17 | public 18 | constructor Create(AOwner: TComponent); override; 19 | destructor Destroy; override; 20 | class property Instance: TMainForm read FInstance; 21 | class var OnMainFormClose: TAutoEvent; 22 | end; 23 | 24 | TChildFormMode = ( 25 | cfmNormal, // No taskbar; overlaps the owner 26 | cfmApplication, // No taskbar; side-by-side with the owner; use with modal 27 | cfmDesktop // Visible on taskbar; side-by-side with the owner 28 | ); 29 | 30 | TChildForm = class abstract (TFormEx) 31 | private 32 | FChildMode: TChildFormMode; 33 | FMainFormCloseSubscription: IAutoReleasable; 34 | protected 35 | procedure CreateParams(var Params: TCreateParams); override; 36 | procedure DoCreate; override; 37 | procedure DoShow; override; 38 | public 39 | constructor Create(AOwner: TComponent; Mode: TChildFormMode); reintroduce; 40 | property ChildMode: TChildFormMode read FChildMode; 41 | end; 42 | 43 | implementation 44 | 45 | uses 46 | System.SysUtils, NtUiCommon.Exceptions; 47 | 48 | { TMainForm } 49 | 50 | constructor TMainForm.Create; 51 | begin 52 | inherited Create(AOwner); 53 | Assert(not Assigned(FInstance), 'Created multiple main forms.'); 54 | FInstance := Self; 55 | end; 56 | 57 | destructor TMainForm.Destroy; 58 | begin 59 | if FInstance = Self then 60 | FInstance := nil; 61 | 62 | inherited; 63 | end; 64 | 65 | { TChildForm } 66 | 67 | constructor TChildForm.Create; 68 | begin 69 | FChildMode := Mode; 70 | inherited Create(AOwner); 71 | 72 | if FChildMode <> cfmDesktop then 73 | BorderIcons := BorderIcons - [biMinimize]; 74 | end; 75 | 76 | procedure TChildForm.CreateParams; 77 | begin 78 | inherited; 79 | 80 | case FChildMode of 81 | cfmApplication: Params.WndParent := Application.Handle; 82 | cfmDesktop: Params.WndParent := HWND_DESKTOP 83 | end; 84 | end; 85 | 86 | procedure TChildForm.DoCreate; 87 | begin 88 | inherited; 89 | FMainFormCloseSubscription := TMainForm.OnMainFormClose.Subscribe(Close); 90 | end; 91 | 92 | procedure TChildForm.DoShow; 93 | begin 94 | // Our parent class makes us inherit stay-on-top from the owner 95 | inherited; 96 | 97 | // If there is no owner, inherit it from the main form 98 | if not Assigned(Owner) and Assigned(TMainForm.Instance) and 99 | (TMainForm.Instance.FormStyle = fsStayOnTop) and (FormStyle = fsNormal) then 100 | FormStyle := fsStayOnTop; 101 | end; 102 | 103 | end. 104 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Capabilities.dfm: -------------------------------------------------------------------------------- 1 | object CapabilityListFrame: TCapabilityListFrame 2 | Left = 0 3 | Top = 0 4 | Width = 640 5 | Height = 480 6 | TabOrder = 0 7 | inline SearchBox: TSearchFrame 8 | Left = 0 9 | Top = 0 10 | Width = 640 11 | Height = 21 12 | Align = alTop 13 | Constraints.MinHeight = 21 14 | Constraints.MinWidth = 240 15 | ParentShowHint = False 16 | ShowHint = True 17 | TabOrder = 0 18 | inherited Splitter: TSplitter 19 | Left = 474 20 | end 21 | inherited tbxSearchBox: TButtonedEditEx 22 | Width = 474 23 | end 24 | inherited cbxColumn: TComboBox 25 | Left = 480 26 | end 27 | end 28 | object Tree: TDevirtualizedTree 29 | AlignWithMargins = True 30 | Left = 0 31 | Top = 26 32 | Width = 640 33 | Height = 454 34 | Margins.Left = 0 35 | Margins.Top = 5 36 | Margins.Right = 0 37 | Margins.Bottom = 0 38 | Align = alClient 39 | ClipboardFormats.Strings = ( 40 | 'CSV' 41 | 'Plain text' 42 | 'Unicode text') 43 | Header.AutoSizeIndex = 0 44 | Header.DefaultHeight = 24 45 | Header.Height = 24 46 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 47 | TabOrder = 1 48 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 49 | TreeOptions.ExportMode = emSelected 50 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 51 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 52 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 53 | Touch.InteractiveGestures = [igPan, igPressAndTap] 54 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 55 | NoItemsText = 'Not initialized' 56 | Columns = < 57 | item 58 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 59 | Position = 0 60 | Text = 'Name' 61 | Width = 300 62 | end 63 | item 64 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 65 | Position = 1 66 | Text = 'Capability SID' 67 | Width = 300 68 | end 69 | item 70 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 71 | Position = 2 72 | Text = 'Group Capability SID' 73 | Width = 300 74 | end> 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /Prototypes/UI.Prototypes.Groups.dfm: -------------------------------------------------------------------------------- 1 | object FrameGroups: TFrameGroups 2 | Left = 0 3 | Top = 0 4 | Width = 493 5 | Height = 304 6 | DoubleBuffered = True 7 | ParentDoubleBuffered = False 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object VST: TDevirtualizedTree 12 | Left = 0 13 | Top = 0 14 | Width = 493 15 | Height = 304 16 | Align = alClient 17 | ClipboardFormats.Strings = ( 18 | 'CSV' 19 | 'Plain text' 20 | 'Unicode text') 21 | Header.AutoSizeIndex = 0 22 | Header.DefaultHeight = 24 23 | Header.Height = 24 24 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 25 | TabOrder = 0 26 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 27 | TreeOptions.ExportMode = emSelected 28 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 29 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 30 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 31 | Touch.InteractiveGestures = [igPan, igPressAndTap] 32 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 33 | NoItemsText = 'No items to display' 34 | Columns = < 35 | item 36 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 37 | Position = 0 38 | Text = 'Friendly Name' 39 | Width = 220 40 | end 41 | item 42 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 43 | Position = 1 44 | Text = 'SID' 45 | Width = 280 46 | end 47 | item 48 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 49 | Position = 2 50 | Text = 'SID Type' 51 | Width = 110 52 | end 53 | item 54 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 55 | Position = 3 56 | Text = 'State' 57 | Width = 100 58 | end 59 | item 60 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 61 | Position = 4 62 | Text = 'Flags' 63 | Width = 120 64 | end> 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.Edit.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.AppContainer.Edit; 2 | 3 | { 4 | This module provides a small control for specifying an AppContainer SID. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, 11 | Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Menus, NtUtils, 12 | NtUtils.Security.AppContainer; 13 | 14 | type 15 | TAppContainerFieldFrame = class(TFrame) 16 | tbxMoniker: TEdit; 17 | btnSelect: TButton; 18 | pmMenu: TPopupMenu; 19 | cmClear: TMenuItem; 20 | procedure btnSelectClick(Sender: TObject); 21 | procedure cmClearClick(Sender: TObject); 22 | procedure tbxMonikerChange(Sender: TObject); 23 | private 24 | FUser, FSid: ISid; 25 | function GetSid: ISid; 26 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 27 | protected 28 | procedure Loaded; override; 29 | public 30 | function TrySetUserFromToken(const hxToken: IHandle): TNtxStatus; 31 | [MayReturnNil] property Sid: ISid read GetSid; 32 | end; 33 | 34 | implementation 35 | 36 | uses 37 | Ntapi.ntseapi, NtUtils.Tokens, NtUtils.Tokens.Info, NtUiBackend.AppContainers, 38 | Vcl.ComCtrls, NtUiCommon.Prototypes; 39 | 40 | {$R *.dfm} 41 | 42 | { TAppContainerFieldFrame } 43 | 44 | procedure TAppContainerFieldFrame.btnSelectClick; 45 | var 46 | Info: TRtlxAppContainerInfo; 47 | begin 48 | if not Assigned(NtUiLibSelectAppContainerAllUsers) then 49 | Exit; 50 | 51 | if not Assigned(FUser) then 52 | NtxQuerySidToken(NtxCurrentEffectiveToken, TokenUser, FUser).RaiseOnError; 53 | 54 | // Show a modal dialog with AppContainer list 55 | Info := NtUiLibSelectAppContainerAllUsers(Self, FUser); 56 | 57 | FUser := Info.User; 58 | FSid := Info.Sid; 59 | tbxMoniker.Text := Info.FullMoniker; 60 | tbxMoniker.Hint := Info.Hint; 61 | end; 62 | 63 | procedure TAppContainerFieldFrame.cmClearClick; 64 | begin 65 | FSid := nil; 66 | tbxMoniker.Text := ''; 67 | tbxMoniker.Hint := ''; 68 | end; 69 | 70 | procedure TAppContainerFieldFrame.FrameEnabledChanged; 71 | begin 72 | inherited; 73 | tbxMoniker.Enabled := Enabled; 74 | btnSelect.Enabled := Enabled; 75 | end; 76 | 77 | function TAppContainerFieldFrame.GetSid; 78 | begin 79 | if Assigned(FSid) then 80 | Exit(FSid); 81 | 82 | Result := UiLibDeriveAppContainer(tbxMoniker.Text); 83 | FSid := Result; 84 | end; 85 | 86 | procedure TAppContainerFieldFrame.Loaded; 87 | begin 88 | inherited; 89 | 90 | // Don't use split button style without manifests; note that the user should 91 | // still be able to trigger the menu via a right mouse click 92 | if GetComCtlVersion < ComCtlVersionIE6 then 93 | btnSelect.Style := bsPushButton; 94 | end; 95 | 96 | procedure TAppContainerFieldFrame.tbxMonikerChange; 97 | begin 98 | FSid := nil; 99 | tbxMoniker.Hint := ''; 100 | end; 101 | 102 | function TAppContainerFieldFrame.TrySetUserFromToken; 103 | var 104 | User: ISid; 105 | begin 106 | Result := NtxQuerySidToken(hxToken, TokenUser, User); 107 | 108 | if Result.IsSuccess then 109 | FUser := User; 110 | end; 111 | 112 | end. 113 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Hex.Edit.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Hex.Edit; 2 | 3 | { 4 | This module includes a simple control for viewing/editing binary data as hex. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, NtUtils; 12 | 13 | type 14 | THexEditFrame = class(TFrame) 15 | tbxHexString: TEdit; 16 | procedure tbxHexStringChange(Sender: TObject); 17 | procedure tbxHexStringExit(Sender: TObject); 18 | private 19 | FOnDataChanged: TNotifyEvent; 20 | FData: IMemory; 21 | function GetData: IMemory; 22 | procedure SetData(const Value: IMemory); 23 | procedure UpdateHint; 24 | protected 25 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 26 | public 27 | function TryGetData(out Value: IMemory): Boolean; 28 | property Data: IMemory read GetData write SetData; 29 | property OnDataChange: TNotifyEvent read FOnDataChanged write FOnDataChanged; 30 | end; 31 | 32 | implementation 33 | 34 | uses 35 | NtUiBackend.HexView, NtUiCommon.Colors, DelphiUiLib.Strings; 36 | 37 | {$R *.dfm} 38 | 39 | { THexEditFrame } 40 | 41 | procedure THexEditFrame.FrameEnabledChanged; 42 | begin 43 | inherited; 44 | tbxHexString.Enabled := Enabled; 45 | end; 46 | 47 | function THexEditFrame.GetData; 48 | begin 49 | if not TryGetData(Result) then 50 | raise EParserError.Create('Invalid hexadecimal data specified.'); 51 | end; 52 | 53 | procedure THexEditFrame.SetData; 54 | var 55 | OnChangeReverter: IDeferredOperation; 56 | begin 57 | // Prevent recursive calls 58 | tbxHexString.OnChange := nil; 59 | OnChangeReverter := Auto.Defer( 60 | procedure 61 | begin 62 | tbxHexString.OnChange := tbxHexStringChange; 63 | end 64 | ); 65 | 66 | FData := Value; 67 | tbxHexString.Text := UiLibRepresentHexData(Value); 68 | tbxHexString.Color := clWindow; 69 | UpdateHint; 70 | end; 71 | 72 | procedure THexEditFrame.tbxHexStringChange; 73 | begin 74 | // Refresh the cached data 75 | FData := nil; 76 | TryGetData(FData); 77 | 78 | if Assigned(FOnDataChanged) then 79 | FOnDataChanged(Self); 80 | end; 81 | 82 | procedure THexEditFrame.tbxHexStringExit; 83 | begin 84 | SetData(FData); 85 | end; 86 | 87 | function THexEditFrame.TryGetData; 88 | begin 89 | // Use cached data when available 90 | if Assigned(FData) then 91 | begin 92 | Value := FData; 93 | Result := True; 94 | Exit; 95 | end; 96 | 97 | Result := UiLibParseHexData(tbxHexString.Text, FData); 98 | 99 | if Result then 100 | tbxHexString.Color := clWindow 101 | else 102 | tbxHexString.Color := ColorSettings.clBackgroundError; 103 | 104 | UpdateHint; 105 | end; 106 | 107 | procedure THexEditFrame.UpdateHint; 108 | begin 109 | if Assigned(FData) then 110 | tbxHexString.Hint := BuildHint([ 111 | THintSection.New('Number of bytes (dec)', UiLibUIntToDec(FData.Size)), 112 | THintSection.New('Number of bytes (hex)', UiLibUIntToHex(FData.Size)) 113 | ]) 114 | else 115 | tbxHexString.Hint := ''; 116 | end; 117 | 118 | end. 119 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Abbreviations.dfm: -------------------------------------------------------------------------------- 1 | inherited SidAbbreviationFrame: TSidAbbreviationFrame 2 | Width = 640 3 | Height = 400 4 | Constraints.MinHeight = 120 5 | Constraints.MinWidth = 300 6 | object Tree: TDevirtualizedTree 7 | AlignWithMargins = True 8 | Left = 0 9 | Top = 24 10 | Width = 640 11 | Height = 376 12 | Margins.Left = 0 13 | Margins.Right = 0 14 | Margins.Bottom = 0 15 | Align = alClient 16 | ClipboardFormats.Strings = ( 17 | 'CSV' 18 | 'Plain text' 19 | 'Unicode text') 20 | Header.AutoSizeIndex = 0 21 | Header.DefaultHeight = 24 22 | Header.Height = 24 23 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 24 | TabOrder = 0 25 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 26 | TreeOptions.ExportMode = emSelected 27 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 28 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 29 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 30 | Touch.InteractiveGestures = [igPan, igPressAndTap] 31 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 32 | NoItemsText = 'Unable to enumerate' 33 | Columns = < 34 | item 35 | Position = 0 36 | Text = 'SDDL' 37 | end 38 | item 39 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 40 | Position = 1 41 | Text = 'Friendly Name' 42 | Width = 300 43 | end 44 | item 45 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 46 | Position = 2 47 | Text = 'SID' 48 | Width = 280 49 | end 50 | item 51 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 52 | Position = 3 53 | Text = 'SID Type' 54 | Width = 110 55 | end> 56 | end 57 | inline SearchBox: TSearchFrame 58 | Left = 0 59 | Top = 0 60 | Width = 640 61 | Height = 21 62 | Align = alTop 63 | Constraints.MinHeight = 21 64 | Constraints.MinWidth = 240 65 | ParentShowHint = False 66 | ShowHint = True 67 | TabOrder = 1 68 | inherited Splitter: TSplitter 69 | Left = 474 70 | end 71 | inherited tbxSearchBox: TButtonedEditEx 72 | Width = 474 73 | end 74 | inherited cbxColumn: TComboBox 75 | Left = 480 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Bits.dfm: -------------------------------------------------------------------------------- 1 | object BitsFrame: TBitsFrame 2 | Left = 0 3 | Top = 0 4 | Width = 320 5 | Height = 317 6 | Constraints.MinHeight = 100 7 | Constraints.MinWidth = 224 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object Tree: TDevirtualizedTree 12 | Left = 0 13 | Top = 0 14 | Width = 320 15 | Height = 289 16 | Align = alClient 17 | ClipboardFormats.Strings = ( 18 | 'CSV' 19 | 'Plain text' 20 | 'Unicode text') 21 | Header.AutoSizeIndex = 0 22 | Header.DefaultHeight = 24 23 | Header.Height = 24 24 | Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 25 | TabOrder = 0 26 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 27 | TreeOptions.ExportMode = emSelected 28 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 29 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 30 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 31 | OnChecked = TreeChecked 32 | Touch.InteractiveGestures = [igPan, igPressAndTap] 33 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 34 | NoItemsText = 'No flags to display' 35 | Columns = < 36 | item 37 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 38 | Position = 0 39 | Text = 'Name' 40 | Width = 320 41 | end> 42 | end 43 | object BottomPanel: TPanel 44 | Left = 0 45 | Top = 289 46 | Width = 320 47 | Height = 28 48 | Align = alBottom 49 | BevelOuter = bvNone 50 | ShowCaption = False 51 | TabOrder = 1 52 | object tbxValue: TEdit 53 | AlignWithMargins = True 54 | Left = 73 55 | Top = 5 56 | Width = 174 57 | Height = 21 58 | Margins.Left = 0 59 | Margins.Top = 5 60 | Margins.Right = 0 61 | Margins.Bottom = 2 62 | Align = alClient 63 | MaxLength = 30 64 | TabOrder = 0 65 | OnChange = tbxValueChange 66 | end 67 | object btnClear: TButton 68 | AlignWithMargins = True 69 | Left = 0 70 | Top = 3 71 | Width = 70 72 | Height = 25 73 | Margins.Left = 0 74 | Margins.Bottom = 0 75 | Align = alLeft 76 | Caption = 'Clear' 77 | TabOrder = 1 78 | OnClick = btnClearClick 79 | end 80 | object btnAll: TButton 81 | AlignWithMargins = True 82 | Left = 250 83 | Top = 3 84 | Width = 70 85 | Height = 25 86 | Margins.Right = 0 87 | Margins.Bottom = 0 88 | Align = alRight 89 | Caption = 'All' 90 | TabOrder = 2 91 | OnClick = btnAllClick 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sid.Trust.dfm: -------------------------------------------------------------------------------- 1 | object FrameTrustSid: TFrameTrustSid 2 | Left = 0 3 | Top = 0 4 | Width = 400 5 | Height = 185 6 | Constraints.MinHeight = 185 7 | Constraints.MinWidth = 330 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object lblNoneType: TLabel 12 | Left = 3 13 | Top = 27 14 | Width = 25 15 | Height = 13 16 | Caption = 'None' 17 | end 18 | object lblLight: TLabel 19 | Left = 190 20 | Top = 27 21 | Width = 23 22 | Height = 13 23 | Alignment = taCenter 24 | Anchors = [akTop] 25 | Caption = 'Light' 26 | end 27 | object lblFull: TLabel 28 | Left = 381 29 | Top = 27 30 | Width = 16 31 | Height = 13 32 | Alignment = taRightJustify 33 | Anchors = [akTop, akRight] 34 | Caption = 'Full' 35 | end 36 | object lblNoneLevel: TLabel 37 | Left = 3 38 | Top = 167 39 | Width = 25 40 | Height = 13 41 | Caption = 'None' 42 | end 43 | object lblAntimalware: TLabel 44 | Left = 53 45 | Top = 167 46 | Width = 59 47 | Height = 13 48 | Anchors = [akTop] 49 | Caption = 'Antimalware' 50 | end 51 | object lblWindows: TLabel 52 | Left = 180 53 | Top = 167 54 | Width = 43 55 | Height = 13 56 | Alignment = taCenter 57 | Anchors = [akTop] 58 | Caption = 'Windows' 59 | end 60 | object lblWinTcb: TLabel 61 | Left = 360 62 | Top = 167 63 | Width = 37 64 | Height = 13 65 | Anchors = [akTop, akRight] 66 | Caption = 'WinTCB' 67 | end 68 | object TrackBarType: TTrackBar 69 | Left = 0 70 | Top = 47 71 | Width = 400 72 | Height = 35 73 | Anchors = [akLeft, akTop, akRight] 74 | LineSize = 128 75 | Max = 1024 76 | PageSize = 512 77 | Frequency = 512 78 | Position = 512 79 | ShowSelRange = False 80 | TabOrder = 0 81 | TickMarks = tmBoth 82 | OnChange = TrackBarTypeChange 83 | end 84 | object TrackBarLevel: TTrackBar 85 | Left = 0 86 | Top = 126 87 | Width = 400 88 | Height = 35 89 | Anchors = [akLeft, akTop, akRight] 90 | LineSize = 256 91 | Max = 8192 92 | PageSize = 512 93 | Frequency = 512 94 | Position = 1536 95 | ShowSelRange = False 96 | TabOrder = 1 97 | TickMarks = tmBoth 98 | OnChange = TrackBarLevelChange 99 | end 100 | object cbxType: TComboBox 101 | Left = 0 102 | Top = 0 103 | Width = 400 104 | Height = 21 105 | Anchors = [akLeft, akTop, akRight] 106 | ItemIndex = 1 107 | TabOrder = 2 108 | Text = 'Light (0x200)' 109 | OnChange = cbxTypeChange 110 | Items.Strings = ( 111 | 'None (0x000)' 112 | 'Light (0x200)' 113 | 'Full (0x400)') 114 | end 115 | object cbxLevel: TComboBox 116 | Left = 0 117 | Top = 99 118 | Width = 400 119 | Height = 21 120 | Anchors = [akLeft, akTop, akRight] 121 | ItemIndex = 2 122 | TabOrder = 3 123 | Text = 'Antimalware (0x0600)' 124 | OnChange = cbxLevelChange 125 | Items.Strings = ( 126 | 'None (0x0000)' 127 | 'Authenticode (0x0400)' 128 | 'Antimalware (0x0600)' 129 | 'Store App (0x0800)' 130 | 'Windows (0x1000)' 131 | 'WinTcb (0x2000)') 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.UserProfiles.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.UserProfiles; 2 | 3 | { 4 | This module provides a frame for listing user profiles. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, 11 | Vcl.Dialogs, VirtualTrees, VirtualTreesEx, DevirtualizedTree, 12 | NtUiFrame.Search, NtUiCommon.Interfaces, NtUiBackend.UserProfiles, NtUiFrame; 13 | 14 | type 15 | TUserProfilesFrame = class(TFrame, ICanConsumeEscape, IObservesActivation, 16 | IHasDefaultCaption, IAllowsDefaultNodeAction, IHasModalResult, 17 | IHasModalResultObservation) 18 | published 19 | Tree: TDevirtualizedTree; 20 | SearchBox: TSearchFrame; 21 | private 22 | Backend: TTreeNodeInterfaceProvider; 23 | BackendRef: IUnknown; 24 | property BackendImpl: TTreeNodeInterfaceProvider read Backend implements IHasModalResult, IHasModalResultObservation, IAllowsDefaultNodeAction; 25 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 26 | function GetDefaultCaption: String; 27 | protected 28 | procedure Loaded; override; 29 | public 30 | procedure LoadAllUsers; 31 | end; 32 | 33 | implementation 34 | 35 | uses 36 | NtUtils, NtUtils.Profiles, NtUiCommon.Prototypes; 37 | 38 | {$R *.dfm} 39 | 40 | { TUserProfilesFrame } 41 | 42 | function TUserProfilesFrame.GetDefaultCaption; 43 | begin 44 | Result := 'User Profiles'; 45 | end; 46 | 47 | procedure TUserProfilesFrame.LoadAllUsers; 48 | var 49 | Providers: TArray; 50 | Provider: IProfileNode; 51 | Status: TNtxStatus; 52 | begin 53 | Status := UiLibEnumerateProfiles(Providers); 54 | Backend.SetStatus(Status); 55 | 56 | if not Status.IsSuccess then 57 | Exit; 58 | 59 | Backend.BeginUpdateAuto; 60 | Backend.ClearItems; 61 | 62 | for Provider in Providers do 63 | Backend.AddItem(Provider); 64 | end; 65 | 66 | procedure TUserProfilesFrame.Loaded; 67 | begin 68 | inherited; 69 | SearchBox.AttachToTree(Tree); 70 | Backend := TTreeNodeInterfaceProvider.Create(Tree, [teSelectionChange]); 71 | Backend.ModalResultFilter := IProfileNode; 72 | BackendRef := Backend; // Make an owning reference 73 | end; 74 | 75 | { Integration } 76 | 77 | function Initializer(AOwner: TComponent): TFrame; 78 | var 79 | Frame: TUserProfilesFrame absolute Result; 80 | begin 81 | Frame := TUserProfilesFrame.Create(AOwner); 82 | try 83 | Frame.LoadAllUsers; 84 | except 85 | Frame.Free; 86 | raise; 87 | end; 88 | end; 89 | 90 | procedure NtUiLibShowUserProfiles; 91 | begin 92 | if not Assigned(NtUiLibHostFrameShow) then 93 | raise ENotSupportedException.Create('Frame host not available'); 94 | 95 | NtUiLibHostFrameShow(Initializer); 96 | end; 97 | 98 | function NtUiLibSelectUserProfile(Owner: TComponent): TNtUiLibProfileInfo; 99 | var 100 | ProfileNode: IProfileNode; 101 | begin 102 | if not Assigned(NtUiLibHostFramePick) then 103 | raise ENotSupportedException.Create('Frame host not available'); 104 | 105 | Profilenode := NtUiLibHostFramePick(Owner, Initializer) as IProfileNode; 106 | Result := ProfileNode.Info; 107 | end; 108 | 109 | initialization 110 | NtUiCommon.Prototypes.NtUiLibShowUserProfiles := NtUiLibShowUserProfiles; 111 | NtUiCommon.Prototypes.NtUiLibSelectUserProfile := NtUiLibSelectUserProfile; 112 | end. 113 | -------------------------------------------------------------------------------- /Prototypes/UI.Prototypes.Privileges.dfm: -------------------------------------------------------------------------------- 1 | object FramePrivileges: TFramePrivileges 2 | Left = 0 3 | Top = 0 4 | Width = 446 5 | Height = 294 6 | TabOrder = 0 7 | object VST: TDevirtualizedTree 8 | Left = 0 9 | Top = 0 10 | Width = 446 11 | Height = 294 12 | Align = alClient 13 | ClipboardFormats.Strings = ( 14 | 'CSV' 15 | 'Plain text' 16 | 'Unicode text') 17 | Header.AutoSizeIndex = 0 18 | Header.DefaultHeight = 24 19 | Header.Height = 24 20 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 21 | TabOrder = 0 22 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 23 | TreeOptions.ExportMode = emSelected 24 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 25 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 26 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 27 | OnChecked = VSTChecked 28 | Touch.InteractiveGestures = [igPan, igPressAndTap] 29 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 30 | NoItemsText = 'No items to display' 31 | Columns = < 32 | item 33 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 34 | Position = 0 35 | Text = 'Friendly Name' 36 | Width = 150 37 | end 38 | item 39 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 40 | Position = 1 41 | Text = 'Name' 42 | Width = 140 43 | end 44 | item 45 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 46 | Position = 2 47 | Text = 'Value' 48 | end 49 | item 50 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 51 | Position = 3 52 | Text = 'State' 53 | Width = 100 54 | end 55 | item 56 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 57 | Position = 4 58 | Text = 'Description' 59 | Width = 200 60 | end 61 | item 62 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 63 | Position = 5 64 | Text = 'Required Integrity' 65 | Width = 105 66 | end> 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Hierarchy.dfm: -------------------------------------------------------------------------------- 1 | inherited SidHierarchyFrame: TSidHierarchyFrame 2 | Width = 640 3 | Height = 400 4 | Constraints.MinHeight = 120 5 | Constraints.MinWidth = 300 6 | object Tree: TDevirtualizedTree 7 | AlignWithMargins = True 8 | Left = 0 9 | Top = 24 10 | Width = 640 11 | Height = 376 12 | Margins.Left = 0 13 | Margins.Right = 0 14 | Margins.Bottom = 0 15 | Align = alClient 16 | ClipboardFormats.Strings = ( 17 | 'CSV' 18 | 'Plain text' 19 | 'Unicode text') 20 | Header.AutoSizeIndex = 0 21 | Header.DefaultHeight = 24 22 | Header.Height = 24 23 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 24 | TabOrder = 0 25 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 26 | TreeOptions.ExportMode = emSelected 27 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 28 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 29 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 30 | Touch.InteractiveGestures = [igPan, igPressAndTap] 31 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 32 | NoItemsText = 'Not initialized' 33 | Columns = < 34 | item 35 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 36 | Position = 0 37 | Text = 'SID' 38 | Width = 210 39 | end 40 | item 41 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 42 | Position = 1 43 | Text = 'Friendly Name' 44 | Width = 290 45 | end 46 | item 47 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 48 | Position = 2 49 | Text = 'SID Type' 50 | Width = 110 51 | end 52 | item 53 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 54 | Position = 3 55 | Text = 'Definition' 56 | Width = 440 57 | end> 58 | end 59 | inline SearchBox: TSearchFrame 60 | Left = 0 61 | Top = 0 62 | Width = 640 63 | Height = 21 64 | Align = alTop 65 | Constraints.MinHeight = 21 66 | Constraints.MinWidth = 240 67 | ParentShowHint = False 68 | ShowHint = True 69 | TabOrder = 1 70 | inherited Splitter: TSplitter 71 | Left = 474 72 | end 73 | inherited tbxSearchBox: TButtonedEditEx 74 | Width = 474 75 | end 76 | inherited cbxColumn: TComboBox 77 | Left = 480 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /Common/NtUiBackend.Sids.Abbreviations.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.Sids.Abbreviations; 2 | 3 | { 4 | This unit provides the logic for listing SDDL SID abbrevations. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | NtUtils, NtUiBackend.Sids; 11 | 12 | type 13 | ISidAbbreviationNode = interface (ISidNode) 14 | ['{0207E69D-423F-46DB-B67E-2F39F7D7033C}'] 15 | function GetSDDL: String; 16 | property SDDL: String read GetSddl; 17 | end; 18 | 19 | // Enumerate known SDDL SID abbreviations and create node for them 20 | function NtUiLibCollectSidAbbreviations( 21 | ): TArray; 22 | 23 | implementation 24 | 25 | uses 26 | NtUtils.Security.Sid, NtUtils.Lsa.Sid, DelphiUiLib.LiteReflection, 27 | DelphiUiLib.Strings, DevirtualizedTree.Provider, DevirtualizedTree; 28 | 29 | const 30 | colSddl = 0; 31 | colFriendlyName = 1; 32 | colSid = 2; 33 | colSidType = 3; 34 | colMax = 4; 35 | 36 | type 37 | TSidAbbreviationNode = class (TNodeProvider, ISidAbbreviationNode) 38 | private 39 | FSDDL: String; 40 | FSidName: TTranslatedName; 41 | public 42 | function GetSDDL: String; 43 | function GetSidName: TTranslatedName; 44 | procedure Initialize; override; 45 | constructor Create(const SDDL: String; const SidName: TTranslatedName); 46 | end; 47 | 48 | { TSidAbbreviationNode } 49 | 50 | constructor TSidAbbreviationNode.Create; 51 | begin 52 | inherited Create(colMax); 53 | FSDDL := SDDL; 54 | FSidName := SidName; 55 | end; 56 | 57 | function TSidAbbreviationNode.GetSDDL; 58 | begin 59 | Result := FSDDL; 60 | end; 61 | 62 | function TSidAbbreviationNode.GetSidName; 63 | begin 64 | Result := FSidName; 65 | end; 66 | 67 | procedure TSidAbbreviationNode.Initialize; 68 | begin 69 | inherited; 70 | 71 | FColumnText[colSddl] := FSDDL; 72 | FColumnText[colSid] := RtlxSidToStringNoError(FSidName.SID); 73 | 74 | if FSidName.IsValid then 75 | begin 76 | FColumnText[colSidType] := Rttix.Format(FSidName.SidType); 77 | FColumnText[colFriendlyName] := FSidName.FullName; 78 | end; 79 | 80 | FHint := BuildHint([ 81 | THintSection.New('SDDL', FColumnText[colSddl]), 82 | THintSection.New('Friendly Name', FColumnText[colFriendlyName]), 83 | THintSection.New('SID', FColumnText[colSid]), 84 | THintSection.New('SID Type', FColumnText[colSidType]) 85 | ]); 86 | 87 | if not FSidName.IsValid then 88 | FColumnText[colFriendlyName] := FSidName.FullName; 89 | end; 90 | 91 | function NtUiLibCollectSidAbbreviations; 92 | const 93 | ALPHABET_LENGTH = Ord('Z') - Ord('A') + 1; 94 | var 95 | i, Count: Integer; 96 | Names: TArray; 97 | SIDs: TArray; 98 | Lookup: TArray; 99 | begin 100 | SetLength(Names, ALPHABET_LENGTH * ALPHABET_LENGTH); 101 | SetLength(SIDs, Length(Names)); 102 | Count := 0; 103 | 104 | // Try converting each two-letter abbreviation to a SID 105 | for i := 0 to High(Names) do 106 | begin 107 | SetLength(Names[Count], 2); 108 | Names[Count][Low(String)] := Chr(Ord('A') + i div ALPHABET_LENGTH); 109 | Names[Count][Succ(Low(String))] := Chr(Ord('A') + i mod ALPHABET_LENGTH); 110 | 111 | if RtlxStringToSid(Names[Count], SIDs[Count]).IsSuccess then 112 | Inc(Count); 113 | end; 114 | 115 | SetLength(Result, Count); 116 | SetLength(SIDs, Count); 117 | 118 | // Translate SIDs in bulk 119 | LsaxLookupSids(SIDs, Lookup); 120 | 121 | // Create nodes 122 | for i := 0 to High(SIDs) do 123 | Result[i] := TSidAbbreviationNode.Create(Names[i], Lookup[i]); 124 | end; 125 | 126 | end. 127 | -------------------------------------------------------------------------------- /Common/NtUiBackend.HexView.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.HexView; 2 | 3 | { 4 | This module provides support for parsing and representing binary data as hex. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | NtUtils; 11 | 12 | // Parse a variable-length hexadecimal string 13 | function UiLibParseHexData( 14 | const HexString: String; 15 | out Data: IMemory 16 | ): Boolean; 17 | 18 | // Represent variable-length data as a hexadecimal string 19 | function UiLibRepresentHexData( 20 | const Data: IMemory 21 | ): String; 22 | 23 | implementation 24 | 25 | type 26 | TParsingState = ( 27 | psBetweenBytes, 28 | psInsideByte 29 | ); 30 | 31 | function UiLibParseHexData; 32 | var 33 | i: Integer; 34 | State: TParsingState; 35 | ByteCount: NativeUInt; 36 | DataCursor: PByte; 37 | SymbolShift: Word; 38 | Value: Byte; 39 | begin 40 | Result := False; 41 | ByteCount := 0; 42 | State := psBetweenBytes; 43 | 44 | for i := Low(HexString) to High(HexString) do 45 | begin 46 | // Determine symbol category 47 | case HexString[i] of 48 | '0'..'9', 'a'..'f', 'A'..'F': 49 | ; 50 | 51 | ' ', #9, #$D, #$A: 52 | if State = psInsideByte then 53 | Exit 54 | else 55 | Continue; 56 | else 57 | Exit; 58 | end; 59 | 60 | // Update the state 61 | case State of 62 | psBetweenBytes: 63 | State := psInsideByte; 64 | 65 | psInsideByte: 66 | begin 67 | State := psBetweenBytes; 68 | Inc(ByteCount); 69 | end; 70 | end; 71 | end; 72 | 73 | // Make sure the last byte is complete 74 | if State = psInsideByte then 75 | Exit; 76 | 77 | // Prepare the buffer for successful parsing 78 | Data := Auto.AllocateDynamic(ByteCount); 79 | DataCursor := Data.Data; 80 | Value := 0; 81 | 82 | for i := Low(HexString) to High(HexString) do 83 | begin 84 | // Read and interpret the symbol 85 | case HexString[i] of 86 | '0'..'9': SymbolShift := Ord('0'); 87 | 'a'..'f': SymbolShift := Ord('a') - $a; 88 | 'A'..'F': SymbolShift := Ord('A') - $A; 89 | else 90 | Continue; 91 | end; 92 | 93 | case State of 94 | psBetweenBytes: 95 | begin 96 | // The first half of the byte 97 | State := psInsideByte; 98 | Value := Byte(Ord(HexString[i]) - SymbolShift); 99 | end; 100 | 101 | psInsideByte: 102 | begin 103 | // The second half of the byte 104 | State := psBetweenBytes; 105 | Value := (Value shl 4) or Byte(Ord(HexString[i]) - SymbolShift); 106 | DataCursor^ := Value; 107 | Inc(DataCursor); 108 | end; 109 | end; 110 | end; 111 | 112 | Result := True; 113 | end; 114 | 115 | function UiLibRepresentHexData; 116 | const 117 | HEX_DIGITS: array [0..15] of WideChar = ('0', '1', '2', '3', '4', '5', '6', 118 | '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); 119 | var 120 | i: Integer; 121 | DataCursor: PByte; 122 | begin 123 | if not Assigned(Data) or (Data.Size = 0) then 124 | Exit(''); 125 | 126 | // Two characters per byte + padding in between 127 | SetLength(Result, (Data.Size * 3) - 1); 128 | DataCursor := Data.Data; 129 | 130 | for i := Low(Result) to High(Result) do 131 | begin 132 | case (i - Low(Result)) mod 3 of 133 | 0: Result[i] := HEX_DIGITS[DataCursor^ shr 4]; 134 | 1: Result[i] := HEX_DIGITS[DataCursor^ and $0F]; 135 | else 136 | Result[i] := ' '; 137 | Inc(DataCursor); 138 | end; 139 | end; 140 | end; 141 | 142 | end. 143 | -------------------------------------------------------------------------------- /Common/NtUiBackend.UserProfiles.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.UserProfiles; 2 | 3 | { 4 | This module provides logic for the user profile list dialog 5 | } 6 | 7 | interface 8 | 9 | uses 10 | DevirtualizedTree, NtUtils.Profiles, NtUtils, NtUiCommon.Prototypes; 11 | 12 | const 13 | colUserName = 0; 14 | colSID = 1; 15 | colPath = 2; 16 | colFullProfile = 3; 17 | colLoaded = 4; 18 | colMax = 5; 19 | 20 | type 21 | IProfileNode = interface (INodeProvider) 22 | ['{3FEAB0A3-69D5-45EA-AA34-F35FBDC60E57}'] 23 | function GetInfo: TNtUiLibProfileInfo; 24 | property Info: TNtUiLibProfileInfo read GetInfo; 25 | end; 26 | 27 | // Enumerate user profiles and convert them into node providers 28 | function UiLibEnumerateProfiles( 29 | out Providers: TArray 30 | ): TNtxStatus; 31 | 32 | implementation 33 | 34 | uses 35 | DelphiApi.Reflection, DevirtualizedTree.Provider, NtUtils.Security.Sid, 36 | DelphiUiLib.LiteReflection, DelphiUiLib.Strings, NtUiCommon.Colors, 37 | NtUtils.SysUtils; 38 | 39 | {$BOOLEVAL OFF} 40 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 41 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 42 | 43 | { TProfileNode } 44 | 45 | type 46 | TProfileNode = class (TNodeProvider, IProfileNode) 47 | private 48 | FUser: ISid; 49 | FListKey: IHandle; 50 | FIsLoaded: Boolean; 51 | protected 52 | procedure Initialize; override; 53 | public 54 | function GetInfo: TNtUiLibProfileInfo; 55 | constructor Create( 56 | const User: ISid 57 | ); 58 | end; 59 | 60 | constructor TProfileNode.Create; 61 | begin 62 | inherited Create(colMax); 63 | FUser := User; 64 | end; 65 | 66 | function TProfileNode.GetInfo; 67 | begin 68 | Result.User := FUser; 69 | Result.hxListKey := FListKey; 70 | end; 71 | 72 | procedure TProfileNode.Initialize; 73 | var 74 | FullProfile: LongBool; 75 | ProfilePath: String; 76 | UserReflection: TRttixFullReflection; 77 | begin 78 | inherited; 79 | 80 | RtlxOpenProfileListKey(FUser, FListKey); 81 | FIsLoaded := RtlxIsProfileLoaded(FUser); 82 | ProfilePath := ''; 83 | 84 | if Assigned(FListKey) then 85 | begin 86 | if not RtlxQueryProfileIsFullProfile(FListKey, FullProfile).IsSuccess then 87 | FullProfile := False; 88 | 89 | FColumnText[colFullProfile] := BooleanToString(FullProfile, bkYesNo); 90 | 91 | if FullProfile then 92 | SetColor(ColorSettings.clBackgroundUser) 93 | else 94 | SetColor(ColorSettings.clBackgroundSystem); 95 | 96 | if RtlxQueryProfilePath(FListKey, ProfilePath).IsSuccess then 97 | FColumnText[colPath] := ProfilePath; 98 | end; 99 | 100 | UserReflection := Rttix.FormatFull(FUser); 101 | FColumnText[colUserName] := UserReflection.Text; 102 | FColumnText[colSID] := RtlxSidToStringNoError(FUser); 103 | FColumnText[colLoaded] := BooleanToString(FIsLoaded, bkYesNo); 104 | 105 | FHint := RtlxJoinStrings([UserReflection.Hint, 106 | BuildHint([ 107 | THintSection.New('Profile Path', FColumnText[colPath]), 108 | THintSection.New('Loaded', FColumnText[colLoaded]) 109 | ])], #$D#$A); 110 | 111 | if not FIsLoaded then 112 | SetFontColor(ColorSettings.clForegroundInactive); 113 | end; 114 | 115 | { Functions } 116 | 117 | function UiLibEnumerateProfiles; 118 | var 119 | Sids: TArray; 120 | i: Integer; 121 | begin 122 | Result := RtlxEnumerateProfiles(Sids); 123 | 124 | if not Result.IsSuccess then 125 | Exit; 126 | 127 | SetLength(Providers, Length(Sids)); 128 | 129 | for i := 0 to High(Sids) do 130 | Providers[i] := TProfileNode.Create(Sids[i]); 131 | end; 132 | 133 | end. 134 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Logon.dfm: -------------------------------------------------------------------------------- 1 | inherited LogonSidsFrame: TLogonSidsFrame 2 | Width = 640 3 | Height = 400 4 | inline SearchBox: TSearchFrame 5 | Left = 0 6 | Top = 0 7 | Width = 640 8 | Height = 21 9 | Align = alTop 10 | Constraints.MinHeight = 21 11 | Constraints.MinWidth = 240 12 | ParentShowHint = False 13 | ShowHint = True 14 | TabOrder = 0 15 | inherited Splitter: TSplitter 16 | Left = 474 17 | end 18 | inherited tbxSearchBox: TButtonedEditEx 19 | Width = 474 20 | end 21 | inherited cbxColumn: TComboBox 22 | Left = 480 23 | end 24 | end 25 | object Tree: TDevirtualizedTree 26 | AlignWithMargins = True 27 | Left = 0 28 | Top = 24 29 | Width = 640 30 | Height = 376 31 | Margins.Left = 0 32 | Margins.Right = 0 33 | Margins.Bottom = 0 34 | Align = alClient 35 | ClipboardFormats.Strings = ( 36 | 'CSV' 37 | 'Plain text' 38 | 'Unicode text') 39 | Header.AutoSizeIndex = 0 40 | Header.DefaultHeight = 24 41 | Header.Height = 24 42 | Header.MainColumn = 1 43 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 44 | TabOrder = 1 45 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 46 | TreeOptions.ExportMode = emSelected 47 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 48 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 49 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 50 | Touch.InteractiveGestures = [igPan, igPressAndTap] 51 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 52 | NoItemsText = 'Not initialized' 53 | Columns = < 54 | item 55 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 56 | Position = 0 57 | Text = 'Logon ID' 58 | Width = 90 59 | end 60 | item 61 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 62 | Position = 1 63 | Text = 'Logon Type' 64 | Width = 80 65 | end 66 | item 67 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 68 | Position = 2 69 | Text = 'Owner SID Friendly Name' 70 | Width = 200 71 | end 72 | item 73 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 74 | Position = 3 75 | Text = 'Owner SID' 76 | Width = 240 77 | end 78 | item 79 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 80 | Position = 4 81 | Text = 'Owner SID Type' 82 | Width = 110 83 | end> 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Sam.dfm: -------------------------------------------------------------------------------- 1 | inherited SamSidsFrame: TSamSidsFrame 2 | Width = 640 3 | Height = 400 4 | Constraints.MinHeight = 120 5 | Constraints.MinWidth = 300 6 | object Tree: TDevirtualizedTree 7 | AlignWithMargins = True 8 | Left = 0 9 | Top = 24 10 | Width = 640 11 | Height = 376 12 | Margins.Left = 0 13 | Margins.Right = 0 14 | Margins.Bottom = 0 15 | Align = alClient 16 | Alignment = taCenter 17 | ClipboardFormats.Strings = ( 18 | 'CSV' 19 | 'Plain text' 20 | 'Unicode text') 21 | Header.AutoSizeIndex = 0 22 | Header.DefaultHeight = 24 23 | Header.Height = 24 24 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 25 | TabOrder = 0 26 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 27 | TreeOptions.ExportMode = emSelected 28 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 29 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 30 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 31 | Touch.InteractiveGestures = [igPan, igPressAndTap] 32 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 33 | NoItemsText = 'Not initialized' 34 | Columns = < 35 | item 36 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 37 | Position = 0 38 | Text = 'Name' 39 | Width = 210 40 | end 41 | item 42 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 43 | Position = 1 44 | Text = 'Account Type' 45 | Width = 90 46 | end 47 | item 48 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 49 | Position = 2 50 | Text = 'SID' 51 | Width = 300 52 | end 53 | item 54 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 55 | Position = 3 56 | Text = 'SID Full Name' 57 | Width = 300 58 | end 59 | item 60 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 61 | Position = 4 62 | Text = 'SID Type' 63 | Width = 90 64 | end> 65 | end 66 | inline SearchBox: TSearchFrame 67 | Left = 0 68 | Top = 0 69 | Width = 640 70 | Height = 21 71 | Align = alTop 72 | Constraints.MinHeight = 21 73 | Constraints.MinWidth = 240 74 | ParentShowHint = False 75 | ShowHint = True 76 | TabOrder = 1 77 | inherited Splitter: TSplitter 78 | Left = 474 79 | end 80 | inherited tbxSearchBox: TButtonedEditEx 81 | Width = 474 82 | end 83 | inherited cbxColumn: TComboBox 84 | Left = 480 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.WellKnown.dfm: -------------------------------------------------------------------------------- 1 | inherited WellKnownSidsFrame: TWellKnownSidsFrame 2 | Width = 640 3 | Height = 400 4 | Constraints.MinHeight = 120 5 | Constraints.MinWidth = 300 6 | object Tree: TDevirtualizedTree 7 | AlignWithMargins = True 8 | Left = 0 9 | Top = 24 10 | Width = 640 11 | Height = 376 12 | Margins.Left = 0 13 | Margins.Right = 0 14 | Margins.Bottom = 0 15 | Align = alClient 16 | ClipboardFormats.Strings = ( 17 | 'CSV' 18 | 'Plain text' 19 | 'Unicode text') 20 | Header.AutoSizeIndex = 0 21 | Header.DefaultHeight = 24 22 | Header.Height = 24 23 | Header.MainColumn = 1 24 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 25 | TabOrder = 0 26 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 27 | TreeOptions.ExportMode = emSelected 28 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 29 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 30 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 31 | Touch.InteractiveGestures = [igPan, igPressAndTap] 32 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 33 | NoItemsText = 'Unable to enumerate' 34 | Columns = < 35 | item 36 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 37 | Position = 0 38 | Text = 'Index' 39 | Width = 46 40 | end 41 | item 42 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 43 | Position = 1 44 | Text = 'Enum Name' 45 | Width = 200 46 | end 47 | item 48 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 49 | Position = 2 50 | Text = 'Friendly Name' 51 | Width = 250 52 | end 53 | item 54 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 55 | Position = 3 56 | Text = 'SID' 57 | Width = 110 58 | end 59 | item 60 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 61 | Position = 4 62 | Text = 'SID Type' 63 | Width = 110 64 | end> 65 | end 66 | inline SearchBox: TSearchFrame 67 | Left = 0 68 | Top = 0 69 | Width = 640 70 | Height = 21 71 | Align = alTop 72 | Constraints.MinHeight = 21 73 | Constraints.MinWidth = 240 74 | ParentShowHint = False 75 | ShowHint = True 76 | TabOrder = 1 77 | inherited Splitter: TSplitter 78 | Left = 474 79 | end 80 | inherited tbxSearchBox: TButtonedEditEx 81 | Width = 474 82 | end 83 | inherited cbxColumn: TComboBox 84 | Left = 480 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /Common/NtUiBackend.Sids.WellKnown.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.Sids.WellKnown; 2 | 3 | { 4 | This unit provides the logic for listing the Well-known SIDs enum. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Ntapi.WinBase, NtUtils, NtUiBackend.Sids; 11 | 12 | type 13 | IWellKnownSidNode = interface (ISidNode) 14 | ['{C2FAA457-A134-4671-AEF3-DCDDB523166D}'] 15 | function GetEnumValue: TWellKnownSidType; 16 | property EnumValue: TWellKnownSidType read GetEnumValue; 17 | end; 18 | 19 | // Create node entries for all well-known SIDs 20 | function NtUiLibMakeWellKnownSidNodes( 21 | ): TArray; 22 | 23 | implementation 24 | 25 | uses 26 | DevirtualizedTree.Provider, NtUtils.Security.Sid, NtUtils.Lsa.Sid, 27 | DelphiUiLib.Strings, DelphiUiLib.LiteReflection, System.SysUtils; 28 | 29 | const 30 | colIndex = 0; 31 | colEnumName = 1; 32 | colFriendlyName = 2; 33 | colSid = 3; 34 | colSidType = 4; 35 | colMax = 5; 36 | 37 | type 38 | TWellKnownSidNode = class (TNodeProvider, IWellKnownSidNode) 39 | private 40 | FEnumValue: TWellKnownSidType; 41 | FSidName: TTranslatedName; 42 | public 43 | function GetEnumValue: TWellKnownSidType; 44 | function GetSidName: TTranslatedName; 45 | procedure Initialize; override; 46 | constructor Create(Value: TWellKnownSidType; const SidName: TTranslatedName); 47 | end; 48 | 49 | { TWellKnownSidNode } 50 | 51 | constructor TWellKnownSidNode.Create; 52 | begin 53 | inherited Create(colMax); 54 | FEnumValue := Value; 55 | FSidName := SidName; 56 | end; 57 | 58 | function TWellKnownSidNode.GetEnumValue; 59 | begin 60 | Result := FEnumValue; 61 | end; 62 | 63 | function TWellKnownSidNode.GetSidName; 64 | begin 65 | Result := FSidName; 66 | end; 67 | 68 | procedure TWellKnownSidNode.Initialize; 69 | begin 70 | inherited; 71 | 72 | FColumnText[colIndex] := UiLibUIntToDec(Cardinal(FEnumValue)); 73 | FColumnText[colEnumName] := Rttix.Format(FEnumValue, RttixPreserveEnumCase); 74 | FColumnText[colSid] := RtlxSidToStringNoError(FSidName.SID); 75 | 76 | if FSidName.IsValid then 77 | begin 78 | FColumnText[colSidType] := Rttix.Format(FSidName.SidType); 79 | FColumnText[colFriendlyName] := FSidName.FullName; 80 | end; 81 | 82 | FHint := BuildHint([ 83 | THintSection.New('Enum Value', Format('%s (%d)', [ 84 | FColumnText[colEnumName], 85 | Integer(FEnumValue) 86 | ])), 87 | THintSection.New('Friendly Name', FColumnText[colFriendlyName]), 88 | THintSection.New('SID', FColumnText[colSid]), 89 | THintSection.New('SID Type', FColumnText[colSidType]) 90 | ]); 91 | end; 92 | 93 | function NtUiLibMakeWellKnownSidNodes; 94 | var 95 | Value: TWellKnownSidType; 96 | Values: TArray; 97 | Sids: TArray; 98 | SidNames: TArray; 99 | i: Integer; 100 | begin 101 | SetLength(Values, Succ(Ord(High(TWellKnownSidType)))); 102 | SetLength(Sids, Succ(Ord(High(TWellKnownSidType)))); 103 | i := 0; 104 | 105 | // Collect SIDs for all enum values 106 | for Value := Low(TWellKnownSidType) to High(TWellKnownSidType) do 107 | if SddlxCreateWellKnownSid(Value, Sids[i]).IsSuccess then 108 | begin 109 | Values[i] := Value; 110 | Inc(i); 111 | end; 112 | 113 | // Truncate failed entries if necessary 114 | if i <> Succ(Ord(High(TWellKnownSidType))) then 115 | begin 116 | SetLength(Values, i); 117 | SetLength(Sids, i); 118 | end; 119 | 120 | // Ask LSA to translate them in bulk 121 | LsaxLookupSids(Sids, SidNames); 122 | 123 | // Create tree nodes 124 | SetLength(Result, Length(SidNames)); 125 | 126 | for i := 0 to High(SidNames) do 127 | Result[i] := TWellKnownSidNode.Create(Values[i], SidNames[i]); 128 | end; 129 | 130 | end. 131 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.UserProfiles.dfm: -------------------------------------------------------------------------------- 1 | object UserProfilesFrame: TUserProfilesFrame 2 | Left = 0 3 | Top = 0 4 | Width = 700 5 | Height = 250 6 | Constraints.MinHeight = 180 7 | Constraints.MinWidth = 370 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | object Tree: TDevirtualizedTree 12 | Left = 0 13 | Top = 26 14 | Width = 700 15 | Height = 224 16 | Align = alClient 17 | ClipboardFormats.Strings = ( 18 | 'CSV' 19 | 'Plain text' 20 | 'Unicode text') 21 | Header.AutoSizeIndex = 0 22 | Header.DefaultHeight = 24 23 | Header.Height = 24 24 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 25 | TabOrder = 0 26 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 27 | TreeOptions.ExportMode = emSelected 28 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 29 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 30 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 31 | Touch.InteractiveGestures = [igPan, igPressAndTap] 32 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 33 | Columns = < 34 | item 35 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 36 | Position = 0 37 | Text = 'User Name' 38 | Width = 200 39 | end 40 | item 41 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 42 | Position = 1 43 | Text = 'SID' 44 | Width = 240 45 | end 46 | item 47 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 48 | Position = 2 49 | Text = 'Profile Path' 50 | Width = 240 51 | end 52 | item 53 | Alignment = taCenter 54 | CaptionAlignment = taCenter 55 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coUseCaptionAlignment, coEditable, coStyleColor] 56 | Position = 3 57 | Text = 'Full Profile' 58 | Width = 70 59 | end 60 | item 61 | Alignment = taCenter 62 | CaptionAlignment = taCenter 63 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coUseCaptionAlignment, coEditable, coStyleColor] 64 | Position = 4 65 | Text = 'Loaded' 66 | Width = 70 67 | end> 68 | end 69 | inline SearchBox: TSearchFrame 70 | AlignWithMargins = True 71 | Left = 0 72 | Top = 0 73 | Width = 700 74 | Height = 21 75 | Margins.Left = 0 76 | Margins.Top = 0 77 | Margins.Right = 0 78 | Margins.Bottom = 5 79 | Align = alTop 80 | Constraints.MinHeight = 21 81 | Constraints.MinWidth = 240 82 | TabOrder = 1 83 | inherited Splitter: TSplitter 84 | Left = 534 85 | end 86 | inherited tbxSearchBox: TButtonedEditEx 87 | Width = 534 88 | end 89 | inherited cbxColumn: TComboBox 90 | Left = 540 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sids.Capabilities.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sids.Capabilities; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 8 | VirtualTreesEx, DevirtualizedTree, NtUiFrame, NtUiFrame.Search, 9 | NtUiCommon.Interfaces; 10 | 11 | type 12 | TCapabilityListFrame = class(TFrame, ICanConsumeEscape, IObservesActivation, 13 | IHasDefaultCaption, IHasModalResult, IDelayedLoad) 14 | SearchBox: TSearchFrame; 15 | Tree: TDevirtualizedTree; 16 | private 17 | Backend: TTreeNodeInterfaceProvider; 18 | BackendRef: IUnknown; 19 | UseCheckboxes: Boolean; 20 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 21 | function GetDefaultCaption: String; 22 | function GetModalResult: IInterface; 23 | protected 24 | procedure Loaded; override; 25 | public 26 | procedure DelayedLoad; 27 | end; 28 | 29 | implementation 30 | 31 | uses 32 | NtUiBackend.Sids.Capabilities, NtUiCommon.Helpers, NtUiCommon.Prototypes, 33 | NtUtils, VirtualTrees.Types; 34 | 35 | {$R *.dfm} 36 | 37 | { TCapabilityListFrame } 38 | 39 | procedure TCapabilityListFrame.DelayedLoad; 40 | var 41 | NodeInfo: TCapabilityNodes; 42 | Category: TCapabilityCategory; 43 | i: Integer; 44 | begin 45 | NodeInfo := UiLibMakeCapabilityNodes; 46 | Backend.BeginUpdateAuto; 47 | Backend.ClearItems; 48 | Tree.NoItemsText := 'No items to display'; 49 | 50 | for Category := Low(TCapabilityCategory) to High(TCapabilityCategory) do 51 | begin 52 | Backend.AddItem(NodeInfo[Category].Group); 53 | 54 | for i := 0 to High(NodeInfo[Category].Items) do 55 | begin 56 | Backend.AddItem(NodeInfo[Category].Items[i], NodeInfo[Category].Group); 57 | 58 | if UseCheckboxes then 59 | Tree.CheckType[NodeInfo[Category].Items[i].Node] := ctCheckBox; 60 | end; 61 | end; 62 | end; 63 | 64 | function TCapabilityListFrame.GetDefaultCaption; 65 | begin 66 | Result := 'Capabilities'; 67 | end; 68 | 69 | function TCapabilityListFrame.GetModalResult; 70 | var 71 | Nodes: TArray; 72 | Provider: ICapabilityNode; 73 | Output: TArray; 74 | i, j: Integer; 75 | begin 76 | Nodes := Tree.CheckedNodes.ToArray; 77 | SetLength(Output, Length(Nodes)); 78 | 79 | j := 0; 80 | for i := 0 to High(Nodes) do 81 | if Nodes[i].TryGetProvider(ICapabilityNode, Provider) then 82 | begin 83 | Output[j].Name := Provider.Name; 84 | Output[j].AppSid := Provider.AppSid; 85 | Output[j].GroupSid := Provider.GroupSid; 86 | Inc(j); 87 | end; 88 | 89 | if j <> Length(Output) then 90 | SetLength(Output, j); 91 | 92 | Result := Auto.Copy(Output); 93 | end; 94 | 95 | procedure TCapabilityListFrame.Loaded; 96 | begin 97 | inherited; 98 | SearchBox.AttachToTree(Tree); 99 | Backend := TTreeNodeInterfaceProvider.Create(Tree, [teSelectionChange]); 100 | BackendRef := Backend; // Make an owning reference 101 | end; 102 | 103 | function Initializer(ShowCheckboxes: Boolean): TFrameInitializer; 104 | begin 105 | Result := function (AOwner: TComponent): TFrame 106 | var 107 | Frame: TCapabilityListFrame absolute Result; 108 | begin 109 | Frame := TCapabilityListFrame.Create(AOwner); 110 | Frame.UseCheckboxes := ShowCheckboxes; 111 | end; 112 | end; 113 | 114 | function NtUiLibSelectCapabilities( 115 | Owner: TComponent 116 | ): TArray; 117 | begin 118 | if not Assigned(NtUiLibHostFramePick) then 119 | raise ENotSupportedException.Create('Frame host not available'); 120 | 121 | Result := TArray((NtUiLibHostFramePick(Owner, 122 | Initializer(True)) as IMemory).Data^); 123 | end; 124 | 125 | initialization 126 | NtUiCommon.Prototypes.NtUiLibSelectCapabilities := NtUiLibSelectCapabilities; 127 | end. 128 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Prototypes.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Prototypes; 2 | 3 | { 4 | This unit provides entrypoints for common inspection/selection dialogs. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Ntapi.WinNt, Ntapi.ntseapi, Ntapi.WinUser, NtUtils, NtUtils.Profiles, 11 | NtUtils.Objects, NtUtils.Security.AppContainer, NtUtils.Security, 12 | NtUtils.Security.Acl, DevirtualizedTree, NtUiDialog.FrameHost, 13 | System.Classes, Vcl.Forms; 14 | 15 | type 16 | TFrameInitializer = NtUiDialog.FrameHost.TFrameInitializer; 17 | 18 | TSecurityAccessMaskLookup = reference to function ( 19 | Info: TSecurityInformation 20 | ): TAccessMask; 21 | 22 | var 23 | { Common: Frame Hosting } 24 | 25 | NtUiLibHostFrameShow: procedure ( 26 | Initializer: TFrameInitializer 27 | ); 28 | 29 | NtUiLibHostFramePick: function ( 30 | AOwner: TComponent; 31 | Initializer: TFrameInitializer 32 | ): IInterface; 33 | 34 | NtUiLibHostPages: function ( 35 | AOwner: TComponent; 36 | Pages: TArray; 37 | const DefaultCaption: String 38 | ): TFrame; 39 | 40 | { Bit Masks } 41 | 42 | NtUiLibShowBitMask: procedure ( 43 | const Value: UInt64; 44 | ATypeInfo: Pointer 45 | ); 46 | 47 | NtUiLibShowAccessMask: procedure ( 48 | const Value: TAccessMask; 49 | ATypeInfo: Pointer; 50 | const GenericMapping: TGenericMapping 51 | ); 52 | 53 | { User Profiles } 54 | 55 | type 56 | TNtUiLibProfileInfo = record 57 | User: ISid; 58 | hxListKey: IHandle; 59 | end; 60 | 61 | var 62 | NtUiLibShowUserProfiles: procedure; 63 | 64 | NtUiLibSelectUserProfile: function ( 65 | Owner: TComponent 66 | ): TNtUiLibProfileInfo; 67 | 68 | { AppContainer Profiles } 69 | 70 | NtUiLibShowAppContainer: procedure( 71 | const Info: TRtlxAppContainerInfo 72 | ); 73 | 74 | NtUiLibShowAppContainers: procedure( 75 | const User: ISid 76 | ); 77 | 78 | NtUiLibShowAppContainersAllUsers: procedure( 79 | [opt] const DefaultUser: ISid = nil 80 | ); 81 | 82 | NtUiLibSelectAppContainer: function ( 83 | Owner: TComponent; 84 | const User: ISid 85 | ): TRtlxAppContainerInfo; 86 | 87 | NtUiLibSelectAppContainerAllUsers: function ( 88 | Owner: TComponent; 89 | [opt] const DefaultUser: ISid = nil 90 | ): TRtlxAppContainerInfo; 91 | 92 | { ACE } 93 | 94 | NtUiLibCreateAce: function ( 95 | Owner: TComponent; 96 | AccessMaskType: Pointer; 97 | const GenericMapping: TGenericMapping; 98 | DefaultAceType: TAceType 99 | ): TAceData; 100 | 101 | NtUiLibEditAce: function ( 102 | Owner: TComponent; 103 | AccessMaskType: Pointer; 104 | const GenericMapping: TGenericMapping; 105 | const Ace: TAceData 106 | ): TAceData; 107 | 108 | { Security } 109 | 110 | type 111 | TNtUiLibSecurityContext = record 112 | HandleProvider: TObjectOpener; 113 | AccessMaskType: Pointer; // TypeInfo(...) 114 | GenericMapping: TGenericMapping; 115 | QueryFunction: TSecurityQueryFunction; 116 | SetFunction: TSecuritySetFunction; 117 | [opt] CustomQueryAccessLookup: TSecurityAccessMaskLookup; 118 | [opt] CustomSetAccessLookup: TSecurityAccessMaskLookup; 119 | end; 120 | 121 | var 122 | NtUiLibShowSecurity: procedure ( 123 | const Context: TNtUiLibSecurityContext 124 | ); 125 | 126 | { SIDs } 127 | 128 | NtUiLibSelectIntegrity: function ( 129 | Owner: TComponent; 130 | [opt] const DefaultSid: ISid = nil 131 | ): ISid; 132 | 133 | NtUiLibSelectTrust: function ( 134 | Owner: TComponent; 135 | [opt] const DefaultSid: ISid = nil 136 | ): ISid; 137 | 138 | NtUiLibSelectDsObject: function ( 139 | ParentWindow: THwnd 140 | ): String; 141 | 142 | type 143 | TNtUiLibCapability = record 144 | Name: String; 145 | AppSid: ISid; 146 | GroupSid: ISid; 147 | end; 148 | 149 | var 150 | NtUiLibSelectCapabilities: function ( 151 | Owner: TComponent 152 | ): TArray; 153 | 154 | implementation 155 | 156 | end. 157 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Ace.Condition.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Ace.Condition; 2 | 3 | { 4 | This module includes a control for selecting callback ACE conditions. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, NtUtils, 12 | NtUiFrame; 13 | 14 | type 15 | TAceConditionFrame = class(TBaseFrame) 16 | tbxCondition: TEdit; 17 | btnNormalize: TButton; 18 | procedure tbxConditionChange(Sender: TObject); 19 | procedure btnNormalizeClick(Sender: TObject); 20 | private 21 | FOnConditionChanged: TNotifyEvent; 22 | FCondition: IMemory; 23 | function GetCondition: IMemory; 24 | procedure SetCondition(const Value: IMemory); 25 | procedure NormalizeIconChanged(ImageList: TImageList; ImageIndex: Integer); 26 | protected 27 | procedure LoadedOnce; override; 28 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 29 | public 30 | function TryGetCondition([MayReturnNil] out Value: IMemory): TNtxStatus; 31 | function TrySetCondition([opt] const Value: IMemory): TNtxStatus; 32 | [MayReturnNil] property Condition: IMemory read GetCondition write SetCondition; 33 | property OnConditionChange: TNotifyEvent read FOnConditionChanged write FOnConditionChanged; 34 | end; 35 | 36 | implementation 37 | 38 | uses 39 | NtUiCommon.Colors, NtUtils.Security, Vcl.ImgList, Resources.Icon.Verify; 40 | 41 | {$R *.dfm} 42 | 43 | procedure TAceConditionFrame.btnNormalizeClick; 44 | begin 45 | // Do a round trip of parsing and representing 46 | SetCondition(GetCondition); 47 | end; 48 | 49 | procedure TAceConditionFrame.FrameEnabledChanged; 50 | begin 51 | inherited; 52 | tbxCondition.Enabled := Enabled; 53 | btnNormalize.Enabled := Enabled; 54 | end; 55 | 56 | function TAceConditionFrame.GetCondition; 57 | begin 58 | TryGetCondition(Result).RaiseOnError; 59 | end; 60 | 61 | procedure TAceConditionFrame.LoadedOnce; 62 | begin 63 | inherited; 64 | RegisterResourceIcon(RESOURCES_ICON_VERIFY, NormalizeIconChanged); 65 | end; 66 | 67 | procedure TAceConditionFrame.NormalizeIconChanged; 68 | begin 69 | btnNormalize.Images := ImageList; 70 | btnNormalize.ImageIndex := ImageIndex; 71 | end; 72 | 73 | procedure TAceConditionFrame.SetCondition; 74 | begin 75 | TrySetCondition(Value).RaiseOnError; 76 | end; 77 | 78 | procedure TAceConditionFrame.tbxConditionChange; 79 | begin 80 | // Refresh the cached condition 81 | FCondition := nil; 82 | TryGetCondition(FCondition); 83 | 84 | if Assigned(FOnConditionChanged) then 85 | FOnConditionChanged(Self); 86 | end; 87 | 88 | function TAceConditionFrame.TryGetCondition; 89 | begin 90 | // Use the cache when available 91 | if Assigned(FCondition) then 92 | begin 93 | Value := FCondition; 94 | Exit(NtxSuccess); 95 | end; 96 | 97 | // Parse the condition and cache the result 98 | Result := AdvxAceConditionFromSddl(tbxCondition.Text, FCondition); 99 | 100 | if Result.IsSuccess then 101 | begin 102 | Value := FCondition; 103 | tbxCondition.Color := clWindow; 104 | end 105 | else 106 | begin 107 | FCondition := nil; 108 | tbxCondition.Color := ColorSettings.clBackgroundError; 109 | end; 110 | end; 111 | 112 | function TAceConditionFrame.TrySetCondition; 113 | var 114 | SDDL: String; 115 | OnChangeReverter: IDeferredOperation; 116 | begin 117 | FCondition := nil; 118 | SDDL := ''; 119 | 120 | if Assigned(Value) then 121 | begin 122 | // Convert the condition to string 123 | Result := AdvxAceConditionToSddl(Value, SDDL); 124 | 125 | if Result.IsSuccess then 126 | FCondition := Value; 127 | end 128 | else 129 | Result := NtxSuccess; 130 | 131 | // Suppress recursive invocation 132 | tbxCondition.OnChange := nil; 133 | OnChangeReverter := Auto.Defer( 134 | procedure 135 | begin 136 | tbxCondition.OnChange := tbxConditionChange; 137 | end 138 | ); 139 | 140 | // Update the text 141 | tbxCondition.Text := SDDL; 142 | tbxCondition.Color := clWindow; 143 | end; 144 | 145 | end. 146 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.List.dfm: -------------------------------------------------------------------------------- 1 | object AppContainerListFrame: TAppContainerListFrame 2 | Left = 0 3 | Top = 0 4 | Width = 600 5 | Height = 407 6 | Constraints.MinHeight = 150 7 | Constraints.MinWidth = 300 8 | ParentShowHint = False 9 | ShowHint = True 10 | TabOrder = 0 11 | inline SearchBox: TSearchFrame 12 | Left = 0 13 | Top = 0 14 | Width = 600 15 | Height = 21 16 | Align = alTop 17 | Constraints.MinHeight = 21 18 | Constraints.MinWidth = 240 19 | TabOrder = 1 20 | inherited Splitter: TSplitter 21 | Left = 434 22 | end 23 | inherited tbxSearchBox: TButtonedEditEx 24 | Width = 434 25 | end 26 | inherited cbxColumn: TComboBox 27 | Left = 440 28 | end 29 | end 30 | object Tree: TDevirtualizedTree 31 | AlignWithMargins = True 32 | Left = 0 33 | Top = 26 34 | Width = 600 35 | Height = 381 36 | Margins.Left = 0 37 | Margins.Top = 5 38 | Margins.Right = 0 39 | Margins.Bottom = 0 40 | Align = alClient 41 | ClipboardFormats.Strings = ( 42 | 'CSV' 43 | 'Plain text' 44 | 'Unicode text') 45 | Header.AutoSizeIndex = 0 46 | Header.DefaultHeight = 24 47 | Header.Height = 24 48 | Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoRestrictDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoHeaderClickAutoSort, hoAutoColumnPopupMenu, hoAutoResizeInclCaption] 49 | TabOrder = 0 50 | TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] 51 | TreeOptions.ExportMode = emSelected 52 | TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] 53 | TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] 54 | TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] 55 | OnNodeDblClick = TreeNodeDblClick 56 | Touch.InteractiveGestures = [igPan, igPressAndTap] 57 | Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] 58 | NoItemsText = 'No items to display' 59 | Columns = < 60 | item 61 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 62 | Position = 0 63 | Text = 'Friendly Name' 64 | Width = 260 65 | end 66 | item 67 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 68 | Position = 1 69 | Text = 'Display Name' 70 | Width = 340 71 | end 72 | item 73 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 74 | Position = 2 75 | Text = 'Moniker' 76 | Width = 220 77 | end 78 | item 79 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus, coEditable, coStyleColor] 80 | Position = 3 81 | Text = 'Package' 82 | Width = 80 83 | end 84 | item 85 | Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coVisible, coAutoSpring, coSmartResize, coAllowFocus, coDisableAnimatedResize, coEditable, coStyleColor] 86 | Position = 4 87 | Text = 'SID' 88 | Width = 400 89 | end> 90 | end 91 | object PopupMenu: TPopupMenu 92 | Left = 72 93 | Top = 112 94 | object cmInspect: TMenuItem 95 | Caption = 'Inspect...' 96 | Default = True 97 | ShortCut = 13 98 | OnClick = cmInspectClick 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.ListAllUsers.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.AppContainer.ListAllUsers; 2 | 3 | { 4 | This module provides a frame for showing AppContainer profiles for all users. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, 11 | Vcl.Dialogs, Vcl.StdCtrls, NtUtils, NtUiFrame.AppContainer.List, 12 | NtUiCommon.Interfaces; 13 | 14 | type 15 | TAppContainerListAllUsersFrame = class (TFrame, ICanConsumeEscape, 16 | IObservesActivation, IHasDefaultCaption, IAllowsDefaultNodeAction, 17 | IHasModalResult, IHasModalResultObservation) 18 | published 19 | lblUsers: TLabel; 20 | tbxUser: TEdit; 21 | btnSelectUser: TButton; 22 | AppContainersFrame: TAppContainerListFrame; 23 | procedure btnSelectUserClick(Sender: TObject); 24 | private 25 | FUser: ISid; 26 | function GetCanConsumeEscapeImpl: ICanConsumeEscape; 27 | function GetNodeDefaultActionImpl: IAllowsDefaultNodeAction; 28 | function GetModalResultObservation: IHasModalResultObservation; 29 | function GetObservesActivationImpl: IObservesActivation; 30 | property CanConsumeEscapeImpl: ICanConsumeEscape read GetCanConsumeEscapeImpl implements ICanConsumeEscape; 31 | property ObservesActivationImpl: IObservesActivation read GetObservesActivationImpl implements IObservesActivation; 32 | property NodeDefaultActionImpl: IAllowsDefaultNodeAction read GetNodeDefaultActionImpl implements IAllowsDefaultNodeAction; 33 | property ModalResultObservationImpl: IHasModalResultObservation read GetModalResultObservation implements IHasModalResult, IHasModalResultObservation; 34 | property Impl: TAppContainerListFrame read AppContainersFrame implements IHasDefaultCaption; 35 | public 36 | procedure LoadForUser([opt] const SelectedUser: ISid); 37 | end; 38 | 39 | implementation 40 | 41 | uses 42 | DelphiUiLib.LiteReflection, NtUiBackend.AppContainers, NtUiCommon.Prototypes; 43 | 44 | {$BOOLEVAL OFF} 45 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 46 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 47 | 48 | {$R *.dfm} 49 | 50 | procedure TAppContainerListAllUsersFrame.btnSelectUserClick; 51 | begin 52 | if Assigned(NtUiLibSelectUserProfile) then 53 | LoadForUser(NtUiLibSelectUserProfile(Self).User); 54 | end; 55 | 56 | function TAppContainerListAllUsersFrame.GetCanConsumeEscapeImpl; 57 | begin 58 | Result := AppContainersFrame; 59 | end; 60 | 61 | function TAppContainerListAllUsersFrame.GetModalResultObservation; 62 | begin 63 | Result := AppContainersFrame; 64 | end; 65 | 66 | function TAppContainerListAllUsersFrame.GetNodeDefaultActionImpl; 67 | begin 68 | Result := AppContainersFrame; 69 | end; 70 | 71 | function TAppContainerListAllUsersFrame.GetObservesActivationImpl; 72 | begin 73 | Result := AppContainersFrame; 74 | end; 75 | 76 | procedure TAppContainerListAllUsersFrame.LoadForUser; 77 | var 78 | UserReflection: TRttixFullReflection; 79 | begin 80 | if not Assigned(SelectedUser) then 81 | FUser := UiLibGetDefaultUser 82 | else 83 | FUser := SelectedUser; 84 | 85 | UserReflection := Rttix.FormatFull(FUser); 86 | tbxUser.Text := UserReflection.Text; 87 | tbxUser.Hint := UserReflection.Hint; 88 | AppContainersFrame.LoadForUser(SelectedUser); 89 | end; 90 | 91 | { Integration } 92 | 93 | function Initializer([opt] const DefaultUser: ISid): TFrameInitializer; 94 | begin 95 | Result := function (AOwner: TComponent): TFrame 96 | var 97 | Frame: TAppContainerListAllUsersFrame absolute Result; 98 | begin 99 | Frame := TAppContainerListAllUsersFrame.Create(AOwner); 100 | try 101 | Frame.LoadForUser(DefaultUser); 102 | except 103 | Frame.Free; 104 | raise; 105 | end; 106 | end; 107 | end; 108 | 109 | procedure NtUiLibShowAppContainersAllUsers( 110 | const User: ISid 111 | ); 112 | begin 113 | if not Assigned(NtUiLibHostFrameShow) then 114 | raise ENotSupportedException.Create('Frame host not available'); 115 | 116 | NtUiLibHostFrameShow(Initializer(User)); 117 | end; 118 | 119 | function NtUiLibSelectAppContainerAllUsers( 120 | Owner: TComponent; 121 | [opt] const DefaultUser: ISid 122 | ): TRtlxAppContainerInfo; 123 | var 124 | ProfileNode: IAppContainerNode; 125 | begin 126 | if not Assigned(NtUiLibHostFramePick) then 127 | raise ENotSupportedException.Create('Frame host not available'); 128 | 129 | ProfileNode := NtUiLibHostFramePick(Owner, 130 | Initializer(DefaultUser)) as IAppContainerNode; 131 | 132 | Result := ProfileNode.Info; 133 | end; 134 | 135 | initialization 136 | NtUiCommon.Prototypes.NtUiLibShowAppContainersAllUsers := 137 | NtUiLibShowAppContainersAllUsers; 138 | NtUiCommon.Prototypes.NtUiLibSelectAppContainerAllUsers := 139 | NtUiLibSelectAppContainerAllUsers; 140 | end. 141 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.AppContainer.List.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.AppContainer.List; 2 | 3 | { 4 | This module provides a frame for showing a list of AppContainer profiles. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Vcl.Controls, System.Classes, Vcl.Forms, VirtualTrees, VirtualTreesEx, 11 | DevirtualizedTree, NtUiFrame.Search, NtUtils, NtUiCommon.Interfaces, 12 | NtUiBackend.AppContainers, Vcl.Menus, NtUiFrame; 13 | 14 | type 15 | TAppContainerListFrame = class (TFrame, ICanConsumeEscape, 16 | IObservesActivation, IHasDefaultCaption, IAllowsDefaultNodeAction, 17 | IHasModalResult, IHasModalResultObservation) 18 | PopupMenu: TPopupMenu; 19 | cmInspect: TMenuItem; 20 | procedure cmInspectClick(Sender: TObject); 21 | procedure TreeNodeDblClick(Sender: TBaseVirtualTree; 22 | const HitInfo: THitInfo); 23 | published 24 | SearchBox: TSearchFrame; 25 | Tree: TDevirtualizedTree; 26 | procedure FrameMainActionSet(Sender: TObject); 27 | private 28 | Backend: TTreeNodeInterfaceProvider; 29 | BackendRef: IUnknown; 30 | property BackendImpl: TTreeNodeInterfaceProvider read Backend implements IHasModalResult, IHasModalResultObservation, IAllowsDefaultNodeAction; 31 | property SearchImpl: TSearchFrame read SearchBox implements ICanConsumeEscape, IObservesActivation; 32 | function GetDefaultCaption: String; 33 | protected 34 | procedure Loaded; override; 35 | public 36 | procedure LoadForUser(const User: ISid); 37 | end; 38 | 39 | implementation 40 | 41 | uses 42 | NtUtils.Errors, NtUiCommon.Prototypes, System.SysUtils, Winapi.Windows; 43 | 44 | {$BOOLEVAL OFF} 45 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 46 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 47 | 48 | {$R *.dfm} 49 | 50 | { TAppContainersFrame } 51 | 52 | procedure TAppContainerListFrame.cmInspectClick(Sender: TObject); 53 | var 54 | NodeProvider: INodeProvider; 55 | AppContainerNode: IAppContainerNode; 56 | begin 57 | if not Assigned(NtUiLibShowAppContainer) then 58 | Exit; 59 | 60 | NodeProvider := Backend.FocusedNode; 61 | 62 | if Assigned(NodeProvider) and NodeProvider.QueryInterface(IAppContainerNode, 63 | AppContainerNode).IsSuccess then 64 | NtUiLibShowAppContainer(AppContainerNode.Info); 65 | end; 66 | 67 | procedure TAppContainerListFrame.FrameMainActionSet; 68 | begin 69 | // Demote the inspect menu from the default Enter to Ctrl+Enter 70 | cmInspect.ShortCut := scCtrl or VK_RETURN; 71 | cmInspect.Default := False; 72 | Tree.RefreshPopupMenuShortcuts; 73 | end; 74 | 75 | function TAppContainerListFrame.GetDefaultCaption; 76 | begin 77 | Result := 'AppContainer Profiles' 78 | end; 79 | 80 | procedure TAppContainerListFrame.Loaded; 81 | begin 82 | inherited; 83 | SearchBox.AttachToTree(Tree); 84 | Backend := TTreeNodeInterfaceProvider.Create(Tree, [teSelectionChange]); 85 | BackendRef := Backend; // Make an owning reference 86 | 87 | if Assigned(NtUiLibShowAppContainer) then 88 | begin 89 | Tree.PopupMenuEx := PopupMenu; 90 | Backend.OnMainActionSet := FrameMainActionSet; 91 | end; 92 | end; 93 | 94 | procedure TAppContainerListFrame.LoadForUser; 95 | var 96 | Parents, Children: TArray; 97 | Parent, Child: IAppContainerNode; 98 | Status: TNtxStatus; 99 | begin 100 | Backend.BeginUpdateAuto; 101 | Backend.ClearItems; 102 | 103 | // Enumerate parent AppContainers 104 | Status := UiLibEnumerateAppContainers(Parents, User); 105 | Backend.SetStatus(Status); 106 | 107 | if not Status.IsSuccess then 108 | Exit; 109 | 110 | for Parent in Parents do 111 | begin 112 | Backend.AddItem(Parent); 113 | 114 | // Enumerate child AppContainers 115 | if UiLibEnumerateAppContainers(Children, User, Parent.Info.Sid).IsSuccess then 116 | for Child in Children do 117 | Backend.AddItem(Child, Parent); 118 | end; 119 | end; 120 | 121 | procedure TAppContainerListFrame.TreeNodeDblClick; 122 | begin 123 | if cmInspect.Default then 124 | cmInspectClick(Sender); 125 | end; 126 | 127 | { Integration } 128 | 129 | function Initializer(const User: ISid): TFrameInitializer; 130 | begin 131 | Result := function (AOwner: TComponent): TFrame 132 | var 133 | Frame: TAppContainerListFrame absolute Result; 134 | begin 135 | Frame := TAppContainerListFrame.Create(AOwner); 136 | try 137 | Frame.LoadForUser(User); 138 | except 139 | Frame.Free; 140 | raise; 141 | end; 142 | end; 143 | end; 144 | 145 | procedure NtUiLibShowAppContainers( 146 | const User: ISid 147 | ); 148 | begin 149 | if not Assigned(NtUiLibHostFrameShow) then 150 | raise ENotSupportedException.Create('Frame host not available'); 151 | 152 | NtUiLibHostFrameShow(Initializer(User)); 153 | end; 154 | 155 | function NtUiLibSelectAppContainer( 156 | Owner: TComponent; 157 | const User: ISid 158 | ): TRtlxAppContainerInfo; 159 | var 160 | ProfileNode: IAppContainerNode; 161 | begin 162 | if not Assigned(NtUiLibHostFramePick) then 163 | raise ENotSupportedException.Create('Frame host not available'); 164 | 165 | Profilenode := NtUiLibHostFramePick(Owner, Initializer(User)) as IAppContainerNode; 166 | Result := ProfileNode.Info; 167 | end; 168 | 169 | initialization 170 | NtUiCommon.Prototypes.NtUiLibShowAppContainers := NtUiLibShowAppContainers; 171 | NtUiCommon.Prototypes.NtUiLibSelectAppContainer := NtUiLibSelectAppContainer; 172 | end. 173 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Sid.Integrity.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Sid.Integrity; 2 | 3 | { 4 | This module includes a control for selecting integrity levels. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, 12 | Vcl.StdCtrls, NtUiCommon.Interfaces, Ntapi.WinNt, Ntapi.ntseapi, NtUtils; 13 | 14 | type 15 | TFrameIntegrity = class(TFrame, ICanConsumeEscape, IHasDefaultCaption, 16 | IHasModalResult) 17 | ComboBox: TComboBox; 18 | lblUntrusted: TLabel; 19 | lblSystem: TLabel; 20 | lblMedium: TLabel; 21 | lblHigh: TLabel; 22 | lblLow: TLabel; 23 | TrackBar: TTrackBar; 24 | procedure ComboBoxChange(Sender: TObject); 25 | procedure TrackBarChange(Sender: TObject); 26 | private 27 | FValue: TIntegrityRid; 28 | procedure UpdateComboBoxValue; 29 | procedure UpdateTrackBarValue; 30 | procedure SetValue(const Value: TIntegrityRid); 31 | function GetSid: ISid; 32 | procedure SetSid(const Value: ISid); 33 | protected 34 | procedure Loaded; override; 35 | function ConsumesEscape: Boolean; 36 | function GetDefaultCaption: String; 37 | function GetModalResult: IInterface; 38 | public 39 | property Value: TIntegrityRid read FValue write SetValue; 40 | property Sid: ISid read GetSid write SetSid; 41 | end; 42 | 43 | implementation 44 | 45 | uses 46 | DelphiUiLib.Strings, NtUtils.Security.Sid, NtUiCommon.Prototypes; 47 | 48 | {$R *.dfm} 49 | 50 | procedure TFrameIntegrity.ComboBoxChange; 51 | begin 52 | case ComboBox.ItemIndex of 53 | 0: FValue := SECURITY_MANDATORY_UNTRUSTED_RID; 54 | 1: FValue := SECURITY_MANDATORY_LOW_RID; 55 | 2: FValue := SECURITY_MANDATORY_MEDIUM_RID; 56 | 3: FValue := SECURITY_MANDATORY_MEDIUM_PLUS_RID; 57 | 4: FValue := SECURITY_MANDATORY_HIGH_RID; 58 | 5: FValue := SECURITY_MANDATORY_SYSTEM_RID; 59 | 6: FValue := SECURITY_MANDATORY_PROTECTED_PROCESS_RID; 60 | else 61 | if not UiLibStringToUInt(ComboBox.Text, Cardinal(FValue)) then 62 | Exit; 63 | end; 64 | 65 | UpdateTrackBarValue; 66 | end; 67 | 68 | function TFrameIntegrity.ConsumesEscape; 69 | begin 70 | Result := ComboBox.DroppedDown; 71 | end; 72 | 73 | function TFrameIntegrity.GetDefaultCaption; 74 | begin 75 | Result := 'Integrity Level'; 76 | end; 77 | 78 | function TFrameIntegrity.GetModalResult; 79 | begin 80 | Result := GetSid; 81 | end; 82 | 83 | function TFrameIntegrity.GetSid; 84 | begin 85 | Result := RtlxMakeSid(SECURITY_MANDATORY_LABEL_AUTHORITY, [FValue]); 86 | end; 87 | 88 | procedure TFrameIntegrity.Loaded; 89 | begin 90 | inherited; 91 | FValue := SECURITY_MANDATORY_MEDIUM_RID; 92 | end; 93 | 94 | procedure TFrameIntegrity.SetSid; 95 | begin 96 | if Assigned(Value) and (RtlxIdentifierAuthoritySid(Value) = 97 | SECURITY_MANDATORY_LABEL_AUTHORITY) then 98 | SetValue(RtlxRidSid(Value)); 99 | end; 100 | 101 | procedure TFrameIntegrity.SetValue; 102 | begin 103 | FValue := Value; 104 | UpdateComboBoxValue; 105 | UpdateTrackBarValue; 106 | end; 107 | 108 | procedure TFrameIntegrity.TrackBarChange; 109 | begin 110 | FValue := TrackBar.Position; 111 | 112 | // Make known values slightly sticky 113 | if $800 - Abs(Integer(FValue and $FFF) - $800) < $1C000 / TrackBar.Width then 114 | FValue := Round(FValue / $1000) * $1000; 115 | 116 | UpdateTrackBarValue; 117 | UpdateComboBoxValue; 118 | end; 119 | 120 | procedure TFrameIntegrity.UpdateComboBoxValue; 121 | var 122 | OnChangeReverter: IDeferredOperation; 123 | begin 124 | ComboBox.OnChange := nil; 125 | OnChangeReverter := Auto.Defer( 126 | procedure 127 | begin 128 | ComboBox.OnChange := ComboBoxChange; 129 | end 130 | ); 131 | 132 | ComboBox.ItemIndex := -1; 133 | case FValue of 134 | SECURITY_MANDATORY_UNTRUSTED_RID: ComboBox.ItemIndex := 0; 135 | SECURITY_MANDATORY_LOW_RID: ComboBox.ItemIndex := 1; 136 | SECURITY_MANDATORY_MEDIUM_RID: ComboBox.ItemIndex := 2; 137 | SECURITY_MANDATORY_MEDIUM_PLUS_RID: ComboBox.ItemIndex := 3; 138 | SECURITY_MANDATORY_HIGH_RID: ComboBox.ItemIndex := 4; 139 | SECURITY_MANDATORY_SYSTEM_RID: ComboBox.ItemIndex := 5; 140 | SECURITY_MANDATORY_PROTECTED_PROCESS_RID: ComboBox.ItemIndex := 6; 141 | else 142 | ComboBox.Text := UiLibUIntToHex(FValue, 4); 143 | end; 144 | end; 145 | 146 | procedure TFrameIntegrity.UpdateTrackBarValue; 147 | var 148 | OnChangeReverter: IDeferredOperation; 149 | begin 150 | TrackBar.OnChange := nil; 151 | OnChangeReverter := Auto.Defer( 152 | procedure 153 | begin 154 | TrackBar.OnChange := TrackBarChange; 155 | end 156 | ); 157 | 158 | TrackBar.Position := FValue; 159 | end; 160 | 161 | { Integration } 162 | 163 | function NtUiLibSelectIntegrity( 164 | Owner: TComponent; 165 | [opt] const DefaultSid: ISid = nil 166 | ): ISid; 167 | var 168 | Selection: IInterface; 169 | begin 170 | if not Assigned(NtUiLibHostFramePick) then 171 | raise ENotSupportedException.Create('Frame host not available'); 172 | 173 | Selection := NtUiLibHostFramePick(Owner, 174 | function (AOwner: TComponent): TFrame 175 | var 176 | Frame: TFrameIntegrity absolute Result; 177 | begin 178 | Frame := TFrameIntegrity.Create(AOwner); 179 | try 180 | Frame.Sid := DefaultSid; 181 | except 182 | Frame.Free; 183 | raise; 184 | end; 185 | end 186 | ); 187 | 188 | Result := Selection as ISid; 189 | end; 190 | 191 | initialization 192 | NtUiCommon.Prototypes.NtUiLibSelectIntegrity := NtUiLibSelectIntegrity; 193 | end. 194 | -------------------------------------------------------------------------------- /Common/NtUiCommon.Helpers.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.Helpers; 2 | 3 | interface 4 | 5 | uses 6 | VirtualTrees, VirtualTreesEx, Vcl.StdCtrls, Vcl.Menus, System.Classes, 7 | NtUtils, DelphiUtils.Arrays; 8 | 9 | type 10 | TCollectionHelper = class helper for TCollection 11 | function BeginUpdateAuto: IAutoReleasable; 12 | end; 13 | 14 | // Automatic operations on virtual tree views 15 | TVirtualTreeAutoHelper = class helper for TBaseVirtualTree 16 | function BeginUpdateAuto: IAutoReleasable; 17 | function BackupSelectionAuto(Comparer: TMapRoutine>): IDeferredOperation; 18 | end; 19 | 20 | TComboBoxHelper = class helper for TComboBox 21 | // Update the list of items preserving selection 22 | procedure UpdateItems(const NewItems: TArray; FallbackIndex: Integer = -1); 23 | end; 24 | 25 | // Change of checkbox state that does not issue OnClick event 26 | TCheckBoxHack = class helper for TCheckBox 27 | procedure SetStateEx(Value: TCheckBoxState); 28 | procedure SetCheckedEx(Value: Boolean); 29 | end; 30 | 31 | // A type that captures shortcuts of items in a popup menu 32 | TMenuShortCut = record 33 | Menu: TMenuItem; 34 | ShiftState: TShiftState; 35 | Key: Word; 36 | constructor Create(Item: TMenuItem); 37 | class function Collect(Item: TMenuItem): TArray; static; 38 | end; 39 | 40 | implementation 41 | 42 | { TCollectionHelper } 43 | 44 | function TCollectionHelper.BeginUpdateAuto; 45 | begin 46 | BeginUpdate; 47 | 48 | Result := Auto.Defer( 49 | procedure 50 | begin 51 | EndUpdate; 52 | end 53 | ); 54 | end; 55 | 56 | { TVirtualTreeAutoHelper } 57 | 58 | function TVirtualTreeAutoHelper.BackupSelectionAuto; 59 | var 60 | SelectionConditions: TArray>; 61 | FocusCondition: TCondition; 62 | begin 63 | // For each selected node, capture necessary data for later comparison 64 | SelectionConditions := TArray.Map>( 65 | SelectedNodes.ToArray, Comparer); 66 | 67 | // Same for the focused node 68 | if Assigned(FocusedNode) then 69 | FocusCondition := Comparer(FocusedNode) 70 | else 71 | FocusCondition := nil; 72 | 73 | // Restore selection afterward 74 | Result := Auto.Defer( 75 | procedure 76 | var 77 | SelectionCondition: TCondition; 78 | Node: PVirtualNode; 79 | UpdateReleaser: IAutoReleasable; 80 | begin 81 | UpdateReleaser := BeginUpdateAuto; 82 | 83 | // Check if each new node matches any conditions for selection 84 | for Node in Nodes do 85 | begin 86 | for SelectionCondition in SelectionConditions do 87 | if Assigned(SelectionCondition) and SelectionCondition(Node) then 88 | begin 89 | Selected[Node] := True; 90 | Break; 91 | end; 92 | 93 | // Same for the focus 94 | if Assigned(FocusCondition) and FocusCondition(Node) then 95 | FocusedNode := Node; 96 | end; 97 | 98 | // Re-apply sorting 99 | Sort(RootNode, Header.SortColumn, Header.SortDirection); 100 | end 101 | ); 102 | end; 103 | 104 | function TVirtualTreeAutoHelper.BeginUpdateAuto; 105 | begin 106 | BeginUpdate; 107 | 108 | Result := Auto.Defer( 109 | procedure 110 | begin 111 | EndUpdate; 112 | end 113 | ); 114 | end; 115 | 116 | { TComboBoxHelper } 117 | 118 | procedure TComboBoxHelper.UpdateItems; 119 | var 120 | PreviousEvent: TNotifyEvent; 121 | PreviousItem: String; 122 | PreviousItemFound: Boolean; 123 | AutoEndUpdate: IDeferredOperation; 124 | i: Integer; 125 | begin 126 | // Save the current state 127 | PreviousItem := Self.Text; 128 | PreviousEvent := Self.OnChange; 129 | 130 | // Remove all items 131 | Self.OnChange := nil; 132 | Self.Items.BeginUpdate; 133 | AutoEndUpdate := Auto.Defer( 134 | procedure 135 | begin 136 | Self.Items.EndUpdate; 137 | Self.OnChange := PreviousEvent; 138 | end 139 | ); 140 | Self.Clear; 141 | 142 | // Add new items 143 | for i := 0 to High(NewItems) do 144 | Self.Items.Add(NewItems[i]); 145 | 146 | // Restore selection 147 | PreviousItemFound := False; 148 | for i := 0 to Pred(Self.Items.Count) do 149 | if Self.Items[i] = PreviousItem then 150 | begin 151 | Self.Text := PreviousItem; 152 | Self.ItemIndex := i; 153 | PreviousItemFound := True; 154 | Break; 155 | end; 156 | 157 | // Reset selection if necessary 158 | if not PreviousItemFound then 159 | begin 160 | Self.Text := PreviousItem; 161 | Self.ItemIndex := FallbackIndex; 162 | end; 163 | end; 164 | 165 | { TCheckBoxHack } 166 | 167 | procedure TCheckBoxHack.SetCheckedEx; 168 | begin 169 | ClicksDisabled := True; 170 | Checked := Value; 171 | ClicksDisabled := False; 172 | end; 173 | 174 | procedure TCheckBoxHack.SetStateEx; 175 | begin 176 | ClicksDisabled := True; 177 | State := Value; 178 | ClicksDisabled := False; 179 | end; 180 | 181 | { TMenuShortCut } 182 | 183 | class function TMenuShortCut.Collect; 184 | begin 185 | Result := nil; 186 | 187 | if Item.ShortCut <> 0 then 188 | begin 189 | SetLength(Result, Length(Result) + 1); 190 | Result[High(Result)] := TMenuShortCut.Create(Item); 191 | end; 192 | 193 | for Item in Item do 194 | Result := Result + TMenuShortCut.Collect(Item); 195 | end; 196 | 197 | constructor TMenuShortCut.Create; 198 | begin 199 | Menu := Item; 200 | Key := Item.ShortCut and $FFF; 201 | ShiftState := []; 202 | 203 | if BitTest(Item.ShortCut and scCommand) then 204 | Include(ShiftState, ssCommand); 205 | 206 | if BitTest(Item.ShortCut and scCtrl) then 207 | Include(ShiftState, ssCtrl); 208 | 209 | if BitTest(Item.ShortCut and scShift) then 210 | Include(ShiftState, ssShift); 211 | 212 | if BitTest(Item.ShortCut and scAlt) then 213 | Include(ShiftState, ssAlt); 214 | end; 215 | 216 | end. 217 | -------------------------------------------------------------------------------- /Prototypes/NtUiCommon.PageHost.pas: -------------------------------------------------------------------------------- 1 | unit NtUiCommon.PageHost; 2 | 3 | { 4 | This module provides a component for hosting frames in a page control. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, 12 | NtUiCommon.Prototypes, NtUiCommon.Interfaces, System.Actions, Vcl.ActnList; 13 | 14 | type 15 | TFramePages = class(TFrame, ICanConsumeEscape, IHasDefaultCaption) 16 | PageControl: TPageControl; 17 | ActionList: TActionList; 18 | procedure PageControlChange(Sender: TObject); 19 | private 20 | FTabs: TArray; 21 | FFrames: TArray; 22 | FActions: TArray; 23 | FDelayLoaded: TArray; 24 | FDefaultCaption: String; 25 | function ConsumesEscape: Boolean; 26 | procedure SwitchToTabAction(Sender: TObject); 27 | function GetDefaultCaption: String; 28 | procedure NotifyDelayedLoading(Index: Integer); 29 | protected 30 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 31 | public 32 | procedure LoadPages( 33 | const Frames: TArray; 34 | const DefaultCaption: String 35 | ); 36 | end; 37 | 38 | implementation 39 | 40 | uses 41 | NtUtils.Errors; 42 | 43 | {$R *.dfm} 44 | 45 | { TFramePages } 46 | 47 | function TFramePages.ConsumesEscape; 48 | var 49 | ForwardedImpl: ICanConsumeEscape; 50 | i: Integer; 51 | begin 52 | i := PageControl.ActivePageIndex; 53 | 54 | // Forward the request to the frame from the active page 55 | Result := (i >= 0) and (i <= High(FFrames)) and 56 | IUnknown(FFrames[i]).QueryInterface(ICanConsumeEscape, 57 | ForwardedImpl).IsSuccess and ForwardedImpl.ConsumesEscape; 58 | end; 59 | 60 | procedure TFramePages.FrameEnabledChanged; 61 | begin 62 | inherited; 63 | // Notify the visible page about activation/disactivation 64 | PageControlChange(Self); 65 | end; 66 | 67 | function TFramePages.GetDefaultCaption; 68 | begin 69 | Result := FDefaultCaption; 70 | end; 71 | 72 | procedure TFramePages.LoadPages; 73 | var 74 | i: Integer; 75 | CaptionImpl: IHasDefaultCaption; 76 | RequiredWidth, RequiredHeight: Integer; 77 | begin 78 | // Instantiate frames 79 | SetLength(FFrames, Length(Frames)); 80 | 81 | RequiredWidth := 0; 82 | RequiredHeight := 0; 83 | 84 | for i := 0 to High(Frames) do 85 | begin 86 | FFrames[i] := Frames[i](Self); 87 | FFrames[i].Name := FFrames[i].Name + IntToStr(i); 88 | 89 | // Select the default page dimensions 90 | if FFrames[i].Width > RequiredWidth then 91 | RequiredWidth := FFrames[i].Width; 92 | 93 | if FFrames[i].Height > RequiredHeight then 94 | RequiredHeight := FFrames[i].Height; 95 | end; 96 | 97 | SetLength(FTabs, Length(Frames)); 98 | SetLength(FActions, Length(Frames)); 99 | SetLength(FDelayLoaded, Length(Frames)); 100 | 101 | for i := 0 to High(Frames) do 102 | begin 103 | // Make a new page 104 | FTabs[i] := TTabSheet.Create(PageControl); 105 | FTabs[i].PageControl := PageControl; 106 | 107 | if i = 0 then 108 | begin 109 | // Resize to the dimensions of the biggest page 110 | Width := RequiredWidth + Width - FTabs[i].Width; 111 | Height := RequiredHeight + Height - FTabs[i].Height; 112 | end; 113 | 114 | // Adjust page caption 115 | if IUnknown(FFrames[i]).QueryInterface(IHasDefaultCaption, 116 | CaptionImpl).IsSuccess then 117 | FTabs[i].Caption := CaptionImpl.GetDefaultCaption 118 | else 119 | FTabs[i].Caption := FFrames[i].ClassName; 120 | 121 | // Attach the frame 122 | FFrames[i].Parent := FTabs[i]; 123 | FFrames[i].Align := alClient; 124 | FDelayLoaded[i] := False; 125 | 126 | if i < 9 then 127 | begin 128 | // Handle page switching on Ctrl+ 129 | FActions[i] := TAction.Create(ActionList); 130 | FActions[i].ShortCut := scCtrl or (Ord('1') + i); 131 | FActions[i].Tag := i; 132 | FActions[i].OnExecute := SwitchToTabAction; 133 | FActions[i].ActionList := ActionList; 134 | end; 135 | end; 136 | 137 | FDefaultCaption := DefaultCaption; 138 | NotifyDelayedLoading(0); 139 | end; 140 | 141 | procedure TFramePages.NotifyDelayedLoading; 142 | var 143 | DelayedLoader: IDelayedLoad; 144 | begin 145 | // Invoke the delayed loading callback on the frame 146 | if (Index >= 0) and (Index <= High(FFrames)) and not FDelayLoaded[Index] then 147 | begin 148 | if IUnknown(FFrames[Index]).QueryInterface(IDelayedLoad, 149 | DelayedLoader).IsSuccess then 150 | DelayedLoader.DelayedLoad; 151 | 152 | FDelayLoaded[Index] := True; 153 | end; 154 | end; 155 | 156 | procedure TFramePages.PageControlChange; 157 | var 158 | Observer: IObservesActivation; 159 | i: Integer; 160 | begin 161 | // Adjust active state for all frames to allow handling conflicting shortcuts 162 | for i := 0 to High(FFrames) do 163 | if IUnknown(FFrames[i]).QueryInterface(IObservesActivation, 164 | Observer).IsSuccess then 165 | Observer.SetActive((i = PageControl.ActivePageIndex) and Enabled); 166 | 167 | // Initiate delayed loading for the newly visible frame 168 | NotifyDelayedLoading(PageControl.ActivePageIndex); 169 | end; 170 | 171 | procedure TFramePages.SwitchToTabAction; 172 | begin 173 | if Sender is TAction then 174 | begin 175 | PageControl.ActivePageIndex := Word(TAction(Sender).Tag); 176 | PageControlChange(Sender); 177 | end; 178 | end; 179 | 180 | { Integration } 181 | 182 | function NtUiLibHostPages( 183 | AOwner: TComponent; 184 | Pages: TArray; 185 | const DefaultCaption: String 186 | ): TFrame; 187 | var 188 | Frame: TFramePages absolute Result; 189 | begin 190 | Frame := TFramePages.Create(AOwner); 191 | try 192 | Frame.LoadPages(Pages, DefaultCaption); 193 | except 194 | Frame.Free; 195 | raise; 196 | end; 197 | end; 198 | 199 | initialization 200 | NtUiCommon.Prototypes.NtUiLibHostPages := NtUiLibHostPages; 201 | end. 202 | -------------------------------------------------------------------------------- /Prototypes/UI.Prototypes.Sid.Edit.pas: -------------------------------------------------------------------------------- 1 | unit UI.Prototypes.Sid.Edit; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 7 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 8 | NtUtils, NtUiFrame, NtUiLib.AutoCompletion; 9 | 10 | type 11 | TSidChoice = ( 12 | scNone, 13 | scIntegrity, 14 | scTrust 15 | ); 16 | 17 | TSidEditor = class(TBaseFrame) 18 | tbxSid: TEdit; 19 | btnDsPicker: TButton; 20 | btnCheatsheet: TButton; 21 | btnChoice: TButton; 22 | procedure btnCheatsheetClick(Sender: TObject); 23 | procedure btnDsPickerClick(Sender: TObject); 24 | procedure tbxSidChange(Sender: TObject); 25 | procedure tbxSidEnter(Sender: TObject); 26 | procedure btnChoiceClick(Sender: TObject); 27 | private 28 | FSuggestions: IAutoCompletionSuggestions; 29 | FOnSidChanged: TNotifyEvent; 30 | SidCache: ISid; 31 | FSidChoice: TSidChoice; 32 | function GetSid: ISid; 33 | procedure SetSid(const Sid: ISid); 34 | procedure DsPickerIconChanged(ImageList: TImageList; ImageIndex: Integer); 35 | procedure CheatsheetIconChanged(ImageList: TImageList; ImageIndex: Integer); 36 | procedure ChoiceIconChanged(ImageList: TImageList; ImageIndex: Integer); 37 | procedure SetSidChoice(const Value: TSidChoice); 38 | protected 39 | procedure LoadedOnce; override; 40 | procedure FrameEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; 41 | public 42 | function TryGetSid(out Sid: ISid): TNtxStatus; 43 | property Sid: ISid read GetSid write SetSid; 44 | published 45 | property OnSidChanged: TNotifyEvent read FOnSidChanged write FOnSidChanged; 46 | property SidChoice: TSidChoice read FSidChoice write SetSidChoice; 47 | end; 48 | 49 | implementation 50 | 51 | uses 52 | Ntapi.ntstatus, Ntapi.WinNt, NtUtils.Lsa.Sid, NtUiLib.AutoCompletion.Sid, 53 | NtUtils.Security.Sid, NtUiCommon.Forms, Resources.Icon.Catalogue, 54 | Resources.Icon.UserPicker, Resources.Icon.Choose, NtUiCommon.Prototypes, 55 | NtUiFrame.Sids.Abbreviations; 56 | 57 | {$R *.dfm} 58 | 59 | { TSidFrame } 60 | 61 | procedure TSidEditor.btnCheatsheetClick; 62 | begin 63 | if tbxSid.CanFocus then 64 | tbxSid.SetFocus; 65 | 66 | NtUiLibHostFrameShow( 67 | function (AOwner: TComponent): TFrame 68 | begin 69 | Result := TSidAbbreviationFrame.Create(AOwner); 70 | end 71 | ); 72 | end; 73 | 74 | procedure TSidEditor.btnChoiceClick; 75 | var 76 | Current: ISid; 77 | begin 78 | if not TryGetSid(Current).IsSuccess then 79 | Current := nil; 80 | 81 | case FSidChoice of 82 | scIntegrity: 83 | if Assigned(NtUiLibSelectIntegrity) then 84 | Sid := NtUiLibSelectIntegrity(Self, Current); 85 | 86 | scTrust: 87 | if Assigned(NtUiLibSelectTrust) then 88 | Sid := NtUiLibSelectTrust(Self, Current); 89 | end; 90 | end; 91 | 92 | procedure TSidEditor.btnDsPickerClick; 93 | begin 94 | if tbxSid.CanFocus then 95 | tbxSid.SetFocus; 96 | 97 | tbxSid.Text := NtUiLibSelectDsObject(Handle); 98 | end; 99 | 100 | procedure TSidEditor.CheatsheetIconChanged; 101 | begin 102 | btnCheatsheet.Images := ImageList; 103 | btnCheatsheet.ImageIndex := ImageIndex; 104 | end; 105 | 106 | procedure TSidEditor.ChoiceIconChanged; 107 | begin 108 | btnChoice.Images := ImageList; 109 | btnChoice.ImageIndex := ImageIndex; 110 | end; 111 | 112 | procedure TSidEditor.DsPickerIconChanged; 113 | begin 114 | btnDsPicker.Images := ImageList; 115 | btnDsPicker.ImageIndex := ImageIndex; 116 | end; 117 | 118 | procedure TSidEditor.FrameEnabledChanged; 119 | begin 120 | inherited; 121 | tbxSid.Enabled := Enabled; 122 | btnCheatsheet.Enabled := Enabled; 123 | btnDsPicker.Enabled := Enabled; 124 | end; 125 | 126 | function TSidEditor.GetSid; 127 | begin 128 | TryGetSid(Result).RaiseOnError; 129 | end; 130 | 131 | procedure TSidEditor.LoadedOnce; 132 | begin 133 | inherited; 134 | RegisterResourceIcon(RESOURCES_ICON_USER_PICKER, DsPickerIconChanged); 135 | RegisterResourceIcon(RESOURCES_ICON_CATALOGUE, CheatsheetIconChanged); 136 | RegisterResourceIcon(RESOURCES_ICON_CHOOSE, ChoiceIconChanged); 137 | btnDsPicker.Visible := Assigned(NtUiLibSelectDsObject); 138 | end; 139 | 140 | procedure TSidEditor.SetSid; 141 | var 142 | OnCheckedReverter: IDeferredOperation; 143 | begin 144 | tbxSid.OnChange := nil; 145 | OnCheckedReverter := Auto.Defer( 146 | procedure 147 | begin 148 | tbxSid.OnChange := tbxSidChange; 149 | end 150 | ); 151 | 152 | SidCache := Sid; 153 | 154 | if Assigned(Sid) then 155 | tbxSid.Text := LsaxSidToString(Sid) 156 | else 157 | tbxSid.Text := ''; 158 | 159 | if Assigned(FOnSidChanged) then 160 | FOnSidChanged(Self); 161 | end; 162 | 163 | procedure TSidEditor.SetSidChoice; 164 | begin 165 | FSidChoice := Value; 166 | 167 | case Value of 168 | scIntegrity: 169 | begin 170 | btnChoice.Visible := Assigned(NtUiLibSelectIntegrity); 171 | btnChoice.Hint := 'Choose Integrity Level'; 172 | end; 173 | 174 | scTrust: 175 | begin 176 | btnChoice.Visible := Assigned(NtUiLibSelectTrust); 177 | btnChoice.Hint := 'Choose Trust Level'; 178 | end; 179 | else 180 | btnChoice.Visible := False; 181 | btnChoice.Hint := ''; 182 | end; 183 | end; 184 | 185 | procedure TSidEditor.tbxSidChange; 186 | begin 187 | SidCache := nil; 188 | 189 | if Assigned(FOnSidChanged) then 190 | FOnSidChanged(Self); 191 | end; 192 | 193 | procedure TSidEditor.tbxSidEnter; 194 | begin 195 | if not Assigned(FSuggestions) then 196 | begin 197 | FSuggestions := ShlxPrepareeSidSuggestions; 198 | ShlxEnableSuggestions(tbxSid.Handle, FSuggestions); 199 | end; 200 | end; 201 | 202 | function TSidEditor.TryGetSid; 203 | begin 204 | // Use cache when available 205 | if Assigned(SidCache) then 206 | begin 207 | Sid := SidCache; 208 | Result := Default(TNtxStatus); 209 | Exit; 210 | end; 211 | 212 | // Workaround empty lookups that give confusing results 213 | if (tbxSid.Text = '') or (tbxSid.Text = '\') then 214 | begin 215 | Result.Location := 'TSidEditor.TryGetSid'; 216 | Result.Status := STATUS_NONE_MAPPED; 217 | Exit; 218 | end; 219 | 220 | Result := LsaxLookupNameOrSddl(tbxSid.Text, Sid); 221 | 222 | // Cache successful lookups 223 | if Result.IsSuccess then 224 | SidCache := Sid; 225 | end; 226 | 227 | end. 228 | -------------------------------------------------------------------------------- /Prototypes/NtUiDialog.FrameHost.pas: -------------------------------------------------------------------------------- 1 | unit NtUiDialog.FrameHost; 2 | 3 | { 4 | This module provides a dialog for hosting frames. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, 11 | Vcl.Dialogs, Vcl.StdCtrls, DevirtualizedTree, NtUiCommon.Forms; 12 | 13 | type 14 | TFrameInitializer = reference to function (AOwner: TComponent): TFrame; 15 | 16 | TFrameHostDialog = class(TChildForm) 17 | btnClose: TButton; 18 | btnSelect: TButton; 19 | procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 20 | procedure btnCloseClick(Sender: TObject); 21 | procedure DefaultActionChosen(const Node: INodeProvider); 22 | procedure btnSelectClick(Sender: TObject); 23 | private 24 | FFrame: TFrame; 25 | FFrameRef: IUnknown; 26 | FFrameModalResult: IInterface; 27 | procedure FrameModalResultChanged(Sender: TObject); 28 | protected 29 | procedure AddFrame(Frame: TFrame; AllowModal: Boolean); 30 | public 31 | function PickModal: IInterface; 32 | class function Pick(AOwner: TComponent; Initializer: TFrameInitializer): IInterface; static; 33 | class procedure Display(Initializer: TFrameInitializer); static; 34 | end; 35 | 36 | implementation 37 | 38 | uses 39 | Winapi.Windows, NtUiCommon.Prototypes, NtUiCommon.Interfaces, NtUtils.Errors; 40 | 41 | {$BOOLEVAL OFF} 42 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 43 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 44 | 45 | {$R *.dfm} 46 | 47 | procedure TFrameHostDialog.AddFrame; 48 | const 49 | SMALL_MARGIN = 3; 50 | BIG_MARGIN = 31; 51 | var 52 | ModalResultObservation: IHasModalResultObservation; 53 | ButtonCaptions: IHasModalButtonCaptions; 54 | DefaultCaption: IHasDefaultCaption; 55 | DefaultAction: IAllowsDefaultNodeAction; 56 | DelayedLoad: IDelayedLoad; 57 | BottomMargin, OtherMargin: Integer; 58 | begin 59 | if not Assigned(Frame) then 60 | Exit; 61 | 62 | FFrame := Frame; 63 | FFrameRef := IUnknown(FFrame); 64 | 65 | if AllowModal then 66 | BottomMargin := BIG_MARGIN * CurrentPPI div 96 67 | else 68 | BottomMargin := SMALL_MARGIN * CurrentPPI div 96; 69 | 70 | OtherMargin := SMALL_MARGIN * CurrentPPI div 96; 71 | ClientWidth := FFrame.Width + OtherMargin * 2; 72 | ClientHeight := FFrame.Height + OtherMargin + BottomMargin; 73 | FFrame.Parent := Self; 74 | FFrame.AlignWithMargins := True; 75 | FFrame.Margins.SetBounds(OtherMargin, OtherMargin, OtherMargin, BottomMargin); 76 | FFrame.Align := alClient; 77 | FFrame.TabOrder := 0; 78 | btnClose.Visible := AllowModal; 79 | btnSelect.Visible := AllowModal; 80 | 81 | if FFrameRef.QueryInterface(IHasDefaultCaption, DefaultCaption).IsSuccess then 82 | Caption := DefaultCaption.GetDefaultCaption 83 | else 84 | Caption := FFrame.ClassName; 85 | 86 | if AllowModal then 87 | begin 88 | // Subscribe to modal result changes 89 | if FFrameRef.QueryInterface(IHasModalResultObservation, 90 | ModalResultObservation).IsSuccess then 91 | begin 92 | ModalResultObservation.OnModalResultChanged := FrameModalResultChanged; 93 | FrameModalResultChanged(Self); 94 | end; 95 | 96 | // Adjust button captions 97 | if FFrameRef.QueryInterface(IHasModalButtonCaptions, 98 | ButtonCaptions).IsSuccess then 99 | begin 100 | btnSelect.Caption := ButtonCaptions.ConfirmationCaption; 101 | btnClose.Caption := ButtonCaptions.CancellationCaption; 102 | end; 103 | 104 | // Set the default action on the frame 105 | if FFrameRef.QueryInterface(IAllowsDefaultNodeAction, 106 | DefaultAction).IsSuccess then 107 | begin 108 | DefaultAction.MainActionCaption := btnSelect.Caption; 109 | DefaultAction.OnMainAction := DefaultActionChosen; 110 | end; 111 | end; 112 | 113 | // Delay-initialize the frame 114 | if FFrameRef.QueryInterface(IDelayedLoad, DelayedLoad).IsSuccess then 115 | DelayedLoad.DelayedLoad; 116 | end; 117 | 118 | procedure TFrameHostDialog.btnCloseClick; 119 | begin 120 | Close; 121 | end; 122 | 123 | procedure TFrameHostDialog.btnSelectClick; 124 | var 125 | ModalResultImpl: IHasModalResult; 126 | begin 127 | // Retrieve the modal result from the frame 128 | if FFrameRef.QueryInterface(IHasModalResult, ModalResultImpl).IsSuccess then 129 | FFrameModalResult := ModalResultImpl.ModalResult 130 | else 131 | FFrameModalResult := nil; 132 | 133 | // Initiate closing if no exceptions occured 134 | ModalResult := mrOk; 135 | end; 136 | 137 | procedure TFrameHostDialog.DefaultActionChosen; 138 | begin 139 | FFrameModalResult := Node; 140 | ModalResult := mrOk; 141 | end; 142 | 143 | class procedure TFrameHostDialog.Display; 144 | var 145 | Form: TFrameHostDialog; 146 | begin 147 | Form := TFrameHostDialog.Create(nil, cfmDesktop); 148 | 149 | try 150 | Form.AddFrame(Initializer(Form), False); 151 | except 152 | Form.Free; 153 | raise; 154 | end; 155 | 156 | Form.Show; 157 | end; 158 | 159 | procedure TFrameHostDialog.FormKeyDown; 160 | var 161 | Consumer: ICanConsumeEscape; 162 | begin 163 | if (Key = VK_ESCAPE) and (not Assigned(FFrameRef) or not 164 | FFrameRef.QueryInterface(ICanConsumeEscape, Consumer).IsSuccess or 165 | not Consumer.ConsumesEscape) then 166 | begin 167 | btnClose.Click; 168 | Key := 0; 169 | end; 170 | end; 171 | 172 | procedure TFrameHostDialog.FrameModalResultChanged; 173 | var 174 | ModalResultImpl: IHasModalResultObservation; 175 | begin 176 | if Assigned(FFrameRef) and FFrameRef.QueryInterface( 177 | IHasModalResultObservation, ModalResultImpl).IsSuccess then 178 | btnSelect.Enabled := ModalResultImpl.HasModalResult; 179 | end; 180 | 181 | class function TFrameHostDialog.Pick; 182 | var 183 | Form: TFrameHostDialog; 184 | begin 185 | Form := TFrameHostDialog.Create(AOwner, cfmApplication); 186 | 187 | try 188 | Form.AddFrame(Initializer(Form), True); 189 | except 190 | Form.Free; 191 | raise; 192 | end; 193 | 194 | // Show the dialog and free on close 195 | Result := Form.PickModal; 196 | 197 | if not Assigned(Result) then 198 | Abort; 199 | end; 200 | 201 | function TFrameHostDialog.PickModal; 202 | begin 203 | ShowModal; 204 | 205 | // Note: the form will be destroyed when it processes the next message. 206 | // until then, we can access the field. 207 | Result := FFrameModalResult; 208 | end; 209 | 210 | initialization 211 | NtUiLibHostFrameShow := TFrameHostDialog.Display; 212 | NtUiLibHostFramePick := TFrameHostDialog.Pick; 213 | end. 214 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Security.OwnerGroup.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Security.OwnerGroup; 2 | 3 | { 4 | This module provides a frame for viewing/editing owner and primary group of 5 | securable objects. 6 | } 7 | 8 | interface 9 | 10 | uses 11 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 12 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, NtUiFrame, 13 | UI.Prototypes.Sid.Edit, Vcl.StdCtrls, System.Actions, Vcl.ActnList, 14 | NtUiCommon.Interfaces, NtUiCommon.Prototypes, NtUtils; 15 | 16 | type 17 | TDescriptorSidType = (dsOwner, dsPrimaryGroup); 18 | 19 | TOwnerGroupSecurityFrame = class(TFrame, IHasDefaultCaption, 20 | IObservesActivation, IDelayedLoad) 21 | SidEditor: TSidEditor; 22 | GroupBox: TGroupBox; 23 | cbxDefaulted: TCheckBox; 24 | btnRefresh: TButton; 25 | btnApply: TButton; 26 | ActionList: TActionList; 27 | ActionRefresh: TAction; 28 | procedure btnRefreshClick(Sender: TObject); 29 | procedure btnApplyClick(Sender: TObject); 30 | private 31 | FSidType: TDescriptorSidType; 32 | FContext: TNtUiLibSecurityContext; 33 | function Refresh: TNtxStatus; 34 | function Apply: TNtxStatus; 35 | function GetDefaultCaption: String; 36 | procedure SetActive(Active: Boolean); 37 | procedure DelayedLoad; 38 | public 39 | procedure LoadFor( 40 | SidType: TDescriptorSidType; 41 | const Context: TNtUiLibSecurityContext 42 | ); 43 | end; 44 | 45 | // Construct a frame initializer for an ACL security editor 46 | function NtUiLibSidSecurityFrameInitializer( 47 | SidType: TDescriptorSidType; 48 | const Context: TNtUiLibSecurityContext 49 | ): TFrameInitializer; 50 | 51 | implementation 52 | 53 | uses 54 | Ntapi.WinNt, NtUtils.Security; 55 | 56 | {$R *.dfm} 57 | 58 | const 59 | FLAG_DEFAULTED: array [TDescriptorSidType] of TSecurityDescriptorControl = ( 60 | SE_OWNER_DEFAULTED, SE_GROUP_DEFAULTED); 61 | 62 | SECURITY_INFORMATION: array [TDescriptorSidType] of TSecurityInformation = ( 63 | OWNER_SECURITY_INFORMATION, GROUP_SECURITY_INFORMATION); 64 | 65 | SID_CAPTIONS: array [TDescriptorSidType] of String = ( 66 | 'Owner', 'Primary Group'); 67 | 68 | { TOwnerGroupSecurityFrame } 69 | 70 | function TOwnerGroupSecurityFrame.Apply; 71 | var 72 | hxObject: IHandle; 73 | SD: TSecurityDescriptorData; 74 | SecDesc: ISecurityDescriptor; 75 | DesiredAccess: TAccessMask; 76 | begin 77 | if not Assigned(FContext.HandleProvider) or 78 | not Assigned(FContext.SetFunction) then 79 | raise Exception.Create('No callback for setting security is available'); 80 | 81 | // Check for custom access mask lookup 82 | if Assigned(FContext.CustomSetAccessLookup) then 83 | DesiredAccess := FContext.CustomSetAccessLookup( 84 | SECURITY_INFORMATION[FSidType]) 85 | else 86 | DesiredAccess := SecurityWriteAccess(SECURITY_INFORMATION[FSidType]); 87 | 88 | // Start building a security descriptor 89 | SD := Default(TSecurityDescriptorData); 90 | 91 | if cbxDefaulted.Checked then 92 | SD.Control := FLAG_DEFAULTED[FSidType]; 93 | 94 | if FSidType = dsOwner then 95 | Result := SidEditor.TryGetSid(SD.Owner) 96 | else 97 | Result := SidEditor.TryGetSid(SD.Group); 98 | 99 | if not Result.IsSuccess then 100 | Exit; 101 | 102 | Result := RtlxAllocateSecurityDescriptor(SD, SecDesc); 103 | 104 | if not Result.IsSuccess then 105 | Exit; 106 | 107 | // Open the handle 108 | Result := FContext.HandleProvider(hxObject, DesiredAccess); 109 | 110 | if not Result.IsSuccess then 111 | Exit; 112 | 113 | // Apply the security descriptor 114 | Result := FContext.SetFunction(hxObject, SECURITY_INFORMATION[FSidType], 115 | SecDesc.Data); 116 | 117 | if not Result.IsSuccess then 118 | Exit; 119 | 120 | Refresh; 121 | end; 122 | 123 | procedure TOwnerGroupSecurityFrame.btnApplyClick; 124 | begin 125 | Apply.RaiseOnError; 126 | end; 127 | 128 | procedure TOwnerGroupSecurityFrame.btnRefreshClick; 129 | begin 130 | Refresh.RaiseOnError; 131 | end; 132 | 133 | procedure TOwnerGroupSecurityFrame.DelayedLoad; 134 | begin 135 | Refresh; 136 | end; 137 | 138 | function TOwnerGroupSecurityFrame.GetDefaultCaption; 139 | begin 140 | Result := SID_CAPTIONS[FSidType]; 141 | end; 142 | 143 | procedure TOwnerGroupSecurityFrame.LoadFor; 144 | begin 145 | if SidType > High(TDescriptorSidType) then 146 | raise Exception.Create('Invalid SID type'); 147 | 148 | FSidType := SidType; 149 | FContext := Context; 150 | end; 151 | 152 | function TOwnerGroupSecurityFrame.Refresh; 153 | var 154 | hxObject: IHandle; 155 | SecDesc: ISecurityDescriptor; 156 | SD: TSecurityDescriptorData; 157 | DesiredAccess: TAccessMask; 158 | begin 159 | if not Assigned(FContext.HandleProvider) or 160 | not Assigned(FContext.QueryFunction) then 161 | raise Exception.Create('No callback for querying security is available'); 162 | 163 | // Check for custom access mask lookup 164 | if Assigned(FContext.CustomQueryAccessLookup) then 165 | DesiredAccess := FContext.CustomQueryAccessLookup( 166 | SECURITY_INFORMATION[FSidType]) 167 | else 168 | DesiredAccess := SecurityReadAccess(SECURITY_INFORMATION[FSidType]); 169 | 170 | // Reset UI state 171 | cbxDefaulted.Checked := False; 172 | SidEditor.Sid := nil; 173 | 174 | // Open the handle 175 | Result := FContext.HandleProvider(hxObject, DesiredAccess); 176 | 177 | if not Result.IsSuccess then 178 | Exit; 179 | 180 | // Query the security descriptor 181 | Result := FContext.QueryFunction(hxObject, SECURITY_INFORMATION[FSidType], 182 | SecDesc); 183 | 184 | if not Result.IsSuccess then 185 | Exit; 186 | 187 | // Parse the data 188 | Result := RtlxCaptureSecurityDescriptor(SecDesc.Data, SD); 189 | 190 | if not Result.IsSuccess then 191 | Exit; 192 | 193 | // Update the controls 194 | cbxDefaulted.Checked := BitTest(SD.Control and FLAG_DEFAULTED[FSidType]); 195 | 196 | if FSidType = dsOwner then 197 | SidEditor.Sid := SD.Owner 198 | else 199 | SidEditor.Sid := SD.Group; 200 | end; 201 | 202 | procedure TOwnerGroupSecurityFrame.SetActive; 203 | begin 204 | if Active then 205 | ActionList.State := asNormal 206 | else 207 | ActionList.State := asSuspended; 208 | end; 209 | 210 | { Integration } 211 | 212 | function NtUiLibSidSecurityFrameInitializer; 213 | begin 214 | Result := function (AOwner: TComponent): TFrame 215 | var 216 | Frame: TOwnerGroupSecurityFrame absolute Result; 217 | begin 218 | Frame := TOwnerGroupSecurityFrame.Create(AOwner); 219 | try 220 | Frame.LoadFor(SidType, Context) 221 | except 222 | Frame.Free; 223 | raise; 224 | end; 225 | end; 226 | end; 227 | 228 | end. 229 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Acl.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Acl; 2 | 3 | { 4 | The module provides a frame for viewing/modifying Access Control Lists. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 12 | VirtualTreesEx, DevirtualizedTree, NtUtils, Vcl.StdCtrls, NtUiFrame, 13 | Ntapi.WinNt, Vcl.Menus, System.Actions, Vcl.ActnList, Vcl.ExtCtrls, 14 | NtUiFrame.Search, NtUiCommon.Interfaces, NtUtils.Security.Acl; 15 | 16 | type 17 | TAclFrame = class(TBaseFrame, ICanConsumeEscape, ICanShowEmptyMessage, 18 | IObservesActivation) 19 | Tree: TDevirtualizedTree; 20 | btnUp: TButton; 21 | btnDown: TButton; 22 | btnCanonicalize: TButton; 23 | btnAdd: TButton; 24 | btnDelete: TButton; 25 | PopupMenu: TPopupMenu; 26 | cmEdit: TMenuItem; 27 | cmDelete: TMenuItem; 28 | cmUp: TMenuItem; 29 | cmDown: TMenuItem; 30 | ActionList: TActionList; 31 | alxNew: TAction; 32 | alxCanonicalize: TAction; 33 | alxEdit: TAction; 34 | RightPanel: TPanel; 35 | Search: TSearchFrame; 36 | procedure btnCanonicalizeClick(Sender: TObject); 37 | procedure btnDeleteClick(Sender: TObject); 38 | procedure SelectionChanged(Sender: TBaseVirtualTree; Node: PVirtualNode); 39 | procedure btnUpClick(Sender: TObject); 40 | procedure btnDownClick(Sender: TObject); 41 | procedure btnAddClick(Sender: TObject); 42 | procedure cmEditClick(Sender: TObject); 43 | procedure TreeGetPopupMenu(Sender: TBaseVirtualTree; Node: PVirtualNode; 44 | Column: TColumnIndex; const P: TPoint; var AskParent: Boolean; 45 | var PopupMenu: TPopupMenu); 46 | private 47 | FMaskType: Pointer; 48 | FGenericMapping: TGenericMapping; 49 | FOnAceChange: TNotifyEvent; 50 | FDefaultAceType: TAceType; 51 | procedure AclChanged; 52 | procedure btnUpIconChanged(ImageList: TImageList; ImageIndex: Integer); 53 | procedure btnAddIconChanged(ImageList: TImageList; ImageIndex: Integer); 54 | procedure btnCanonicalizeIconChanged(ImageList: TImageList; ImageIndex: Integer); 55 | procedure btnDeleteIconChanged(ImageList: TImageList; ImageIndex: Integer); 56 | procedure btnDownIconChanged(ImageList: TImageList; ImageIndex: Integer); 57 | procedure SetActive(Active: Boolean); 58 | function GetAces: TArray; 59 | property SearchImpl: TSearchFrame read Search implements ICanConsumeEscape; 60 | protected 61 | procedure LoadedOnce; override; 62 | public 63 | procedure SetEmptyMessage(const Value: String); 64 | procedure LoadAces( 65 | const Aces: TArray; 66 | MaskType: Pointer; 67 | const GenericMapping: TGenericMapping; 68 | DefaultAceType: TAceType = ACCESS_ALLOWED_ACE_TYPE 69 | ); 70 | property Aces: TArray read GetAces; 71 | property OnAceChange: TNotifyEvent read FOnAceChange write FOnAceChange; 72 | end; 73 | 74 | implementation 75 | 76 | uses 77 | NtUiBackend.Acl, NtUiCommon.Helpers, Resources.Icon.Add, 78 | Resources.Icon.Delete, Resources.Icon.Down, Resources.Icon.Up, 79 | Resources.Icon.Verify, NtUiCommon.Prototypes; 80 | 81 | {$R *.dfm} 82 | 83 | { TAclFrame } 84 | 85 | procedure TAclFrame.AclChanged; 86 | begin 87 | btnCanonicalize.Enabled := not UiLibIsCanonicalAcl(Tree); 88 | SelectionChanged(Tree, nil); 89 | 90 | if Assigned(FOnAceChange) then 91 | FOnAceChange(Self); 92 | end; 93 | 94 | procedure TAclFrame.btnAddClick; 95 | begin 96 | if not Assigned(NtUiLibCreateAce) then 97 | Exit; 98 | 99 | UiLibInsertAceNode(Tree, NtUiLibCreateAce(Self, FMaskType, FGenericMapping, 100 | FDefaultAceType), FMaskType); 101 | AclChanged; 102 | end; 103 | 104 | procedure TAclFrame.btnAddIconChanged; 105 | begin 106 | btnAdd.Images := ImageList; 107 | btnAdd.ImageIndex := ImageIndex; 108 | end; 109 | 110 | procedure TAclFrame.btnCanonicalizeClick; 111 | begin 112 | UiLibCanonicalizeAcl(Tree); 113 | AclChanged; 114 | end; 115 | 116 | procedure TAclFrame.btnCanonicalizeIconChanged; 117 | begin 118 | btnCanonicalize.Images := ImageList; 119 | btnCanonicalize.ImageIndex := ImageIndex; 120 | end; 121 | 122 | procedure TAclFrame.btnDeleteClick; 123 | begin 124 | Tree.BeginUpdateAuto; 125 | Tree.DeleteSelectedNodesEx(True); 126 | AclChanged; 127 | end; 128 | 129 | procedure TAclFrame.btnDeleteIconChanged; 130 | begin 131 | btnDelete.Images := ImageList; 132 | btnDelete.ImageIndex := ImageIndex; 133 | end; 134 | 135 | procedure TAclFrame.btnDownClick; 136 | begin 137 | Tree.MoveSelectedNodesDown; 138 | AclChanged; 139 | end; 140 | 141 | procedure TAclFrame.btnDownIconChanged; 142 | begin 143 | btnDown.Images := ImageList; 144 | btnDown.ImageIndex := ImageIndex; 145 | end; 146 | 147 | procedure TAclFrame.btnUpClick; 148 | begin 149 | Tree.MoveSelectedNodesUp; 150 | AclChanged; 151 | end; 152 | 153 | procedure TAclFrame.btnUpIconChanged; 154 | begin 155 | btnUp.Images := ImageList; 156 | btnUp.ImageIndex := ImageIndex; 157 | end; 158 | 159 | procedure TAclFrame.cmEditClick; 160 | var 161 | Node: IAceNode; 162 | begin 163 | if not Assigned(NtUiLibEditAce) or (Tree.SelectedCount <> 1) or not 164 | Tree.FocusedNode.TryGetProvider(IAceNode, Node) then 165 | Exit; 166 | 167 | // Invoke the editor dialog and save the result 168 | Node.Ace := NtUiLibEditAce(Self, FMaskType, FGenericMapping, Node.Ace); 169 | UiLibUnhideAceSpecificColumns(Tree, Node.Ace); 170 | AclChanged; 171 | end; 172 | 173 | function TAclFrame.GetAces; 174 | begin 175 | Result := UiLibCollectAces(Tree); 176 | end; 177 | 178 | procedure TAclFrame.LoadAces; 179 | begin 180 | UiLibLoadAceNodes(Tree, Aces, MaskType); 181 | FMaskType := MaskType; 182 | FGenericMapping := GenericMapping; 183 | FDefaultAceType := DefaultAceType; 184 | AclChanged; 185 | end; 186 | 187 | procedure TAclFrame.LoadedOnce; 188 | begin 189 | inherited; 190 | RegisterResourceIcon(RESOURCES_ICON_UP, btnUpIconChanged); 191 | RegisterResourceIcon(RESOURCES_ICON_ADD, btnAddIconChanged); 192 | RegisterResourceIcon(RESOURCES_ICON_VERIFY, btnCanonicalizeIconChanged); 193 | RegisterResourceIcon(RESOURCES_ICON_DELETE, btnDeleteIconChanged); 194 | RegisterResourceIcon(RESOURCES_ICON_DOWN, btnDownIconChanged); 195 | btnAdd.Enabled := Assigned(NtUiLibCreateAce); 196 | Search.AttachToTree(Tree); 197 | end; 198 | 199 | procedure TAclFrame.SelectionChanged; 200 | begin 201 | btnUp.Enabled := Tree.CanMoveSelectedNodesUp; 202 | btnDelete.Enabled := Tree.SelectedCount > 0; 203 | btnDown.Enabled := Tree.CanMoveSelectedNodesDown; 204 | end; 205 | 206 | procedure TAclFrame.SetActive; 207 | begin 208 | if Active then 209 | ActionList.State := asNormal 210 | else 211 | ActionList.State := asSuspended; 212 | 213 | (Search as IObservesActivation).SetActive(Active); 214 | end; 215 | 216 | procedure TAclFrame.SetEmptyMessage; 217 | begin 218 | Tree.NoItemsText := Value; 219 | end; 220 | 221 | procedure TAclFrame.TreeGetPopupMenu; 222 | begin 223 | cmEdit.Visible := Assigned(NtUiLibEditAce) and (Tree.SelectedCount = 1); 224 | end; 225 | 226 | end. 227 | -------------------------------------------------------------------------------- /Prototypes/NtUiFrame.Bits.pas: -------------------------------------------------------------------------------- 1 | unit NtUiFrame.Bits; 2 | 3 | { 4 | This module provides a frame for showing bit masks and enumerations. 5 | } 6 | 7 | interface 8 | 9 | uses 10 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, 11 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, 12 | VirtualTreesEx, DevirtualizedTree, Vcl.StdCtrls, Vcl.ExtCtrls, Ntapi.WinNt, 13 | DelphiUtils.AutoObjects, NtUiCommon.Interfaces, NtUiBackend.Bits, 14 | NtUtils.SysUtils; 15 | 16 | type 17 | TBitsFrame = class(TFrame, IHasDefaultCaption) 18 | Tree: TDevirtualizedTree; 19 | BottomPanel: TPanel; 20 | tbxValue: TEdit; 21 | btnClear: TButton; 22 | btnAll: TButton; 23 | procedure tbxValueChange(Sender: TObject); 24 | procedure TreeChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); 25 | procedure btnClearClick(Sender: TObject); 26 | procedure btnAllClick(Sender: TObject); 27 | private 28 | FSize: TIntegerSize; 29 | FValidMask: UInt64; 30 | FValue: UInt64; 31 | FIsReadOnly: Boolean; 32 | function SuppressTreeReadOnly: IAutoReleasable; 33 | procedure RefreshText(Editing: Boolean = False); 34 | procedure RefreshItems; 35 | procedure SetValue(const NewValue: UInt64); 36 | procedure SetTreeReadOnly(const Value: Boolean); 37 | procedure SetReadOnly(const Value: Boolean); 38 | function GetDefaultCaption: String; 39 | public 40 | procedure LoadType(ATypeInfo: Pointer); 41 | procedure LoadAccessMaskType( 42 | ATypeInfo: Pointer; 43 | const GenericMapping: TGenericMapping; 44 | ShowGenericRights: Boolean; 45 | ShowMiscRights: Boolean 46 | ); 47 | property Value: UInt64 read FValue write SetValue; 48 | property IsReadOnly: Boolean read FIsReadOnly write SetReadOnly; 49 | end; 50 | 51 | implementation 52 | 53 | uses 54 | VirtualTrees.Types, NtUiCommon.Helpers, NtUiCommon.Colors, 55 | DelphiUiLib.Strings, NtUiCommon.Prototypes; 56 | 57 | {$R *.dfm} 58 | 59 | { TBitsFrame } 60 | 61 | procedure TBitsFrame.btnAllClick; 62 | begin 63 | Value := FValidMask; 64 | end; 65 | 66 | procedure TBitsFrame.btnClearClick; 67 | begin 68 | Value := 0; 69 | end; 70 | 71 | function TBitsFrame.GetDefaultCaption; 72 | begin 73 | if FIsReadOnly then 74 | Result := 'Bit Mask Viewer' 75 | else 76 | Result := 'Bit Mask Editor' 77 | end; 78 | 79 | procedure TBitsFrame.LoadAccessMaskType; 80 | begin 81 | SuppressTreeReadOnly; 82 | FSize := isCardinal; 83 | UiLibAddAccessMaskNodes(Tree, ATypeInfo, GenericMapping, FValidMask, 84 | ShowGenericRights, ShowMiscRights); 85 | 86 | // Update item states 87 | SetValue(FValue); 88 | end; 89 | 90 | procedure TBitsFrame.LoadType; 91 | begin 92 | SuppressTreeReadOnly; 93 | UiLibAddBitNodes(Tree, ATypeInfo, FSize, FValidMask); 94 | 95 | // Update item states 96 | SetValue(FValue); 97 | end; 98 | 99 | procedure TBitsFrame.RefreshItems; 100 | const 101 | CHECK_STATE: array [Boolean] of TCheckState = ( 102 | csUncheckedNormal, csCheckedNormal); 103 | var 104 | Node: PVirtualNode; 105 | FlagNode: IFlagNode; 106 | OnCheckedReverter: IDeferredOperation; 107 | begin 108 | Tree.BeginUpdateAuto; 109 | SuppressTreeReadOnly; 110 | Tree.OnChecked := nil; 111 | OnCheckedReverter := Auto.Defer( 112 | procedure 113 | begin 114 | Tree.OnChecked := TreeChecked; 115 | end 116 | ); 117 | 118 | // Update states for checkboxes 119 | for Node in Tree.Nodes do 120 | if Node.TryGetProvider(IFlagNode, FlagNode) then 121 | Tree.CheckState[Node] := CHECK_STATE[(FlagNode.Mask and FValue) = 122 | FlagNode.Value]; 123 | end; 124 | 125 | procedure TBitsFrame.RefreshText; 126 | var 127 | OnCheckedReverter: IDeferredOperation; 128 | begin 129 | if not Editing then 130 | begin 131 | tbxValue.OnChange := nil; 132 | OnCheckedReverter := Auto.Defer( 133 | procedure 134 | begin 135 | tbxValue.OnChange := tbxValueChange; 136 | end 137 | ); 138 | 139 | // Update the text 140 | tbxValue.Text := UiLibUIntToHex(FValue, NUMERIC_WIDTH_PER_SIZE[FSize]); 141 | end; 142 | 143 | tbxValue.Hint := BuildHint('Decimal', UiLibUIntToDec(FValue)); 144 | tbxValue.Color := clWindow; 145 | end; 146 | 147 | procedure TBitsFrame.SetReadOnly; 148 | begin 149 | FIsReadOnly := Value; 150 | btnClear.Visible := not Value; 151 | btnAll.Visible := not Value; 152 | tbxValue.ReadOnly := Value; 153 | SetTreeReadOnly(Value); 154 | RefreshText; 155 | end; 156 | 157 | procedure TBitsFrame.SetTreeReadOnly; 158 | begin 159 | if Value then 160 | Tree.TreeOptions.MiscOptions := Tree.TreeOptions.MiscOptions + [toReadOnly] 161 | else 162 | Tree.TreeOptions.MiscOptions := Tree.TreeOptions.MiscOptions - [toReadOnly]; 163 | end; 164 | 165 | procedure TBitsFrame.SetValue; 166 | begin 167 | FValue := NewValue; 168 | RefreshText; 169 | RefreshItems; 170 | end; 171 | 172 | function TBitsFrame.SuppressTreeReadOnly; 173 | begin 174 | if FIsReadOnly then 175 | begin 176 | SetTreeReadOnly(False); 177 | Result := Auto.Defer( 178 | procedure 179 | begin 180 | SetTreeReadOnly(True); 181 | end 182 | ); 183 | end 184 | else 185 | Result := nil; 186 | end; 187 | 188 | procedure TBitsFrame.tbxValueChange; 189 | var 190 | NewValue: UInt64; 191 | begin 192 | if UiLibStringToUInt64(tbxValue.Text, NewValue, False, FSize) then 193 | begin 194 | FValue := NewValue; 195 | RefreshText(True); 196 | RefreshItems; 197 | end 198 | else 199 | tbxValue.Color := ColorSettings.clBackgroundError; 200 | end; 201 | 202 | procedure TBitsFrame.TreeChecked; 203 | var 204 | FlagNode: IFlagNode; 205 | begin 206 | if not Node.TryGetProvider(IFlagNode, FlagNode) then 207 | Exit; 208 | 209 | // Modify the value according to the change 210 | case Tree.CheckState[Node] of 211 | csUncheckedNormal: 212 | if Tree.CheckType[Node] = ctCheckBox then 213 | FValue := FValue and not FlagNode.Value; 214 | 215 | csCheckedNormal: 216 | FValue := (FValue and not FlagNode.Mask) or FlagNode.Value; 217 | end; 218 | 219 | RefreshText; 220 | RefreshItems; 221 | end; 222 | 223 | procedure NtUiLibShowBitMask( 224 | const Value: UInt64; 225 | ATypeInfo: Pointer 226 | ); 227 | begin 228 | if not Assigned(NtUiLibHostFrameShow) then 229 | raise ENotSupportedException.Create('Frame host not available'); 230 | 231 | NtUiLibHostFrameShow( 232 | function (AOwner: TComponent): TFrame 233 | var 234 | Frame: TBitsFrame absolute Result; 235 | begin 236 | Frame := TBitsFrame.Create(AOwner); 237 | try 238 | Frame.LoadType(ATypeInfo); 239 | Frame.Value := Value; 240 | Frame.IsReadOnly := True; 241 | except 242 | Frame.Free; 243 | raise; 244 | end; 245 | end 246 | ); 247 | end; 248 | 249 | procedure NtUiLibShowAccessMask( 250 | const Value: TAccessMask; 251 | ATypeInfo: Pointer; 252 | const GenericMapping: TGenericMapping 253 | ); 254 | begin 255 | if not Assigned(NtUiLibHostFrameShow) then 256 | raise ENotSupportedException.Create('Frame host not available'); 257 | 258 | NtUiLibHostFrameShow( 259 | function (AOwner: TComponent): TFrame 260 | var 261 | Frame: TBitsFrame absolute Result; 262 | begin 263 | Frame := TBitsFrame.Create(AOwner); 264 | try 265 | Frame.LoadAccessMaskType(ATypeInfo, GenericMapping, False, False); 266 | Frame.Value := Value; 267 | Frame.IsReadOnly := True; 268 | except 269 | Frame.Free; 270 | raise; 271 | end; 272 | end 273 | ); 274 | end; 275 | 276 | initialization 277 | NtUiCommon.Prototypes.NtUiLibShowBitMask := NtUiLibShowBitMask; 278 | NtUiCommon.Prototypes.NtUiLibShowAccessMask := NtUiLibShowAccessMask; 279 | end. 280 | -------------------------------------------------------------------------------- /Common/NtUiBackend.Sids.Logon.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.Sids.Logon; 2 | 3 | interface 4 | 5 | uses 6 | Ntapi.WinNt, Ntapi.NtSecApi, NtUtils, NtUiBackend.Sids, DevirtualizedTree; 7 | 8 | type 9 | ILogonSessionErrorNode = interface (INodeProvider) 10 | ['{2A6AC1C0-3056-49D0-9706-A1356D179A1A}'] 11 | function GetLogonId: TLogonId; 12 | function GetStatus: TNtxStatus; 13 | property LogonId: TLogonId read GetLogonId; 14 | property Status: TNtxStatus read GetStatus; 15 | end; 16 | 17 | ILogonSessionSidNode = interface (ISidNode) 18 | ['{C44BE4D5-EC6C-40EA-A183-27008F886278}'] 19 | function GetLogonId: TLogonId; 20 | function GetLogonType: TSecurityLogonType; 21 | property LogonId: TLogonId read GetLogonId; 22 | property LogonType: TSecurityLogonType read GetLogonType; 23 | end; 24 | 25 | function NtUiLibCollectLogonSidNodes( 26 | out Nodes: TArray 27 | ): TNtxStatus; 28 | 29 | implementation 30 | 31 | uses 32 | NtUtils.Security.Sid, NtUtils.Lsa.Sid, NtUtils.Lsa.Logon, NtUtils.Errors, 33 | NtUiLib.Errors, DevirtualizedTree.Provider, DelphiUtils.Arrays, 34 | DelphiUiLib.Strings, DelphiUiLib.LiteReflection, NtUiCommon.Colors; 35 | 36 | {$BOOLEVAL OFF} 37 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 38 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 39 | 40 | const 41 | colId = 0; 42 | colLogonType = 1; 43 | colFriendlyName = 2; 44 | colSid = 3; 45 | colSidType = 4; 46 | colMax = 5; 47 | 48 | type 49 | ILogonSessionSidNodeInternal = interface (ILogonSessionSidNode) 50 | ['{3F5FBC1B-0C47-4EFD-9E47-28786A7C44A9}'] 51 | procedure SetSidName(const Value: TTranslatedName); 52 | end; 53 | 54 | TLogonSessionErrorNode = class (TNodeProvider, ILogonSessionErrorNode) 55 | private 56 | FLogonId: TLogonId; 57 | FStatus: TNtxStatus; 58 | protected 59 | procedure Initialize; override; 60 | function GetLogonId: TLogonId; 61 | function GetStatus: TNtxStatus; 62 | public 63 | constructor Create(const LogonId: TLogonId; const Status: TNtxStatus); 64 | end; 65 | 66 | TLogonSessionSidNode = class (TNodeProvider, ILogonSessionSidNode, 67 | ILogonSessionSidNodeInternal) 68 | private 69 | FLogonId: TLogonId; 70 | FLogonType: TSecurityLogonType; 71 | FSidName: TTranslatedName; 72 | protected 73 | procedure Initialize; override; 74 | function GetLogonId: TLogonId; 75 | function GetLogonType: TSecurityLogonType; 76 | function GetSidName: TTranslatedName; 77 | procedure SetSidName(const Value: TTranslatedName); 78 | public 79 | constructor Create( 80 | LogonId: TLogonId; 81 | LogonType: TSecurityLogonType; 82 | const Sid: ISid 83 | ); 84 | end; 85 | 86 | { TLogonSessionErrorNode } 87 | 88 | constructor TLogonSessionErrorNode.Create; 89 | begin 90 | inherited Create(colMax); 91 | FLogonId := LogonId; 92 | FStatus := Status; 93 | end; 94 | 95 | function TLogonSessionErrorNode.GetLogonId; 96 | begin 97 | Result := FLogonId;; 98 | end; 99 | 100 | function TLogonSessionErrorNode.GetStatus; 101 | begin 102 | Result := FStatus; 103 | end; 104 | 105 | procedure TLogonSessionErrorNode.Initialize; 106 | begin 107 | inherited; 108 | FColumnText[colId] := UiLibUIntToHex(FLogonId); 109 | 110 | if FStatus.IsSuccess then 111 | begin 112 | FColumnText[colFriendlyName] := '(None)'; 113 | FColumnText[colSid] := '(None)'; 114 | FColumnText[colSidType] := '(None)'; 115 | end 116 | else 117 | FHint := FStatus.ToString; 118 | 119 | SetFontColor(ColorSettings.clForegroundInactive); 120 | end; 121 | 122 | { TLogonSessionSidNode } 123 | 124 | constructor TLogonSessionSidNode.Create; 125 | begin 126 | inherited Create(colMax); 127 | FLogonId := LogonId; 128 | FLogonType := LogonType; 129 | FSidName.SID := Sid; 130 | end; 131 | 132 | function TLogonSessionSidNode.GetLogonId; 133 | begin 134 | Result := FLogonId; 135 | end; 136 | 137 | function TLogonSessionSidNode.GetLogonType; 138 | begin 139 | Result := FLogonType; 140 | end; 141 | 142 | function TLogonSessionSidNode.GetSidName; 143 | begin 144 | Result := FSidName; 145 | end; 146 | 147 | procedure TLogonSessionSidNode.Initialize; 148 | begin 149 | inherited; 150 | FColumnText[colId] := UiLibUIntToHex(FLogonId); 151 | FColumnText[colSid] := RtlxSidToStringNoError(FSidName.SID); 152 | 153 | if FLogonType in [TSecurityLogonType.Interactive..High(TSecurityLogonType)] then 154 | FColumnText[colLogonType] := Rttix.Format(FLogonType); 155 | 156 | if FSidName.IsValid then 157 | begin 158 | FColumnText[colFriendlyName] := FSidName.FullName; 159 | FColumnText[colSidType] := Rttix.Format(FSidName.SidType); 160 | end; 161 | 162 | FHint := BuildHint([ 163 | THintSection.New('Logon ID', FColumnText[colId]), 164 | THintSection.New('Logon Type', FColumnText[colLogonType]), 165 | THintSection.New('Owner SID Friendly Name', FColumnText[colFriendlyName]), 166 | THintSection.New('Owner SID', FColumnText[colSid]) 167 | ]); 168 | end; 169 | 170 | procedure TLogonSessionSidNode.SetSidName; 171 | begin 172 | FSidName := Value; 173 | end; 174 | 175 | { Functions } 176 | 177 | procedure AttachLookup( 178 | const Nodes: TArray 179 | ); 180 | var 181 | SIDs: TArray; 182 | Names: TArray; 183 | TranslatedNodes: TArray; 184 | i, Count: Integer; 185 | Node: ILogonSessionSidNodeInternal; 186 | begin 187 | Count := 0; 188 | 189 | // Count non-error nodes 190 | for i := 0 to High(Nodes) do 191 | if Nodes[i].QueryInterface(ILogonSessionSidNodeInternal, Node).IsSuccess then 192 | Inc(Count); 193 | 194 | // Collect their SIDs 195 | SetLength(SIDs, Count); 196 | SetLength(TranslatedNodes, Count); 197 | Count := 0; 198 | 199 | // Count non-error nodes 200 | for i := 0 to High(Nodes) do 201 | if Nodes[i].QueryInterface(ILogonSessionSidNodeInternal, Node).IsSuccess then 202 | begin 203 | SIDs[Count] := Node.SidName.SID; 204 | TranslatedNodes[Count] := Node; 205 | Inc(Count); 206 | end; 207 | 208 | // Perform bulk lookup and attach it to nodes 209 | LsaxLookupSids(SIDs, Names); 210 | 211 | for i := 0 to High(TranslatedNodes) do 212 | TranslatedNodes[i].SetSidName(Names[i]); 213 | end; 214 | 215 | function NtUiLibCollectLogonSidNodes; 216 | var 217 | Luids: TArray; 218 | Info: ILogonSession; 219 | LogonType: TSecurityLogonType; 220 | Sid: ISid; 221 | i: Integer; 222 | begin 223 | // Snapshot logon sessions 224 | Result := LsaxEnumerateLogonSessions(Luids); 225 | 226 | if not Result.IsSuccess then 227 | Exit; 228 | 229 | TArray.SortInline(Luids, 230 | function (const A, B: TLogonId): Integer 231 | begin 232 | if A > B then 233 | Result := 1 234 | else if A < B then 235 | Result := -1 236 | else 237 | Result := 0; 238 | end 239 | ); 240 | 241 | SetLength(Nodes, Length(Luids)); 242 | 243 | for i := 0 to High(Luids) do 244 | begin 245 | // Retrieve details 246 | Result := LsaxQueryLogonSession(Luids[i], Info); 247 | 248 | if not Result.IsSuccess or not Assigned(Info.Data.SID) or 249 | not RtlxCopySid(Info.Data.SID, Sid).SaveTo(Result).IsSuccess then 250 | Sid := nil; 251 | 252 | if Result.IsSuccess then 253 | LogonType := Info.Data.LogonType 254 | else 255 | begin 256 | // Check if we know the SID from logon ID 257 | Sid := LsaxLookupKnownLogonSessionSid(Luids[i]); 258 | LogonType := TSecurityLogonType.UndefinedLogonType; 259 | end; 260 | 261 | if Assigned(Sid) then 262 | Nodes[i] := TLogonSessionSidNode.Create(Luids[i], LogonType, Sid) 263 | else 264 | Nodes[i] := TLogonSessionErrorNode.Create(Luids[i], Result); 265 | end; 266 | 267 | // Perform bulk SID lookup and attach it 268 | AttachLookup(Nodes); 269 | Result := NtxSuccess; 270 | end; 271 | 272 | end. 273 | -------------------------------------------------------------------------------- /Common/NtUiBackend.Sids.Capabilities.pas: -------------------------------------------------------------------------------- 1 | unit NtUiBackend.Sids.Capabilities; 2 | 3 | { 4 | This module provides logic for the capability list dialog 5 | } 6 | 7 | interface 8 | 9 | uses 10 | DevirtualizedTree, NtUtils; 11 | 12 | const 13 | colName = 0; 14 | colAppSid = 1; 15 | colGroupSid = 2; 16 | colMax = 3; 17 | 18 | type 19 | TCapabilityCategory = ( 20 | ccBuiltin, 21 | ccLpac, 22 | ccAppSilo, 23 | ccNormal, 24 | ccVendor, 25 | ccLegacy 26 | ); 27 | 28 | ICapabilityGroupNode = interface (INodeProvider) 29 | ['{A3D7BD74-E834-4D49-98F6-862EEAAE6F7D}'] 30 | function GetCategory: TCapabilityCategory; 31 | property Category: TCapabilityCategory read GetCategory; 32 | end; 33 | 34 | ICapabilityNode = interface (INodeProvider) 35 | ['{B518F216-9BEE-4E21-8508-AC79FB88973A}'] 36 | function GetName: String; 37 | function GetAppSid: ISid; 38 | function GetGroupSid: ISid; 39 | function GetCategory: TCapabilityCategory; 40 | 41 | property Name: String read GetName; 42 | property AppSid: ISid read GetAppSid; 43 | property GroupSid: ISid read GetGroupSid; 44 | property Category: TCapabilityCategory read GetCategory; 45 | end; 46 | 47 | TCapabilityGroup = record 48 | Group: ICapabilityGroupNode; 49 | Items: TArray; 50 | end; 51 | 52 | TCapabilityNodes = array [TCapabilityCategory] of TCapabilityGroup; 53 | 54 | function UiLibMakeCapabilityNodes( 55 | ): TCapabilityNodes; 56 | 57 | implementation 58 | 59 | uses 60 | NtUtils.SysUtils, NtUtils.Packages, DevirtualizedTree.Provider, 61 | NtUtils.Security.Sid, NtUtils.Security.AppContainer, DelphiUtils.Arrays, 62 | DelphiUiLib.Strings, NtUiLib.AutoCompletion.Sid.Capabilities, 63 | Vcl.Graphics, NtUiCommon.Colors; 64 | 65 | {$BOOLEVAL OFF} 66 | {$IFOPT R+}{$DEFINE R+}{$ENDIF} 67 | {$IFOPT Q+}{$DEFINE Q+}{$ENDIF} 68 | 69 | function ColorForState( 70 | Category: TCapabilityCategory 71 | ): TColor; 72 | begin 73 | case Category of 74 | ccBuiltin: Result := ColorSettings.clBackgroundSystem; 75 | ccLpac: Result := ColorSettings.clBackgroundAllowAccent; 76 | ccAppSilo: Result := ColorSettings.clBackgroundAllow; 77 | ccNormal: Result := ColorSettings.clBackgroundUser; 78 | ccVendor: Result := ColorSettings.clBackgroundAlter; 79 | ccLegacy: Result := ColorSettings.clBackgroundInactive; 80 | else 81 | Result := clWindow; 82 | end; 83 | end; 84 | 85 | type 86 | TCapabilityBaseNode = class (TNodeProvider, ICapabilityGroupNode) 87 | FCategory: TCapabilityCategory; 88 | function GetCategory: TCapabilityCategory; 89 | procedure Initialize; override; 90 | constructor Create(Category: TCapabilityCategory); 91 | end; 92 | 93 | { TCapabilityBaseNode } 94 | 95 | constructor TCapabilityBaseNode.Create; 96 | begin 97 | inherited Create(colMax); 98 | FCategory := Category; 99 | end; 100 | 101 | function TCapabilityBaseNode.GetCategory; 102 | begin 103 | Result := FCategory;; 104 | end; 105 | 106 | procedure TCapabilityBaseNode.Initialize; 107 | const 108 | NAMES: array [TCapabilityCategory] of String = ( 109 | 'Built-in Capabilities', 'LPAC Capabilities', 'AppSilo Capabilities', 110 | 'Other Capabilities', 'Vendor Capabilities', 'Legacy Capabilities' 111 | ); 112 | begin 113 | inherited; 114 | FColumnText[colName] := NAMES[FCategory]; 115 | SetFontStyle([TFontStyle.fsBold]); 116 | SetColor(ColorForState(FCategory)); 117 | end; 118 | 119 | type 120 | TCapabilityNode = class (TNodeProvider, ICapabilityNode) 121 | FCapabilityName: String; 122 | FAppSid, FGroupSid: ISid; 123 | FCategory: TCapabilityCategory; 124 | function GetName: String; 125 | function GetAppSid: ISid; 126 | function GetGroupSid: ISid; 127 | function GetCategory: TCapabilityCategory; 128 | procedure Initialize; override; 129 | constructor Create(const Name: String; const AppSid: ISid; const GroupSid: ISid); 130 | end; 131 | 132 | { TCapabilityNode } 133 | 134 | constructor TCapabilityNode.Create; 135 | begin 136 | inherited Create(colMax); 137 | 138 | FCapabilityName := Name; 139 | FAppSid := AppSid; 140 | FGroupSid := GroupSid; 141 | 142 | if RtlxSubAuthorityCountSid(FAppSid) = 2 then 143 | FCategory := ccBuiltin 144 | else if RtlxPrefixString('lpac', FCapabilityName) then 145 | FCategory := ccLpac 146 | else if RtlxPrefixString('isolatedWin32-', FCapabilityName) then 147 | FCategory := ccAppSilo 148 | else if RtlxPrefixString('ID_CAP_', FCapabilityName) then 149 | FCategory := ccLegacy 150 | else if PkgxIsValidFamilyName(FCapabilityName) then 151 | FCategory := ccVendor 152 | else 153 | FCategory := ccNormal; 154 | end; 155 | 156 | function TCapabilityNode.GetAppSid; 157 | begin 158 | Result := FAppSid; 159 | end; 160 | 161 | function TCapabilityNode.GetCategory; 162 | begin 163 | Result := FCategory; 164 | end; 165 | 166 | function TCapabilityNode.GetGroupSid; 167 | begin 168 | Result := FGroupSid; 169 | end; 170 | 171 | function TCapabilityNode.GetName; 172 | begin 173 | Result := FCapabilityName; 174 | end; 175 | 176 | procedure TCapabilityNode.Initialize; 177 | begin 178 | inherited; 179 | 180 | FColumnText[colName] := FCapabilityName; 181 | FColumnText[colAppSid] := RtlxSidToStringNoError(FAppSid); 182 | FColumnText[colGroupSid] := RtlxSidToStringNoError(FGroupSid); 183 | FHint := BuildHint([ 184 | THintSection.New('Name', FColumnText[colName]), 185 | THintSection.New('App Capability SID', FColumnText[colAppSid]), 186 | THintSection.New('Group Capability SID', FColumnText[colGroupSid]) 187 | ]); 188 | SetColor(ColorForState(FCategory)); 189 | end; 190 | 191 | function CompareBySid(const A, B: ICapabilityNode): Integer; 192 | begin 193 | Result := RtlxCompareSids(A.AppSid, B.AppSid); 194 | end; 195 | 196 | function CompareByName(const A, B: ICapabilityNode): Integer; 197 | begin 198 | Result := RtlxCompareStrings(A.Name, b.Name); 199 | end; 200 | 201 | { Functions } 202 | 203 | [Result: MayReturnNil] 204 | function UiLibMakeCapabilityNode( 205 | const Name: String 206 | ): ICapabilityNode; 207 | var 208 | AppSid, GroupSid: ISid; 209 | begin 210 | if RtlxDeriveCapabilitySids(Name, GroupSid, AppSid).IsSuccess then 211 | Result := TCapabilityNode.Create(Name, AppSid, GroupSid) 212 | else 213 | Result := nil; 214 | end; 215 | 216 | function UiLibMakeCapabilityNodes; 217 | var 218 | Names: TArray; 219 | Nodes: TArray; 220 | Category: TCapabilityCategory; 221 | i, j: Integer; 222 | Counts: array [TCapabilityCategory] of Integer; 223 | begin 224 | Names := RtlxEnumerateKnownCapabilities; 225 | 226 | // Makes nodes for all known names 227 | SetLength(Nodes, Length(Names)); 228 | 229 | j := 0; 230 | for i := 0 to High(Names) do 231 | begin 232 | Nodes[j] := UiLibMakeCapabilityNode(Names[i]); 233 | 234 | if Assigned(Nodes[j]) then 235 | Inc(j); 236 | end; 237 | 238 | if j <> Length(Nodes) then 239 | SetLength(Nodes, j); 240 | 241 | // Count nodes per category 242 | FillChar(Counts, SizeOf(Counts), 0); 243 | 244 | for i := 0 to High(Nodes) do 245 | Inc(Counts[Nodes[i].Category]); 246 | 247 | // Allocate groups 248 | for Category := Low(TCapabilityCategory) to High(TCapabilityCategory) do 249 | begin 250 | Result[Category].Group := TCapabilityBaseNode.Create(Category); 251 | SetLength(Result[Category].Items, Counts[Category]); 252 | end; 253 | 254 | // Assign nodes to groups 255 | FillChar(Counts, SizeOf(Counts), 0); 256 | 257 | for i := 0 to High(Nodes) do 258 | begin 259 | Category := Nodes[i].Category; 260 | Result[Category].Items[Counts[Category]] := Nodes[i]; 261 | Inc(Counts[Category]); 262 | end; 263 | 264 | // Sort each group 265 | TArray.SortInline(Result[ccBuiltin].Items, CompareBySid); 266 | 267 | for Category := Succ(Low(TCapabilityCategory)) to High(TCapabilityCategory) do 268 | TArray.SortInline(Result[Category].Items, CompareByName); 269 | end; 270 | 271 | end. 272 | -------------------------------------------------------------------------------- /Components/VirtualTreesEx.DefaultMenu.pas: -------------------------------------------------------------------------------- 1 | unit VirtualTreesEx.DefaultMenu; 2 | 3 | { 4 | This module provides the default popup menu for the VirtualTreeView for 5 | copying and inspecting items. 6 | } 7 | 8 | interface 9 | 10 | uses 11 | VirtualTrees, Vcl.Menus, System.Classes; 12 | 13 | type 14 | TNodeEvent = procedure (Node: PVirtualNode) of object; 15 | 16 | // A structure for capturing keyboard shortcuts of a popup menu 17 | TMenuShortCut = record 18 | Menu: TMenuItem; 19 | ShiftState: TShiftState; 20 | Key: Word; 21 | function Matches(ShiftState: TShiftState; Key: Word): Boolean; 22 | constructor Create(Item: TMenuItem); 23 | class function Collect(Item: TMenuItem): TArray; static; 24 | end; 25 | 26 | // A provider of the default menu items for extended virtual trees 27 | TDefaultTreeMenu = class 28 | private 29 | FTree: TCustomVirtualStringTree; 30 | FMenu, FFallbackMenu: TPopupMenu; 31 | FMenuMainAction: TMenuItem; 32 | FMenuSeparator: TMenuItem; 33 | FMenuCopy: TMenuItem; 34 | FMenuCopyColumn: TMenuItem; 35 | FShortcuts: TArray; 36 | FPopupColumnIndex: Integer; 37 | FOnMainAction: TNodeEvent; 38 | procedure MenuMainActionClick(Sender: TObject); 39 | procedure MenuCopyClick(Sender: TObject); 40 | procedure MenuCopyColumnClick(Sender: TObject); 41 | function GetMainActionText: String; 42 | procedure SetMainActionText(const Value: String); 43 | public 44 | procedure AttachItemsTo(Menu: TPopupMenu); 45 | procedure InvokeShortcuts(Key: Word; Shift: TShiftState); 46 | procedure InvokeMainAction; 47 | procedure RefreshShortcuts; 48 | procedure NotifyPopup(Node: PVirtualNode; Menu: TPopupMenu; Column: TColumnIndex); 49 | property FallbackMenu: TPopupMenu read FFallbackMenu; 50 | property OnMainAction: TNodeEvent read FOnMainAction write FOnMainAction; 51 | property MainActionText: String read GetMainActionText write SetMainActionText; 52 | constructor Create(Owner: TCustomVirtualStringTree); 53 | end; 54 | 55 | implementation 56 | 57 | uses 58 | Winapi.Windows, Vcl.Clipbrd, System.SysUtils, VirtualTreesEx; 59 | 60 | { TMenuShortCut } 61 | 62 | class function TMenuShortCut.Collect; 63 | begin 64 | Result := nil; 65 | 66 | // Save the shortcut from the current item 67 | if Item.ShortCut <> 0 then 68 | begin 69 | SetLength(Result, Length(Result) + 1); 70 | Result[High(Result)] := TMenuShortCut.Create(Item); 71 | end; 72 | 73 | // Process netsed items recursively 74 | for Item in Item do 75 | Result := Result + TMenuShortCut.Collect(Item); 76 | end; 77 | 78 | constructor TMenuShortCut.Create; 79 | begin 80 | Menu := Item; 81 | Key := Item.ShortCut and $FFF; 82 | ShiftState := []; 83 | 84 | if LongBool(Item.ShortCut and scCommand) then 85 | Include(ShiftState, ssCommand); 86 | 87 | if LongBool(Item.ShortCut and scCtrl) then 88 | Include(ShiftState, ssCtrl); 89 | 90 | if LongBool(Item.ShortCut and scShift) then 91 | Include(ShiftState, ssShift); 92 | 93 | if LongBool(Item.ShortCut and scAlt) then 94 | Include(ShiftState, ssAlt); 95 | end; 96 | 97 | function TMenuShortCut.Matches; 98 | begin 99 | Result := (Self.ShiftState = ShiftState) and (Self.Key = Key); 100 | end; 101 | 102 | { TDefaultTreeMenu } 103 | 104 | procedure TDefaultTreeMenu.AttachItemsTo; 105 | begin 106 | // Note: nil means no menu, so we use our fallback one 107 | if not Assigned(Menu) then 108 | Menu := FFallbackMenu; 109 | 110 | FMenu := Menu; 111 | 112 | // Attach the item for the main action to the top 113 | if Assigned(FMenuMainAction.Parent) then 114 | FMenuMainAction.Parent.Remove(FMenuMainAction); 115 | 116 | Menu.Items.Insert(0, FMenuMainAction); 117 | 118 | // Attach items for copying text to the bottom of the popup menu 119 | FMenuSeparator.SetParentComponent(Menu); 120 | FMenuCopy.SetParentComponent(Menu); 121 | FMenuCopyColumn.SetParentComponent(Menu); 122 | 123 | RefreshShortcuts; 124 | end; 125 | 126 | constructor TDefaultTreeMenu.Create; 127 | begin 128 | FTree := Owner; 129 | FFallbackMenu := TPopupMenu.Create(FTree); 130 | 131 | FMenuMainAction := TMenuItem.Create(FTree); 132 | FMenuMainAction.Caption := 'Inspect...'; 133 | FMenuMainAction.Default := True; 134 | FMenuMainAction.ShortCut := VK_RETURN; 135 | FMenuMainAction.Visible := False; 136 | FMenuMainAction.OnClick := MenuMainActionClick; 137 | 138 | FMenuSeparator := TMenuItem.Create(FTree); 139 | FMenuSeparator.Caption := '-'; 140 | FMenuSeparator.Visible := False; 141 | 142 | FMenuCopy := TMenuItem.Create(FTree); 143 | FMenuCopy.Caption := 'Copy'; 144 | FMenuCopy.ShortCut := scCtrl or Ord('C'); 145 | FMenuCopy.OnClick := MenuCopyClick; 146 | 147 | FMenuCopyColumn := TMenuItem.Create(FTree); 148 | FMenuCopyColumn.Caption := 'Copy "%s"'; 149 | FMenuCopyColumn.OnClick := MenuCopyColumnClick; 150 | 151 | AttachItemsTo(FFallbackMenu); 152 | end; 153 | 154 | function TDefaultTreeMenu.GetMainActionText; 155 | begin 156 | Result := FMenuMainAction.Caption; 157 | end; 158 | 159 | procedure TDefaultTreeMenu.InvokeMainAction; 160 | begin 161 | MenuMainActionClick(FTree); 162 | end; 163 | 164 | procedure TDefaultTreeMenu.InvokeShortcuts; 165 | var 166 | Shortcut: TMenuShortCut; 167 | begin 168 | inherited; 169 | 170 | // Ignore item-specific shortcuts when they are no items selected 171 | if (FTree.SelectedCount = 0) and (FTree is TVirtualStringTreeEx) and 172 | (TVirtualStringTreeEx(FTree).PopupMode = pmOnItemsOnly) then 173 | Exit; 174 | 175 | // Invoke events on all menu items with matching shortcuts 176 | for Shortcut in FShortcuts do 177 | if Shortcut.Matches(Shift, Key) and Assigned(Shortcut.Menu.OnClick) then 178 | Shortcut.Menu.OnClick(FTree); 179 | end; 180 | 181 | procedure TDefaultTreeMenu.MenuCopyClick; 182 | begin 183 | FTree.CopyToClipboard; 184 | end; 185 | 186 | procedure TDefaultTreeMenu.MenuCopyColumnClick; 187 | var 188 | Node: PVirtualNode; 189 | Texts: TArray; 190 | i: Integer; 191 | begin 192 | i := 0; 193 | for Node in FTree.SelectedNodes do 194 | Inc(i); 195 | 196 | SetLength(Texts, i); 197 | 198 | i := 0; 199 | for Node in FTree.SelectedNodes do 200 | begin 201 | Texts[i] := FTree.Text[Node, FPopupColumnIndex]; 202 | Inc(i); 203 | end; 204 | 205 | Clipboard.SetTextBuf(PWideChar(string.Join(#$D#$A, Texts))); 206 | end; 207 | 208 | procedure TDefaultTreeMenu.MenuMainActionClick; 209 | begin 210 | if Assigned(FOnMainAction) and Assigned(FTree.FocusedNode) and 211 | (FTree.SelectedCount = 1) then 212 | FOnMainAction(FTree.FocusedNode); 213 | end; 214 | 215 | procedure TDefaultTreeMenu.NotifyPopup; 216 | begin 217 | // Allow the main action only a single node 218 | FMenuMainAction.Visible := Assigned(FOnMainAction) and (FTree.SelectedCount = 1); 219 | 220 | // Allow the node selected to explicitly disable the default menu 221 | if Assigned(Node) and (FTree is TVirtualStringTreeEx) and 222 | not TVirtualStringTreeEx(FTree).OverrideMainActionMenuEnabled(Node) then 223 | FMenuMainAction.Visible := False; 224 | 225 | // Enable regular copying when there are things to copy 226 | FMenuCopy.Visible := FTree.SelectedCount > 0; 227 | 228 | // Enable column-specific copying 229 | FPopupColumnIndex := Column; 230 | FMenuCopyColumn.Visible := (FTree.SelectedCount > 0) and (Column >= 0); 231 | 232 | if FMenuCopyColumn.Visible then 233 | FMenuCopyColumn.Caption := Format('Copy "%s"', 234 | [FTree.Header.Columns[Column].Text]); 235 | 236 | // Enable the separator if there are items to separate 237 | FMenuSeparator.Visible := (Assigned(Menu) or FMenuMainAction.Visible) and 238 | FMenuCopy.Visible; 239 | end; 240 | 241 | procedure TDefaultTreeMenu.RefreshShortcuts; 242 | begin 243 | if Assigned(FMenu) then 244 | FShortcuts := TMenuShortCut.Collect(FMenu.Items) 245 | else 246 | FShortcuts := nil; 247 | end; 248 | 249 | procedure TDefaultTreeMenu.SetMainActionText; 250 | begin 251 | FMenuMainAction.Caption := Value; 252 | end; 253 | 254 | end. 255 | --------------------------------------------------------------------------------