EnumKnownFolders() v2

Post your working scripts, libraries and tools.
eugenesv
Posts: 171
Joined: 21 Dec 2015, 10:11

EnumKnownFolders() v2

Post by eugenesv » 06 Dec 2021, 05:12

While trying to select a localized version of a Desktop in a Window's path, I've stumbled on this nice EnumKnownFolders library that allows one to find such a name via some COM magic. Unfortunately, it's for AutoHotkey v1 :(, so I've updated it to v2 :)

Code: Select all

#Requires AutoHotKey v2.0-beta.3
; v1 @ autohotkey.com/boards/viewtopic.php?t=82925
; v2 @ autohotkey.com/boards/viewtopic.php?f=83&t=97513
global Borderless	:= True
  , WS_Caption   	:= 0x00C00000 ; Title bar (WS_BORDER + WS_DLGFRAME)
  , WS_SizeBox   	:= 0x00040000 ; Sizing border (=WS_THICKFRAME)
  , WS_Borderless	:= WS_Caption|WS_SizeBox ; BitwiseOR (logical inclusive OR)

KFProps := ["Name","GUID","CSIDL","LocalizedName","Category","Path"
  ,"ParsingName","Parent","RelativePath","Description","ToolTip","Icon"
  ,"Security","Attributes","Flags","Type"]
; --------------------------------------------------
KF := EnumKnownFolders()
; --------------------------------------------------
LVMainColName:= ["#","GUID","CSIDL","Name","Name (Localized)","Category"]
gMain := Gui()
mainStyle := ""
  , mainStyle .= " " (Borderless ? "-" WS_Borderless : "")
  ; , mainStyle .= " " "-Border"
  ; , mainStyle .= " " "+Resize"
gMain.Opt(mainStyle)
gMain.MarginX := 0, gMain.MarginY := 0 ; Disables padding
gMain.Title := "KnownFolders"
gMain.OnEvent("Close", gMainClose)
gMain.SetFont("s10", "Lucida Console")
lvS := "" ; ListView style
  , lvS .= ' ' "LV0x10000"	; Paints via double-buffering, which reduces flicker
  , lvS .= ' ' "LV0x100"  	; Enables flat scroll bars
  ; , lvS .= ' ' "x0 y0"  	; Disables left/top padding
gMainLV := gMain.Add("ListView", opt:="w1000 r30 Grid Count200" lvS, col:=LVMainColName)
gMainLV.OnEvent("DoubleClick", gMainLV_DoubleClick)
For i, P in KF {
  gMainLV.Add("",i,P["GUID"],P["CSIDL"],P["Name"],P["LocalizedName"],P["Category"])
}
Loop gMainLV.GetCount("Column")
  gMainLV.ModifyCol(A_Index, "AutoHdr")
gMainLV.ModifyCol(1, "Integer")
gMain.Show()
; --------------------------------------------------
LVPropColName := ["Property","Value"]
gProp := Gui()
gProp.Opt("+Owner" gMain.Hwnd)
gProp.OnEvent("Close" , gPropClose)
gProp.OnEvent("Escape", gPropClose)
gProp.SetFont("s10", "Lucida Console")
gPropLV := gProp.Add("ListView", "w1100 r20 Grid Count20", LVPropColName)
Return
; --------------------------------------------------
gMainLV_DoubleClick(gMainLV, rowNu) {
  gPropLV.Delete()
  FolderProps := KF[rowNu]
  for i, p in KFProps {
    field := FolderProps.Has(p) ? FolderProps[p] : ""
    gPropLV.Add("", p, field)
  }
  gPropLV.ModifyCol(1, "AutoHdr")
  gPropLV.ModifyCol(2, "AutoHdr")
  gProp.Title := "Properties"
  gMain.Opt("+Disabled")
  gProp.Opt("-Disabled")
  gProp.Show()
  }
; --------------------------------------------------
gPropClose(thisGui) {
  gMain.Opt("-Disabled")
  gProp.Opt("+Disabled")
  gProp.Hide()
  gMain.Show()
  }
gMainClose(thisGui) {
  ExitApp()
  }
