So it deletes the user folder and these associated registry entries via WMI:
"HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{SID of User}"
"HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileGuid\{GUID}" SidString = {SID of User}
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\{SID of User}"
I'm self-taught and I'm sure there are tons of ways to simplify/improve this, but here you go.
Code: Select all
; created by skoliver1
; [email protected]
; inspired by Remove-UserProfile.ps1 Developer: Andrew Saraceni ([email protected])
; http gallery.technet.microsoft.com /scriptcenter/Remove-UserProfile-Remove-96e27a3b Broken Link for safety
#SingleInstance force
if A_OSVersion in WIN_XP
{
MsgBox, 262160, Profile Remover, This is not compatible with XP.`n`nThis script will now exit.
ExitApp
}
if not A_IsAdmin
{
Run *RunAs "%A_AhkPath%" "%A_ScriptFullPath%"
ExitApp
}
OnExit("Cleanup")
OnExit(ObjBindMethod(MyObject, "Exiting"))
SetBatchLines, -1
TempFolder = %A_Temp%\ProfileKiller
FileCreateDir %TempFolder%
Gui, Margin, 10, 10
Gui, Add, ListView, r10 w260 h180 Grid vVLV hwndHLV gColClick
, User Profiles|Last Modified|Size|SSID|Extra
Gui Add, Text, x276 y5, Select the profiles to remove and click Go.
Gui Add, Text, x276 y25 w220, Any rows highlighted in yellow are user folders that are invalid and are not in the registry.
Gui Add, Button, x276 y60 w50 gEngage, Go
gosub UserList
; Create a new instance of LV_Colors
CLV := New LV_Colors(HLV)
; Set the colors for selected rows
CLV.SelectionColors(0x0000FF, 0xFFFFFF)
If !IsObject(CLV) {
MsgBox, 0, ERROR, Couldn't create a new LV_Colors object!
ExitApp
}
; ====== Adjusting column widths ======
LV_ModifyCol(1, AutoHdr)
LV_ModifyCol(3, 80)
LV_ModifyCol(4, 0)
LV_ModifyCol(5, 0)
Gui Show, xCenter YCenter, Profile Remover
; Redraw the ListView after the first Gui, Show command to show the colors, if any.
WinSet, Redraw, , ahk_id %HLV%
gosub ExtraFolders
gosub FolderSize
Return
GuiClose:
GuiEscape:
ExitApp
UserList:
; ============== get list of logged in users to exclude from list ==================
RunWait cmd.exe /c quser > %TempFolder%\quser.txt,, Hide
FileRead LoadedProfiles, %TempFolder%\quser.txt
; ============== this piece gets the list of existing profiles from registry ==================
ProfileRegList = HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
Loop Reg, %ProfileRegList%, KR
{
if (A_LoopRegName = "S-1-5-18" or A_LoopRegName = "S-1-5-19" or A_LoopRegName = "S-1-5-20")
continue ; skip the above system accounts
SIDNames = %SIDNames%%A_LoopRegName%`n ; add the SID #s of these reg entries to a list
}
; ====== parse the SID list and get the username each corresponds to ======
Loop Parse, SIDNames, `n
{
if A_LoopField = ; if empty, move on
continue
RegRead LocalPath, %ProfileRegList%\%A_LoopField%, ProfileImagePath
LocalPath := StrReplace(LocalPath, "C:\Users\") ; remove the beginning of the path so it's just the username
Needle = %LocalPath%%A_Space% ; Username plus a space
if InStr(LoadedProfiles, Needle) ; if the Username+Space is found in the list of loaded users
continue ; skip it
LV_Add("",LocalPath,,, A_LoopField) ; this gives me a username and SID
NewLocalPath = %NewLocalPath%%LocalPath%`n
}
myUserList = %NewLocalPath%
; ====== get last modified time for folders ======
Loop Parse, myUserList, `n
{
if A_LoopField =
continue
FileGetTime LastMod, C:\Users\%A_LoopField%
FormatTime LastMod, %LastMod%, yyyy/M/d
LV_Modify(A_Index, , , LastMod, "<calculating>")
}
return
ExtraFolders:
CLV.OnMessage()
GuiControl, Focus, %HLV%
GuiControl, -Redraw, %HLV%
CLV.Clear(1, 1)
Loop Files, C:\Users\*, D
{
Needle = %A_LoopFileName%%A_Space% ; Username plus a space
if InStr(LoadedProfiles, Needle) ; if the Username+Space is found in the list of loaded users
continue ; skip it
if (A_LoopFileName = "All Users" or A_LoopFileName = "Default" or A_LoopFileName = "Default User" or A_LoopFileName = "Public" or A_LoopFileName = "Administrator")
continue
if !InStr(NewLocalPath, A_LoopFileName . "`n")
{
FileGetTime LastMod, C:\Users\%A_LoopFileName%
FormatTime LastMod, %LastMod%, yyyy/M/d
LV_Add("", A_LoopFileName, LastMod, "<calculating>",, "1")
Row := LV_GetCount()
CLV.Row(Row, 0xFFFF00, 0x000000) ; make it yellow
}
}
CLV.NoSort(False) ; this enables column re-sorting
GuiControl, +Redraw, %HLV%
return
; ====== calculate user folder sizes ======
FolderSize:
Loop
{
LV_GetText(Name, A_Index) ; Resume the search at the row after that found by the previous iteration.
if Name =
break
; ====== calculate the size. No offline files, directories or system files. The last two don't make much diff for size but speeds it up ======
if A_OSVersion in WIN_7,WIN_8,WIN_8.1,WIN_VISTA
RunWait cmd.exe /c dir C:\Users\%Name% /a:-D-S /S > %TempFolder%\%Name%-Size.txt,, Hide
else if (A_OSVersion >= "10.0.17763")
; the Offline file attribute was introduced in version 1809 of Windows 10, which is preferred, as it
; lets me calculate the actual "on disk" file size. Not just what is allocated by offline files in cloud-syncing programs.
RunWait cmd.exe /c dir C:\Users\%Name% /a:-O-D-S /S > %TempFolder%\%Name%-Size.txt,, Hide
else ; if W10 and lower than 1809
RunWait cmd.exe /c dir C:\Users\%Name% /a:-D-S /S > %TempFolder%\%Name%-Size.txt,, Hide
FileRead theText, %TempFolder%\%Name%-Size.txt
; ====== get beginning of location from bottom and trim ======
FileLineNum := InStr(theText, "File", , 0, 1)
Replacement1 := SubStr(theText, FileLineNum)
; ====== get end of byte #'s and trim ======
0Dir := InStr(Replacement1, "0 Dir",, 0) - 1
Replacement1 := SubStr(Replacement1, 1, 0Dir)
; ====== get rid of extra stuff ======
Replacement1 := StrReplace(Replacement1, "bytes", "")
Replacement1 := StrReplace(Replacement1, ",", "")
Replacement1 := StrReplace(Replacement1, "File(s) ", "")
Replacement1 := StrReplace(Replacement1, "`r`n", "")
Replacement1 := StrReplace(Replacement1, " ", "")
; ====== converstion from bytes to xxx.x MB or xx.xx GB ======
if (Replacement1 <= 1073741824) ; if < 1GB
{
Replacement1 := Replacement1 // 1024 / 1024 ; the individual "/" is not a mistake
Replacement1 := Round(Replacement1, 1)
LV_Modify(A_Index, , , , Replacement1 . " MB") ; modify the size field with calculated value
}
else
{
Replacement1 := Replacement1 // 1024 // 1024 / 1024
Replacement1 := Round(Replacement1, 2)
LV_Modify(A_Index, , , , Replacement1 . " GB")
}
}
return
; ====== this section is to re-color the "extra" user profiles if the columns are re-sorted ======
ColClick:
CLV.OnMessage()
GuiControl, Focus, %HLV%
GuiControl, -Redraw, %HLV%
CLV.Clear(1, 1)
Loop
{
LV_GetText(Name, A_Index) ; Resume the search at the row after that found by the previous iteration.
if Name =
break
LV_GetText(Extra, A_Index, 5)
if Extra = 1
CLV.Row(A_Index, 0xFFFF00, 0x000000)
else
CLV.Row(A_Index)
}
GuiControl, +Redraw, %HLV%
return
; ====== kill the profile ======
Engage:
RowNumber = 0 ; This causes the first loop iteration to start the search at the top of the list.
Loop
{
RowNumber := LV_GetNext(RowNumber) ; Resume the search at the row after that found by the previous iteration.
if not RowNumber
break ; The above returned zero, so there are no more selected rows.
LV_GetText(ListUserName, RowNumber)
LV_GetText(SSID, RowNumber, 4)
Profile = C:\Users\%ListUserName%
Gui, 2:add, progress, xCenter yCenter w500 h20 Range0-2
; ====== remove C:\Users\ folder ======
Gui, 2:Show,, Removing User folder
RunWait cmd /c "rmdir %Profile% /S /Q",, Hide
IfExist %Profile%
RunWait cmd /c "rmdir %Profile% /S /Q",, Hide
GuiControl, 2:, msctls_progress321, +1
; ====== use PS to remove profile from registry ======
Gui, 2:Show,, Removing Profile
RunWait Powershell -command "& {Get-WmiObject win32_userprofile | Where-Object {!$_.Special -and !$_.Loaded -and $_.LocalPath -like '%Profile%'} | RWMI}",, Hide
; ====== see if it's still there ======
RegRead LocalPath, %ProfileRegList%\%SSID%, ProfileImagePath
if !ErrorLevel ; and try again if it is
RunWait Powershell -command "& {Get-WmiObject win32_userprofile | Where-Object {!$_.Special -and !$_.Loaded -and $_.LocalPath -like '%Profile%'} | RWMI}",, Hide
Gui, 2:Destroy
IfExist %Profile%
{
Failure = 1
FolderMessage = %Profile% was not deleted
}
RegRead LocalPath, %ProfileRegList%\%SSID%, ProfileImagePath
if !ErrorLevel
{
Failure = 1
RegMessage = Registry profile was not removed
}
if Failure = 1
MsgBox %FolderMessage%`n%RegMessage%
else
LV_Delete(RowNumber)
}
gosub ColClick ; re-color the rows
return
; ====== cleanup the Temp folder ======
Cleanup(ExitReason, ExitCode)
{
}
class MyObject
{
Exiting()
{
Run cmd.exe /c rmdir "%LocalAppData%\Temp\ProfileKiller" /S /Q,, Hide
}
}
; ====== do not modify below this line ======
; credit to "just me", https://www.autohotkey.com/boards/memberlist.php?mode=viewprofile&u=148
; posting: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=1081
; ======================================================================================================================
; Namespace: LV_Colors
; Function: Individual row and cell coloring for AHK ListView controls.
; Tested with: AHK 1.1.23.05 (A32/U32/U64)
; Tested on: Win 10 (x64)
; Changelog:
; 1.1.04.01/2016-05-03/just me - added change to remove the focus rectangle from focused rows
; 1.1.04.00/2016-05-03/just me - added SelectionColors method
; 1.1.03.00/2015-04-11/just me - bugfix for StaticMode
; 1.1.02.00/2015-04-07/just me - bugfixes for StaticMode, NoSort, and NoSizing
; 1.1.01.00/2015-03-31/just me - removed option OnMessage from __New(), restructured code
; 1.1.00.00/2015-03-27/just me - added AlternateRows and AlternateCols, revised code.
; 1.0.00.00/2015-03-23/just me - new version using new AHK 1.1.20+ features
; 0.5.00.00/2014-08-13/just me - changed 'static mode' handling
; 0.4.01.00/2013-12-30/just me - minor bug fix
; 0.4.00.00/2013-12-30/just me - added static mode
; 0.3.00.00/2013-06-15/just me - added "Critical, 100" to avoid drawing issues
; 0.2.00.00/2013-01-12/just me - bugfixes and minor changes
; 0.1.00.00/2012-10-27/just me - initial release
; ======================================================================================================================
; CLASS LV_Colors
;
; The class provides six public methods to set individual colors for rows and/or cells, to clear all colors, to
; prevent/allow sorting and rezising of columns dynamically, and to deactivate/activate the message handler for
; WM_NOTIFY messages (see below).
;
; The message handler for WM_NOTIFY messages will be activated for the specified ListView whenever a new instance is
; created. If you want to temporarily disable coloring call MyInstance.OnMessage(False). This must be done also before
; you try to destroy the instance. To enable it again, call MyInstance.OnMessage().
;
; To avoid the loss of Gui events and messages the message handler might need to be set 'critical'. This can be
; achieved by setting the instance property 'Critical' ti the required value (e.g. MyInstance.Critical := 100).
; New instances default to 'Critical, Off'. Though sometimes needed, ListViews or the whole Gui may become
; unresponsive under certain circumstances if Critical is set and the ListView has a g-label.
; ======================================================================================================================
Class LV_Colors {
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; META FUNCTIONS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ===================================================================================================================
; __New() Create a new LV_Colors instance for the given ListView
; Parameters: HWND - ListView's HWND.
; Optional ------------------------------------------------------------------------------------------
; StaticMode - Static color assignment, i.e. the colors will be assigned permanently to the row
; contents rather than to the row number.
; Values: True/False
; Default: False
; NoSort - Prevent sorting by click on a header item.
; Values: True/False
; Default: True
; NoSizing - Prevent resizing of columns.
; Values: True/False
; Default: True
; ===================================================================================================================
__New(HWND, StaticMode := False, NoSort := True, NoSizing := True) {
If (This.Base.Base.__Class) ; do not instantiate instances
Return False
If This.Attached[HWND] ; HWND is already attached
Return False
If !DllCall("IsWindow", "Ptr", HWND) ; invalid HWND
Return False
VarSetCapacity(Class, 512, 0)
DllCall("GetClassName", "Ptr", HWND, "Str", Class, "Int", 256)
If (Class <> "SysListView32") ; HWND doesn't belong to a ListView
Return False
; ----------------------------------------------------------------------------------------------------------------
; Set LVS_EX_DOUBLEBUFFER (0x010000) style to avoid drawing issues.
SendMessage, 0x1036, 0x010000, 0x010000, , % "ahk_id " . HWND ; LVM_SETEXTENDEDLISTVIEWSTYLE
; Get the default colors
SendMessage, 0x1025, 0, 0, , % "ahk_id " . HWND ; LVM_GETTEXTBKCOLOR
This.BkClr := ErrorLevel
SendMessage, 0x1023, 0, 0, , % "ahk_id " . HWND ; LVM_GETTEXTCOLOR
This.TxClr := ErrorLevel
; Get the header control
SendMessage, 0x101F, 0, 0, , % "ahk_id " . HWND ; LVM_GETHEADER
This.Header := ErrorLevel
; Set other properties
This.HWND := HWND
This.IsStatic := !!StaticMode
This.AltCols := False
This.AltRows := False
This.NoSort(!!NoSort)
This.NoSizing(!!NoSizing)
This.OnMessage()
This.Critical := "Off"
This.Attached[HWND] := True
}
; ===================================================================================================================
__Delete() {
This.Attached.Remove(HWND, "")
This.OnMessage(False)
WinSet, Redraw, , % "ahk_id " . This.HWND
}
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PUBLIC METHODS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ===================================================================================================================
; Clear() Clears all row and cell colors.
; Parameters: AltRows - Reset alternate row coloring (True / False)
; Default: False
; AltCols - Reset alternate column coloring (True / False)
; Default: False
; Return Value: Always True.
; ===================================================================================================================
Clear(AltRows := False, AltCols := False) {
If (AltCols)
This.AltCols := False
If (AltRows)
This.AltRows := False
This.Remove("Rows")
This.Remove("Cells")
Return True
}
; ===================================================================================================================
; AlternateRows() Sets background and/or text color for even row numbers.
; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default background color
; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default text color
; Return Value: True on success, otherwise false.
; ===================================================================================================================
AlternateRows(BkColor := "", TxColor := "") {
If !(This.HWND)
Return False
This.AltRows := False
If (BkColor = "") && (TxColor = "")
Return True
BkBGR := This.BGR(BkColor)
TxBGR := This.BGR(TxColor)
If (BkBGR = "") && (TxBGR = "")
Return False
This["ARB"] := (BkBGR <> "") ? BkBGR : This.BkClr
This["ART"] := (TxBGR <> "") ? TxBGR : This.TxClr
This.AltRows := True
Return True
}
; ===================================================================================================================
; AlternateCols() Sets background and/or text color for even column numbers.
; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default background color
; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default text color
; Return Value: True on success, otherwise false.
; ===================================================================================================================
AlternateCols(BkColor := "", TxColor := "") {
If !(This.HWND)
Return False
This.AltCols := False
If (BkColor = "") && (TxColor = "")
Return True
BkBGR := This.BGR(BkColor)
TxBGR := This.BGR(TxColor)
If (BkBGR = "") && (TxBGR = "")
Return False
This["ACB"] := (BkBGR <> "") ? BkBGR : This.BkClr
This["ACT"] := (TxBGR <> "") ? TxBGR : This.TxClr
This.AltCols := True
Return True
}
; ===================================================================================================================
; SelectionColors() Sets background and/or text color for selected rows.
; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default selected background color
; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default selected text color
; Return Value: True on success, otherwise false.
; ===================================================================================================================
SelectionColors(BkColor := "", TxColor := "") {
If !(This.HWND)
Return False
This.SelColors := False
If (BkColor = "") && (TxColor = "")
Return True
BkBGR := This.BGR(BkColor)
TxBGR := This.BGR(TxColor)
If (BkBGR = "") && (TxBGR = "")
Return False
This["SELB"] := BkBGR
This["SELT"] := TxBGR
This.SelColors := True
Return True
}
; ===================================================================================================================
; Row() Sets background and/or text color for the specified row.
; Parameters: Row - Row number
; Optional ------------------------------------------------------------------------------------------
; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default background color
; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> default text color
; Return Value: True on success, otherwise false.
; ===================================================================================================================
Row(Row, BkColor := "", TxColor := "") {
If !(This.HWND)
Return False
If This.IsStatic
Row := This.MapIndexToID(Row)
This["Rows"].Remove(Row, "")
If (BkColor = "") && (TxColor = "")
Return True
BkBGR := This.BGR(BkColor)
TxBGR := This.BGR(TxColor)
If (BkBGR = "") && (TxBGR = "")
Return False
This["Rows", Row, "B"] := (BkBGR <> "") ? BkBGR : This.BkClr
This["Rows", Row, "T"] := (TxBGR <> "") ? TxBGR : This.TxClr
Return True
}
; ===================================================================================================================
; Cell() Sets background and/or text color for the specified cell.
; Parameters: Row - Row number
; Col - Column number
; Optional ------------------------------------------------------------------------------------------
; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> row's background color
; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name.
; Default: Empty -> row's text color
; Return Value: True on success, otherwise false.
; ===================================================================================================================
Cell(Row, Col, BkColor := "", TxColor := "") {
If !(This.HWND)
Return False
If This.IsStatic
Row := This.MapIndexToID(Row)
This["Cells", Row].Remove(Col, "")
If (BkColor = "") && (TxColor = "")
Return True
BkBGR := This.BGR(BkColor)
TxBGR := This.BGR(TxColor)
If (BkBGR = "") && (TxBGR = "")
Return False
If (BkBGR <> "")
This["Cells", Row, Col, "B"] := BkBGR
If (TxBGR <> "")
This["Cells", Row, Col, "T"] := TxBGR
Return True
}
; ===================================================================================================================
; NoSort() Prevents/allows sorting by click on a header item for this ListView.
; Parameters: Apply - True/False
; Default: True
; Return Value: True on success, otherwise false.
; ===================================================================================================================
NoSort(Apply := True) {
If !(This.HWND)
Return False
If (Apply)
This.SortColumns := False
Else
This.SortColumns := True
Return True
}
; ===================================================================================================================
; NoSizing() Prevents/allows resizing of columns for this ListView.
; Parameters: Apply - True/False
; Default: True
; Return Value: True on success, otherwise false.
; ===================================================================================================================
NoSizing(Apply := True) {
Static OSVersion := DllCall("GetVersion", "UChar")
If !(This.Header)
Return False
If (Apply) {
If (OSVersion > 5)
Control, Style, +0x0800, , % "ahk_id " . This.Header ; HDS_NOSIZING = 0x0800
This.ResizeColumns := False
}
Else {
If (OSVersion > 5)
Control, Style, -0x0800, , % "ahk_id " . This.Header ; HDS_NOSIZING
This.ResizeColumns := True
}
Return True
}
; ===================================================================================================================
; OnMessage() Adds/removes a message handler for WM_NOTIFY messages for this ListView.
; Parameters: Apply - True/False
; Default: True
; Return Value: Always True
; ===================================================================================================================
OnMessage(Apply := True) {
If (Apply) && !This.HasKey("OnMessageFunc") {
This.OnMessageFunc := ObjBindMethod(This, "On_WM_Notify")
OnMessage(0x004E, This.OnMessageFunc) ; add the WM_NOTIFY message handler
}
Else If !(Apply) && This.HasKey("OnMessageFunc") {
OnMessage(0x004E, This.OnMessageFunc, 0) ; remove the WM_NOTIFY message handler
This.OnMessageFunc := ""
This.Remove("OnMessageFunc")
}
WinSet, Redraw, , % "ahk_id " . This.HWND
Return True
}
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PRIVATE PROPERTIES +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Static Attached := {}
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PRIVATE METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
On_WM_NOTIFY(W, L, M, H) {
; Notifications: NM_CUSTOMDRAW = -12, LVN_COLUMNCLICK = -108, HDN_BEGINTRACKA = -306, HDN_BEGINTRACKW = -326
Critical, % This.Critical
If ((HCTL := NumGet(L + 0, 0, "UPtr")) = This.HWND) || (HCTL = This.Header) {
Code := NumGet(L + (A_PtrSize * 2), 0, "Int")
If (Code = -12)
Return This.NM_CUSTOMDRAW(This.HWND, L)
If !This.SortColumns && (Code = -108)
Return 0
If !This.ResizeColumns && ((Code = -306) || (Code = -326))
Return True
}
}
; -------------------------------------------------------------------------------------------------------------------
NM_CUSTOMDRAW(H, L) {
; Return values: 0x00 (CDRF_DODEFAULT), 0x20 (CDRF_NOTIFYITEMDRAW / CDRF_NOTIFYSUBITEMDRAW)
Static SizeNMHDR := A_PtrSize * 3 ; Size of NMHDR structure
Static SizeNCD := SizeNMHDR + 16 + (A_PtrSize * 5) ; Size of NMCUSTOMDRAW structure
Static OffItem := SizeNMHDR + 16 + (A_PtrSize * 2) ; Offset of dwItemSpec (NMCUSTOMDRAW)
Static OffItemState := OffItem + A_PtrSize ; Offset of uItemState (NMCUSTOMDRAW)
Static OffCT := SizeNCD ; Offset of clrText (NMLVCUSTOMDRAW)
Static OffCB := OffCT + 4 ; Offset of clrTextBk (NMLVCUSTOMDRAW)
Static OffSubItem := OffCB + 4 ; Offset of iSubItem (NMLVCUSTOMDRAW)
; ----------------------------------------------------------------------------------------------------------------
DrawStage := NumGet(L + SizeNMHDR, 0, "UInt")
, Row := NumGet(L + OffItem, "UPtr") + 1
, Col := NumGet(L + OffSubItem, "Int") + 1
, Item := Row - 1
If This.IsStatic
Row := This.MapIndexToID(Row)
; CDDS_SUBITEMPREPAINT = 0x030001 --------------------------------------------------------------------------------
If (DrawStage = 0x030001) {
UseAltCol := !(Col & 1) && (This.AltCols)
, ColColors := This["Cells", Row, Col]
, ColB := (ColColors.B <> "") ? ColColors.B : UseAltCol ? This.ACB : This.RowB
, ColT := (ColColors.T <> "") ? ColColors.T : UseAltCol ? This.ACT : This.RowT
, NumPut(ColT, L + OffCT, "UInt"), NumPut(ColB, L + OffCB, "UInt")
Return (!This.AltCols && !This.HasKey(Row) && (Col > This["Cells", Row].MaxIndex())) ? 0x00 : 0x20
}
; CDDS_ITEMPREPAINT = 0x010001 -----------------------------------------------------------------------------------
If (DrawStage = 0x010001) {
; LVM_GETITEMSTATE = 0x102C, LVIS_SELECTED = 0x0002
If (This.SelColors) && DllCall("SendMessage", "Ptr", H, "UInt", 0x102C, "Ptr", Item, "Ptr", 0x0002, "UInt") {
; Remove the CDIS_SELECTED (0x0001) and CDIS_FOCUS (0x0010) states from uItemState and set the colors.
NumPut(NumGet(L + OffItemState, "UInt") & ~0x0011, L + OffItemState, "UInt")
If (This.SELB <> "")
NumPut(This.SELB, L + OffCB, "UInt")
If (This.SELT <> "")
NumPut(This.SELT, L + OffCT, "UInt")
Return 0x02 ; CDRF_NEWFONT
}
UseAltRow := (Item & 1) && (This.AltRows)
, RowColors := This["Rows", Row]
, This.RowB := RowColors ? RowColors.B : UseAltRow ? This.ARB : This.BkClr
, This.RowT := RowColors ? RowColors.T : UseAltRow ? This.ART : This.TxClr
If (This.AltCols || This["Cells"].HasKey(Row))
Return 0x20
NumPut(This.RowT, L + OffCT, "UInt"), NumPut(This.RowB, L + OffCB, "UInt")
Return 0x00
}
; CDDS_PREPAINT = 0x000001 ---------------------------------------------------------------------------------------
Return (DrawStage = 0x000001) ? 0x20 : 0x00
}
; -------------------------------------------------------------------------------------------------------------------
MapIndexToID(Row) { ; provides the unique internal ID of the given row number
SendMessage, 0x10B4, % (Row - 1), 0, , % "ahk_id " . This.HWND ; LVM_MAPINDEXTOID
Return ErrorLevel
}
; -------------------------------------------------------------------------------------------------------------------
BGR(Color, Default := "") { ; converts colors to BGR
Static Integer := "Integer" ; v2
; HTML Colors (BGR)
Static HTML := {AQUA: 0x00FFFF, BLACK: 0x000000, RED: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080, GREEN: 0x008000
, LIME: 0x00FF00, MAROON: 0x800000, NAVY: 0x000080, OLIVE: 0x808000, PURPLE: 0x800080, BLUE: 0x0000FF
, SILVER: 0xC0C0C0, TEAL: 0x008080, WHITE: 0xFFFFFF, YELLOW: 0xFFFF00}
If Color Is Integer
Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16)
Return (HTML.HasKey(Color) ? HTML[Color] : Default)
}
}