Code: Select all
fileselectfile Filename,3
; opens an existing root storage object in the file system
IPropertySetStorage := GetPropSetStorage(Filename)
If (!IPropertySetStorage)
{
MsgBox % "IPropertySetStorage ERROR " . Format("0x{:08X}", ErrorLevel)
ExitApp
}
Info := ""
; retrieves the property sets stored in this property set storage
PropertySets := EnumPropSetStorage(IPropertySetStorage)
For Each, STATPROPSETSTG in PropertySets
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(STATPROPSETSTG.fmtid) . "`n" ; format identifier (FMTID) of the property set
Info .= "STATPROPSETSTG.clsid " . StringFromCLSID(STATPROPSETSTG.clsid) . "`n"
Info .= "STATPROPSETSTG.grfFlags " . STATPROPSETSTG.grfFlags . "`n`n"
; opens a property set contained in the property set storage object
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, STATPROPSETSTG.fmtid)
If (IPropertyStorage)
{
; get statistical data in the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
; retrieves any existing string name for the specified property ID
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
; reads the property value
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
Info .= "`n`n`n----------------------`n`n`n`n"
}
; special-case handling for the UserDefined property set
CLSID := ""
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, CLSIDFromString("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", CLSID))
If (IPropertyStorage)
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(&CLSID) . "`n`n" ; format identifier (FMTID) of the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
ObjRelease(IPropertySetStorage)
FileOpen(A_Desktop . "\~tmp.txt", "w", "UTF-16").Write(Info)
Run % A_Desktop . "\~tmp.txt"
ExitApp
GetPropSetStorage(Filename, AccessMode := 0x10)
{
Local GUID := "", IPropertySetStorage := 0
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{0000013A-0000-0000-C000-000000000046}", "UPtr", &GUID, "UInt")
; StgOpenStorageEx function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380342(v=vs.85).aspx
; STGFMT_ANY = 4
ErrorLevel := DllCall("Ole32.dll\StgOpenStorageEx", "UPtr", &Filename, "UInt", AccessMode, "Int", 4, "UInt", 0, "UPtr", 0, "UPtr", 0, "UPtr", &GUID, "UPtrP", IPropertySetStorage, "UInt")
Return IPropertySetStorage
}
EnumPropSetStorage(IPropertySetStorage)
{
; IPropertySetStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379960(v=vs.85).aspx
Local IEnumSTATPROPSETSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage+0)+6*A_PtrSize), "UPtr", IPropertySetStorage, "UPtrP", IEnumSTATPROPSETSTG, "UInt"))
Return FALSE
; STATPROPSETSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380317(v=vs.85).aspx
Local PropertySets := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(PropertySets[i], "Buffer", 64) ; sizeof STATPROPSETSTG = 64 | PropertySets.Buffer = struct STATPROPSETSTG
; IEnumSTATPROPSETSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379202(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSETSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSETSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(PropertySets[i], "Buffer"), "UPtr", 0, "UInt"))
{
ObjRawSet(PropertySets[i], "fmtid", Address) ; FMTID STATPROPSETSTG.fmtid (FMTID of the current property set when created)
ObjRawSet(PropertySets[i], "clsid", Address+16) ; CLSID STATPROPSETSTG.clsid (CLSID associated with this property set when created or modified)
ObjRawSet(PropertySets[i], "grfFlags", NumGet(Address+32, "UInt")) ; DWORD STATPROPSETSTG.grfFlags (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380069(v=vs.85).aspx)
ObjRawSet(PropertySets[i], "mtime", Address+40) ; FILETIME STATPROPSETSTG.mtime (time in Universal Coordinated Time (UTC) when the property set was last modified)
ObjRawSet(PropertySets[i], "ctime", Address+48) ; FILETIME STATPROPSETSTG.ctime (time in UTC when this property set was created)
ObjRawSet(PropertySets[i], "atime", Address+56) ; FILETIME STATPROPSETSTG.atime (Time in UTC when this property set was last accessed)
ObjSetCapacity(PropertySets[i:=ObjPush(PropertySets, {Buffer: ""})], "Buffer", 64) ; new struct STATPROPSETSTG
}
ObjPop(PropertySets) ; remove the last STATPROPSETSTG structure
ObjRelease(IEnumSTATPROPSETSTG)
Return PropertySets
}
PropSetStorage_Open(IPropertySetStorage, FMTID, AccessMode := 0x10)
{
; IPropertySetStorage::Open method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379965(v=vs.85).aspx
Local IPropertyStorage := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage+0)+4*A_PtrSize), "UPtr", IPropertySetStorage, "UPtr", FMTID, "UInt", AccessMode, "UPtrP", IPropertyStorage, "UInt")
Return IPropertyStorage
}
EnumPropStorage(IPropertyStorage)
{
; IPropertyStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379973(v=vs.85).aspx
Local IEnumSTATPROPSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage+0)+11*A_PtrSize), "UPtr", IPropertyStorage, "UPtrP", IEnumSTATPROPSTG, "UInt"))
Return FALSE
; STATPROPSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380318(v=vs.85).aspx
Local StatisticalData := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(StatisticalData[i], "Buffer", A_PtrSize+8) ; sizeof STATPROPSTG = A_PtrSize+8 | StatisticalData.Buffer = struct STATPROPSTG
; IEnumSTATPROPSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379213(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(StatisticalData[i], "Buffer"), "UPtr", 0, "UInt"))
{
If (NumGet(Address+0))
ObjRawSet(StatisticalData[i], "lpwstrName", StrGet(NumGet(Address+0), "UTF-16")) ; LPWSTR STATPROPSTG.lpwstrName (optional string name associated with the property)
, DllCall("Ole32.dll\CoTaskMemFree", "UPtr", NumGet(Address+0)) ; must be freed using CoTaskMemFree
, NumPut(ObjGetAddress(StatisticalData[i], "lpwstrName"), Address+0) ; update STATPROPSTG.lpwstrName with the new pointer because we released the previous one
ObjRawSet(StatisticalData[i], "propid", NumGet(Address+A_PtrSize, "UInt")) ; PROPID STATPROPSTG.propid (32-bit identifier that uniquely identifies the property)
ObjRawSet(StatisticalData[i], "vt", NumGet(Address+A_PtrSize+4, "UShort")) ; VARTYPE STATPROPSTG.vt (property type)
ObjSetCapacity(StatisticalData[i:=ObjPush(StatisticalData, {Buffer: ""})], "Buffer", A_PtrSize+8) ; new struct STATPROPSTG
}
ObjPop(StatisticalData) ; remove the last STATPROPSTG structure
ObjRelease(IEnumSTATPROPSTG)
Return StatisticalData
}
PropStorage_Read(IPropertyStorage, PropID)
{
; PROPSPEC structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380070(v=vs.85).aspx
Local PROPSPEC := ""
VarSetCapacity(PROPSPEC, 2*A_PtrSize)
NumPut(1, &PROPSPEC+0, "UInt") ; ULONG PROPSPEC.ulKind
NumPut(PropID, &PROPSPEC + A_PtrSize, "UInt") ; PROPID PROPSPEC.propid
; PROPVARIANT structure
; https://docs.microsoft.com/es-es/windows/desktop/api/propidl/ns-propidl-tagpropvariant
Local PROPVARIANT := {Buffer: ""}
ObjSetCapacity(PROPVARIANT, "Buffer", A_PtrSize == 4 ? 16 : 24)
Local Address := ObjGetAddress(PROPVARIANT, "Buffer")
; IPropertyStorage::ReadMultiple method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379975(v=vs.85).aspx
; S_FALSE = 1 (valid syntax, but no properties were retrieved)
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage+0)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", Address, "UInt"))
Return FALSE
ObjRawSet(PROPVARIANT, "vt", NumGet(Address+0, "UInt"))
ObjRawSet(PROPVARIANT, "ptr", NumGet(Address+8, "UPtr"))
Return PROPVARIANT
}
PropStorage_ReadPropertyName(IPropertyStorage, PropID)
{
; IPropertyStorage::ReadPropertyNames method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379976(v=vs.85).aspx
Local Buffer := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage+0)+6*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UIntP", PropID, "UPtrP", Buffer, "UInt")
Local R := ""
If (!ErrorLevel) ; S_OK
R := StrGet(Buffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", Buffer)
Return R
}
StringFromCLSID(Address)
{
; StringFromGUID2 function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683893(v=vs.85).aspx
Local Buffer := ""
VarSetCapacity(Buffer, (38 + 1) * 2)
DllCall("Ole32.dll\StringFromGUID2", "UPtr", Address, "Str", Buffer, "Int", 38 + 1)
Return Buffer
}
CLSIDFromString(String, ByRef CLSID)
{
; CLSIDFromString function
; https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-clsidfromstring
VarSetCapacity(CLSID, 16)
Return DllCall("Ole32.dll\CLSIDFromString", "Str", String, "UPtr", &CLSID, "UInt") ? 0 : &CLSID
}
PropVariantClear(Address)
{
Return DllCall("Ole32.dll\PropVariantClear", "UPtr", IsObject(Address) ? ObjGetAddress(Address, "Buffer") : Address)
}
Code: Select all
global Gui, eFile, bFile, lList, Tab, eStr, eHex
, _hex := _sto := 0
MenuBar := MenuBarCreate()
menu_file := MenuCreate()
menu_file.Add("Open", "SelectFile")
menu_file.Add("Exit", "ExitApp")
MenuBar.Add("File", menu_file)
Gui := GuiCreate("-DPIScale -MinSize650x450 -Resize", "ADS Viewer | Flipeador")
Gui.SetFont("s9" , "Segoe UI")
Gui.MenuBar := MenuBar
eFile := Gui.AddEdit("x10 y10 w585 h21 c161616 +ReadOnly")
;SendMessage(0x1501, TRUE, &"Select the file to analyze..",, "ahk_id" . eFile.Hwnd)
bFile := Gui.AddButton("x600 y10 w40 h21", "•••")
bFile.OnEvent("Click", "SelectFile")
lList := Gui.AddListView("x10 y40 w630 h150", "Name|Size|Storage Object")
DllCall("UxTheme.dll\SetWindowTheme", "Ptr", lList.Hwnd, "Str", "Explorer", "UPtr", 0, "UInt")
lList.OnEvent("ItemSelect", "LVEvents")
Tab := Gui.AddTab3("x10 y200 w630 h240", "String|Hexadecimal|Storage Object")
Tab.OnEvent("Change", "TabEvent")
Tab.UseTab(1)
eStr := Gui.AddEdit("x20 y230 w610 h200 +ReadOnly")
Tab.UseTab(2)
eHex := Gui.AddEdit("x20 y230 w610 h200 +ReadOnly")
eHex.SetFont(, "Monospac821 BT")
Tab.UseTab(3)
eSto := Gui.AddEdit("x20 y230 w610 h200 +ReadOnly")
Gui.Show("w650 h450")
Gui.OnEvent("Close", () => ExitApp())
Return
SelectFile()
{
Local File := FileSelect(3)
If (!ErrorLevel)
{
lList.Delete(), Reset()
eFile.Text := File
Tab.Value := 1
Local Each := "", Stream := ""
For Each, Stream in EnumStreams(File)
lList.Add(, Stream.Name == "" ? "<unnamed>" : Stream.Name, StrFormatByteSize(Stream.Size), Stream.Name ~= "^\x5" ? "TRUE" : "FALSE")
lList.ModifyCol(1, "AutoHdr")
lList.ModifyCol(2, "AutoHdr")
}
}
Reset()
{
global _hex, _sto
eStr.Text := ""
eHex.Text := ""
_hex := 0
_sto := 0
}
ConvertEOL(Str, EOL := "`r`n")
{
Local Count := ""
Loop
Str := StrReplace(Str, "`r`n", "`n", Count)
Until (!Count)
Str := StrReplace(Str, "`r", "`n")
Return EOL == "`n" ? Str : StrReplace(Str, "`n", EOL)
}
TabEvent()
{
global _hex, _sto, eSto
Gui.Opt("+Disabled")
If (Tab.Value == 2 && !_hex)
{
Local Stream := lList.GetText(lList.GetNext())
, File := FileOpen(eFile.Text . (Stream == "<unnamed>" ? "" : ":" . Stream), "r")
If (!File)
{
MsgBox("The file couldn't be opened"), Gui.Opt("-Disabled")
Return
}
File.Seek(0)
Local HexTxt := "0001 ", Arr := [], i := 0
While (!File.AtEOF)
{
HexTxt .= Format("{:02X} ", Arr[ObjPush(Arr, File.ReadUChar())])
If (!Mod(i:=A_Index, 16))
{
HexTxt .= " "
For k, v in Arr
HexTxt .= v < 33 || v > 126 ? "." : Chr(v)
HexTxt .= "`r`n" . Format("{:04X} ", A_Index//16+1)
Arr := []
}
If (A_Index//16 > 10000)
{
HexTxt .= "`r`n ..."
Break
}
}
If (i:=Mod(i, 16))
{
HexTxt .= " "
Loop 16-i
HexTxt .= " "
For k, v in Arr
HexTxt .= !v || v == 10 || v == 13 ? "." : Chr(v)
}
_hex := 1, eHex.Text := HexTxt
}
If (Tab.Value == 3 && !_sto)
{
Local IPropertySetStorage := GetPropSetStorage(eFile.Text)
If (!IPropertySetStorage)
{
MsgBox "IPropertySetStorage ERROR " . Format("0x{:08X}", ErrorLevel), Gui.Opt("-Disabled")
Return
}
Local Info := ""
local PropertySets := EnumPropSetStorage(IPropertySetStorage)
For Each, STATPROPSETSTG in PropertySets
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(STATPROPSETSTG.fmtid) . "`n" ; format identifier (FMTID) of the property set
Info .= "STATPROPSETSTG.clsid " . StringFromCLSID(STATPROPSETSTG.clsid) . "`n"
Info .= "STATPROPSETSTG.grfFlags " . STATPROPSETSTG.grfFlags . "`n`n"
; opens a property set contained in the property set storage object
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, STATPROPSETSTG.fmtid)
If (IPropertyStorage)
{
; get statistical data in the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
; retrieves any existing string name for the specified property ID
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
; reads the property value
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
Info .= "`n`n`n----------------------`n`n`n`n"
}
; special-case handling for the UserDefined property set
CLSID := ""
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, CLSIDFromString("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", CLSID))
If (IPropertyStorage)
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(&CLSID) . "`n`n" ; format identifier (FMTID) of the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
ObjRelease(IPropertySetStorage)
_sto := 1, eSto.Text := ConvertEOL(Info)
}
Gui.Opt("-Disabled")
}
LVEvents(LV, Item, Selected)
{
Sleep(50)
Local Stream := LV.GetText(Item)
, File := FileOpen(eFile.Text . (Stream == "<unnamed>" ? "" : ":" . Stream), "r")
If (!File)
{
MsgBox "The file couldn't be opened"
Return
}
Gui.Opt("+Disabled")
Tab.Value := 1
Reset()
Local Buffer := "", Size := 0
eStr.Text := ConvertEOL(File.Read(10000))
Gui.Opt("-Disabled")
}
EnumStreams(File)
{
Local Streams := []
, WIN32_FIND_STREAM_DATA := ""
VarSetCapacity(WIN32_FIND_STREAM_DATA, 8 + (260 + 36) * 2)
Local Handle := DllCall("Kernel32.dll\FindFirstStreamW", "UPtr", &File, "UInt", 0, "UPtr", &WIN32_FIND_STREAM_DATA, "UInt", 0, "Ptr")
If (!Handle)
Return FALSE
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: SubStr(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), 2, -6)})
While (DllCall("Kernel32.dll\FindNextStreamW", "Ptr", Handle, "UPtr", &WIN32_FIND_STREAM_DATA, "Ptr"))
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: SubStr(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), 2, -6)})
Return Streams
} ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365741(v=vs.85).aspx
StrFormatByteSize(Number, Flags := 1)
{
Local Buffer := ""
VarSetCapacity(Buffer, 30 * 2, 0)
Local R := DllCall("Shlwapi.dll\StrFormatByteSizeEx", "Int64", Number, "UInt", Flags, "UPtr", &Buffer, "UInt", 30)
Return R == 0 ? StrGet(&Buffer, "UTF-16") : ""
} ;https://msdn.microsoft.com/en-us/library/windows/desktop/bb892884(v=vs.85).aspx
GetPropSetStorage(Filename, AccessMode := 0x10)
{
Local GUID := "", IPropertySetStorage := 0
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{0000013A-0000-0000-C000-000000000046}", "UPtr", &GUID, "UInt")
; StgOpenStorageEx function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380342(v=vs.85).aspx
; STGFMT_ANY = 4
ErrorLevel := DllCall("Ole32.dll\StgOpenStorageEx", "UPtr", &Filename, "UInt", AccessMode, "Int", 4, "UInt", 0, "UPtr", 0, "UPtr", 0, "UPtr", &GUID, "UPtrP", IPropertySetStorage, "UInt")
Return IPropertySetStorage
}
EnumPropSetStorage(IPropertySetStorage)
{
; IPropertySetStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379960(v=vs.85).aspx
Local IEnumSTATPROPSETSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage)+6*A_PtrSize), "UPtr", IPropertySetStorage, "UPtrP", IEnumSTATPROPSETSTG, "UInt"))
Return FALSE
; STATPROPSETSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380317(v=vs.85).aspx
Local PropertySets := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(PropertySets[i], "Buffer", 64) ; sizeof STATPROPSETSTG = 64 | PropertySets.Buffer = struct STATPROPSETSTG
; IEnumSTATPROPSETSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379202(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSETSTG)+3*A_PtrSize), "UPtr", IEnumSTATPROPSETSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(PropertySets[i], "Buffer"), "UPtr", 0, "UInt"))
{
ObjRawSet(PropertySets[i], "fmtid", Address) ; FMTID STATPROPSETSTG.fmtid (FMTID of the current property set when created)
ObjRawSet(PropertySets[i], "clsid", Address+16) ; CLSID STATPROPSETSTG.clsid (CLSID associated with this property set when created or modified)
ObjRawSet(PropertySets[i], "grfFlags", NumGet(Address+32, "UInt")) ; DWORD STATPROPSETSTG.grfFlags (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380069(v=vs.85).aspx)
ObjRawSet(PropertySets[i], "mtime", Address+40) ; FILETIME STATPROPSETSTG.mtime (time in Universal Coordinated Time (UTC) when the property set was last modified)
ObjRawSet(PropertySets[i], "ctime", Address+48) ; FILETIME STATPROPSETSTG.ctime (time in UTC when this property set was created)
ObjRawSet(PropertySets[i], "atime", Address+56) ; FILETIME STATPROPSETSTG.atime (Time in UTC when this property set was last accessed)
ObjSetCapacity(PropertySets[i:=ObjPush(PropertySets, {Buffer: ""})], "Buffer", 64) ; new struct STATPROPSETSTG
}
ObjPop(PropertySets) ; remove the last STATPROPSETSTG structure
ObjRelease(IEnumSTATPROPSETSTG)
Return PropertySets
}
PropSetStorage_Open(IPropertySetStorage, FMTID, AccessMode := 0x10)
{
; IPropertySetStorage::Open method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379965(v=vs.85).aspx
Local IPropertyStorage := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage)+4*A_PtrSize), "UPtr", IPropertySetStorage, "UPtr", FMTID, "UInt", AccessMode, "UPtrP", IPropertyStorage, "UInt")
Return IPropertyStorage
}
EnumPropStorage(IPropertyStorage)
{
; IPropertyStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379973(v=vs.85).aspx
Local IEnumSTATPROPSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+11*A_PtrSize), "UPtr", IPropertyStorage, "UPtrP", IEnumSTATPROPSTG, "UInt"))
Return FALSE
; STATPROPSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380318(v=vs.85).aspx
Local StatisticalData := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(StatisticalData[i], "Buffer", A_PtrSize+8) ; sizeof STATPROPSTG = A_PtrSize+8 | StatisticalData.Buffer = struct STATPROPSTG
; IEnumSTATPROPSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379213(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSTG)+3*A_PtrSize), "UPtr", IEnumSTATPROPSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(StatisticalData[i], "Buffer"), "UPtr", 0, "UInt"))
{
If (NumGet(Address))
ObjRawSet(StatisticalData[i], "lpwstrName", StrGet(NumGet(Address), "UTF-16")) ; LPWSTR STATPROPSTG.lpwstrName (optional string name associated with the property)
, DllCall("Ole32.dll\CoTaskMemFree", "UPtr", NumGet(Address)) ; must be freed using CoTaskMemFree
, NumPut(ObjGetAddress(StatisticalData[i], "lpwstrName"), Address) ; update STATPROPSTG.lpwstrName with the new pointer because we released the previous one
ObjRawSet(StatisticalData[i], "propid", NumGet(Address+A_PtrSize, "UInt")) ; PROPID STATPROPSTG.propid (32-bit identifier that uniquely identifies the property)
ObjRawSet(StatisticalData[i], "vt", NumGet(Address+A_PtrSize+4, "UShort")) ; VARTYPE STATPROPSTG.vt (property type)
ObjSetCapacity(StatisticalData[i:=ObjPush(StatisticalData, {Buffer: ""})], "Buffer", A_PtrSize+8) ; new struct STATPROPSTG
}
ObjPop(StatisticalData) ; remove the last STATPROPSTG structure
ObjRelease(IEnumSTATPROPSTG)
Return StatisticalData
}
PropStorage_Read(IPropertyStorage, PropID)
{
; PROPSPEC structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380070(v=vs.85).aspx
Local PROPSPEC := ""
VarSetCapacity(PROPSPEC, 2*A_PtrSize)
NumPut(1, &PROPSPEC, "UInt") ; ULONG PROPSPEC.ulKind
NumPut(PropID, &PROPSPEC + A_PtrSize, "UInt") ; PROPID PROPSPEC.propid
; PROPVARIANT structure
; https://docs.microsoft.com/es-es/windows/desktop/api/propidl/ns-propidl-tagpropvariant
Local PROPVARIANT := {Buffer: ""}
ObjSetCapacity(PROPVARIANT, "Buffer", A_PtrSize == 4 ? 16 : 24)
Local Address := ObjGetAddress(PROPVARIANT, "Buffer")
; IPropertyStorage::ReadMultiple method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379975(v=vs.85).aspx
; S_FALSE = 1 (valid syntax, but no properties were retrieved)
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", Address, "UInt"))
Return FALSE
ObjRawSet(PROPVARIANT, "vt", NumGet(Address, "UInt"))
ObjRawSet(PROPVARIANT, "ptr", NumGet(Address+8, "UPtr"))
Return PROPVARIANT
}
PropStorage_ReadPropertyName(IPropertyStorage, PropID)
{
; IPropertyStorage::ReadPropertyNames method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379976(v=vs.85).aspx
Local Buffer := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+6*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UIntP", PropID, "UPtrP", Buffer, "UInt")
Local R := ""
If (!ErrorLevel) ; S_OK
R := StrGet(Buffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", Buffer)
Return R
}
StringFromCLSID(Address)
{
; StringFromGUID2 function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683893(v=vs.85).aspx
Local Buffer := ""
VarSetCapacity(Buffer, (38 + 1) * 2)
DllCall("Ole32.dll\StringFromGUID2", "UPtr", Address, "Str", Buffer, "Int", 38 + 1)
Return Buffer
}
CLSIDFromString(String, ByRef CLSID)
{
; CLSIDFromString function
; https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-clsidfromstring
VarSetCapacity(CLSID, 16)
Return DllCall("Ole32.dll\CLSIDFromString", "Str", String, "UPtr", &CLSID, "UInt") ? 0 : &CLSID
}
PropVariantClear(Address)
{
Return DllCall("Ole32.dll\PropVariantClear", "UPtr", IsObject(Address) ? ObjGetAddress(Address, "Buffer") : Address)
}