; ==================================================
EnumKnownFolders() {
  Static Categories	:= ["VIRTUAL","FIXED","COMMON","PERUSER"]
  Static Δs        	:= [A_PtrSize,A_PtrSize,A_PtrSize, 16 ,A_PtrSize
    ,A_PtrSize,A_PtrSize,A_PtrSize,A_PtrSize,A_PtrSize
    , 4 ,4]
  Δ:=0, IKFM:=0, IKF:=0, KFID:=0, CID:=0, CSIDL:=0, KFD:=Buffer(40+(A_PtrSize*9), 0)
  if !(IKFM := IKnownFoldersManager_Create())
    return False
  if !IKnownFoldersManager_GetFolderIds(IKFM, &KFID, &CID)
    return False
  KnownFolders := Map()
  pKNID := KFID ; pointer to the current KNOWNFOLDERID
  Loop CID {
    if !IKnownFoldersManager_GetFolder(IKFM, pKNID, &IKF)
      Continue
    Properties := Map("GUID", GUID2→str(pKNID))
    if IKnownFoldersManager_FolderIdToCsidl(IKFM, pKNID, &CSIDL) {
      Properties["CSIDL"] := CSIDL
    } else {
      Properties["CSIDL"] := ""
    }
    if IKnownFolder_GetFolderDefinition(IKF, &KFD) {
      addr                       	:= NumGet(KFD, Δ:=0     , "UInt")
      Properties["Category"]     	:= addr ? Categories[addr]      : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[1] , "UPtr")
      Properties["Name"]         	:= addr ? StrGet(addr,"UTF-16") : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[2] , "UPtr")
      Properties["Description"]  	:= addr ? StrGet(addr,"UTF-16") : ""
      Properties["Parent"]       	:= GUID2→str(KFD.Ptr+(Δ+=Δs[3]))
      addr                       	:= NumGet(KFD, Δ+=Δs[4] , "UPtr")
      Properties["RelativePath"] 	:= addr ? StrGet(addr,"UTF-16") : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[5] , "UPtr")
      Properties["ParsingName"]  	:= addr ? StrGet(addr,"UTF-16") : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[6] , "UPtr")
      ToolTip                    	:= addr ? StrGet(addr,"UTF-16") : ""
      if (SubStr(ToolTip,1,1)    	= "@")
        ToolTip                  	:= GetMUIString(ToolTip)
      Properties["ToolTip"]      	:= ToolTip
      addr                       	:= NumGet(KFD, Δ+=Δs[7], "UPtr")
      LocalName                  	:= addr ? StrGet(addr,"UTF-16") : ""
      if (SubStr(LocalName,1,1)  	= "@")
        LocalName                	:= GetMUIString(LocalName)
      Properties["LocalizedName"]	:= LocalName
      addr                       	:= NumGet(KFD, Δ+=Δs[8], "UPtr")
      Properties["Icon"]         	:= addr ? StrGet(addr,"UTF-16") : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[9], "UPtr")
      Properties["Security"]     	:= addr ? StrGet(addr,"UTF-16") : ""
      addr                       	:= NumGet(KFD, Δ+=Δs[10], "UInt")
      Properties["Attributes"]   	:= Format("0x{:08X}",addr)
      addr                       	:= NumGet(KFD, Δ+=Δs[11], "UInt")
      Properties["Flags"]        	:= Format("0x{:08X}",addr)
      Properties["Type"]         	:= GUID2→str(KFD.Ptr+(Δ+=Δs[12]))
      FreeKnownFolderDefinitionFields(KFD.Ptr)
    }
    if IKnownFolder_GetPath(IKF, &Path)
      Properties["Path"] := Path
    KnownFolders[A_Index] := Properties
    ObjRelease(IKF)
    pKNID += 16 ; switch to the next KNOWNFOLDERID
  }
  DllCall("Ole32.dll\CoTaskMemFree", "Ptr",KFID)
  return KnownFolders
  }
IKnownFoldersManager_Create() { ; IKnownFoldersManager interface docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iknownfoldermanager
  ; Creates a IKNOWNFOLDERSMANAGER interface and returns its pointer on success.
  Static SCLSID_KnownFoldersManager := "{4DF0C730-DF9D-4AE3-9153-AA6B82E9795A}"
    ,    SIID_IKnownFoldersManager  := "{8BE2D872-86AA-4d47-B776-32CCA40C7018}"
  if !(IKFM := ComObject(SCLSID_KnownFoldersManager, SIID_IKnownFoldersManager))
    return False
  return IKFM
  }
IKnownFoldersManager_FolderIdToCsidl(IKFM, pKNID, &CSIDL) {
  ; Gets the legacy CSIDL value that is the equivalent of a given KNOWNFOLDERID docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iknownfoldermanager-folderidtocsidl
  IKFM0 := ComObjValue(IKFM)
  FolderIdToCsidl := NumGet(NumGet(IKFM0, "Uptr"), A_PtrSize*4, "UPtr")
  return !DllCall(FolderIdToCsidl, "Ptr",IKFM, "Ptr",pKNID, "Int*",&CSIDL, "UInt")
  }
IKnownFoldersManager_GetFolderIds(   IKFM, &KFID, &CID) {
  ; Gets an array of all registered known folder IDs. This can be used in enumerating all known folders. docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iknownfoldermanager-getfolderids
  IKFM0 := ComObjValue(IKFM)
  GetFolderIds := NumGet(NumGet(IKFM0, "Uptr"), A_PtrSize*5, "UPtr")
  return !DllCall(GetFolderIds, "Ptr",IKFM, "Ptr*",&KFID, "Int*",&CID, "UInt")
  }
IKnownFoldersManager_GetFolder(      IKFM, pFolderID, &IKF) {
  ; Gets an object that represents a known folder identified by its KNOWNFOLDERID. docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iknownfoldermanager-getfolder
  IKFM0 := ComObjValue(IKFM)
  GetFolder := NumGet(NumGet(IKFM0, "Uptr"), A_PtrSize*6, "UPtr")
  return !DllCall(GetFolder, "Ptr",IKFM, "Ptr",pFolderID, "Ptr*",&IKF, "UInt")
  }
IKnownFoldersManager_Release(        IKFM) { ; Releases the IKNOWNFOLDERSMANAGER interface
  return ObjRelease(IKFM)
  }

; IKnownFolder interface docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-iknownfolder; docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iknownfolder-getfolderdefinition
IKnownFolder_GetFolderDefinition(IKF, &KFD) {
  ; Retrieves a structure that contains the defining elements of a known folder, which includes the folder's category, name, path, description, tooltip, icon, and other properties.
  GetFolderDefinition := NumGet(NumGet(IKF, "Uptr"), A_PtrSize*11, "UPtr")
  KFD := Buffer(40+(A_PtrSize*9), 0)
  return !DllCall(GetFolderDefinition, "Ptr",IKF, "Ptr",KFD.Ptr, "UInt")
  }
IKnownFolder_GetPath(IKF, &Path, Flags := 0) { ; Retrieves the path of a known folder as a string. ; docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-iknownfolder-getpath
  Path:= "", KFP:=0
  GetPath	:= NumGet(NumGet(IKF, "Uptr"), A_PtrSize*6, "UPtr")
  HR     	:= DllCall(GetPath, "Ptr",IKF, "UInt",Flags, "Ptr*",&KFP, "UInt")
  if !(HR) {
    Path := StrGet(KFP, "UTF-16")
    DllCall("Ole32.dll\CoTaskMemFree", "Ptr",KFP)
  }
  return !HR
  }

; Auxiliary functions
ExpandEnvironmentStrings(Str) {
  Chars:=DllCall("ExpandEnvironmentStrings", "Ptr",StrPtr(Str), "Ptr",0  , "UInt",0   , "Int")
  if (Chars) {
    VarSetStrCapacity(&Exp, ++Chars << !!1)
    DllCall(     "ExpandEnvironmentStrings", "Ptr",StrPtr(Str), "Str",Exp, "UInt",Chars, "Int")
    return Exp
  }
  return Str
  }
FreeKnownFolderDefinitionFields(KFD) {
  Static OffSets := [A_PtrSize,A_PtrSize,A_PtrSize+16,A_PtrSize,A_PtrSize,A_PtrSize,A_PtrSize,A_PtrSize]
  Offset := 0
  for i, v in Offsets {
    Offset += v
    DllCall("Ole32.dll\CoTaskMemFree", "Ptr",NumGet(KFD + OffSet, "UPtr"))
  }
  }
GetMUIString(ResPath) {
  if InStr(ResPath, "%")
    ResPath := ExpandEnvironmentStrings(ResPath)
  ResStr:="", ResPtr:=0
  ResSplit := StrSplit(ResPath, [",", ";"], "@-")
  idRes2   := IsInteger(ResSplit[2]) ? ResSplit[2] : 0
  HMUI := DllCall("LoadLibraryEx", "Str",ResSplit[1], "Ptr",0, "UInt",0x00000020, "UPtr")
  Size := DllCall("LoadStringW"  , "Ptr",HMUI, "UInt",idRes2, "Ptr*",&ResPtr, "Int",0, "Int")
  if (Size)
    ResStr := StrGet(ResPtr, Size, "UTF-16")
  DllCall("FreeLibrary", "Ptr",HMUI)
  return (ResStr ? ResStr : ResPath)
  }
GUID2→str(PGUID) {
  SGUID := Buffer(128, 0)
  CC    := DllCall("Ole32.dll\StringFromGUID2", "Ptr",PGUID, "Ptr",SGUID.Ptr, "Int",64, "Int")
  return StrGet(SGUID.Ptr, CC, "UTF-16")
  }

Return to “Scripts and Functions (v2)”