My contribution to this beautiful topic:
sd := ComObjCreate("Shell.Explorer")
Lib.COM.ShowMembers(sd, "sd")
;###########################################################################
;###########################################################################
;##
;## Lib - COM - Component Object Model
;## by Andre Garcia - andre.garcia@xpnet.com.br
;##
;###########################################################################
;###########################################################################
;##
;## Requirements:
;## Previous Lib object where this object will be attached
;## For Debug, global methods deb and PCS
;##
;###########################################################################
;###########################################################################
; Attaches the Lib
Lib.COM := {}
;===========================================================================
;===========================================================================
;==
;== "Private" Error/Validate Methods
;==
;===========================================================================
;===========================================================================
;---------------------------------------------------------------------------
; Get COM Members
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; https://autohotkey.c...bers-itypeinfo/
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
; ; Original Code
; EnumComMembers(pti) {
; ;deb("EnumComMembers")
; static InvKind := {1:"method", 2:"get", 4:"put", 8:"putref"}
; if ComObjType(pti)=9 { ; if Com Object, get iTypeInfo Interface
; ptr := ComObjValue(pti)
; { ; Check if *ptr* has ITypeInfo Interface
; GetTypeInfoCount := vtable(ptr, 3)
; DllCall(GetTypeInfoCount, "ptr",ptr, "ptr*",HasITypeInfo)
; if Not HasITypeInfo {
; MsgBox ITypeInfo Interface not supported
; return
; }
; }
; GetTypeInfo := vTable(ptr, 4)
; if DllCall(GetTypeInfo, "ptr",ptr, "uint",0, "uint",0, "ptr*",pti)!=0
; return
; }
; { ; Com Methods
; GetTypeAttr := vTable(pti, 3)
; ReleaseTypeAttr := vTable(pti, 19)
; GetRefTypeOfImplType := vTable(pti, 8)
; GetRefTypeInfo := vTable(pti, 14)
; GetFuncDesc := vTable(pti, 5)
; ReleaseFuncDesc := vTable(pti, 20)
; GetDocumentation := vTable(pti, 12)
; }
; { ; get cFuncs (number of functions)
; DllCall(GetTypeAttr, "ptr",pti, "ptr*",typeAttr)
; cFuncs := NumGet(typeAttr+0, 40+A_PtrSize, "short")
; cImplTypes := NumGet(typeAttr+0, 44+A_PtrSize, "short")
; DllCall(ReleaseTypeAttr, "ptr",pti, "ptr",typeAttr)
; }
; if cImplTypes { ; Get Inherited Class (cImplTypes should be true)
; DllCall(GetRefTypeOfImplType, "ptr",pti, "int",0, "int*",pRefType)
; DllCall(GetRefTypeInfo, "ptr",pti, "ptr",pRefType, "ptr*", pti2)
; DllCall(GetDocumentation, "ptr",pti2, "int",-1, "ptr*",Name, "ptr",0, "ptr",0, "ptr",0) ; get Interface Name
; if StrGet(Name) != "IDispatch"
; t .= EnumComMembers(pti2) "`n"
; else
; ObjRelease(pti2)
; }
; Loop, %cFuncs% { ; get Member IDs
; DllCall(GetFuncDesc, "ptr",pti, "int",A_Index-1, "ptr*",FuncDesc)
; ID := NumGet(FuncDesc+0, "short") ; get Member ID
; n := NumGet(FuncDesc+0, 4+3*A_PtrSize, "int") ; get InvKind
; ; Args := NumGet(FuncDesc+0, 12+3*A_PtrSize, "short") ; get Num of Args
; ; Opt := NumGet(FuncDesc+0, 14+3*A_PtrSize, "short") ; get Num of Opt Args
; DllCall(ReleaseFuncDesc, "ptr",pti, "ptr",FuncDesc)
; DllCall(GetDocumentation, "ptr",pti, "int",ID, "ptr*",Name, "ptr",0, "ptr",0, "ptr",0)
; if StrGet(Name, "UTF-16") ; Exclude Members that didn't return a Name
; {
; ; t .= ID "`t" StrGet(Name, "UTF-16") "`t" InvKind[n] "`n"
; t .= ID "`t" InvKind[n] "`t" StrGet(Name, "UTF-16") "`n"
; }
; }
; { ; formatting & cleanup
; t := SubStr(t,1,-1)
; Sort, t, ND`n
; ObjRelease(pti)
; }
; return t
; }
; vTable(ptr, n) { ; see ComObjQuery documentation
; return NumGet(NumGet(ptr+0), n*A_PtrSize)
; }
;---------------------------------------------------------------------------
Lib.COM.GetMembers := Func("Lib_COM_GetMembers")
Lib_COM_GetMembers(this, pti, Arg_Members = -1) ; pti is ComObj pointer
{
; deb("Lib_COM_GetMembers")
; Create Members (if not created yet)
if (Arg_Members == -1)
{
Members := Object()
Members.Length := 0
Members.Errors := ""
}
else
Members := Arg_Members
;---------------------------------------------------------------------------
; ComObjType
;---------------------------------------------------------------------------
; VT_EMPTY = 0 ; No value
; VT_NULL = 1 ; SQL-style Null
; VT_I2 = 2 ; 16-bit signed int
; VT_I4 = 3 ; 32-bit signed int
; VT_R4 = 4 ; 32-bit floating-point number
; VT_R8 = 5 ; 64-bit floating-point number
; VT_CY = 6 ; Currency
; VT_DATE = 7 ; Date
; VT_BSTR = 8 ; COM string (Unicode string with length prefix)
; VT_DISPATCH = 9 ; COM object
; VT_ERROR = 0xA ; Error code (32-bit integer)
; VT_BOOL = 0xB ; Boolean True (-1) or False (0)
; VT_VARIANT = 0xC ; VARIANT (must be combined with VT_ARRAY or VT_BYREF)
; VT_UNKNOWN = 0xD ; IUnknown interface pointer
; VT_DECIMAL = 0xE ; (not supported)
; VT_I1 = 0x10 ; 8-bit signed int
; VT_UI1 = 0x11 ; 8-bit unsigned int
; VT_UI2 = 0x12 ; 16-bit unsigned int
; VT_UI4 = 0x13 ; 32-bit unsigned int
; VT_I8 = 0x14 ; 64-bit signed int
; VT_UI8 = 0x15 ; 64-bit unsigned int
; VT_INT = 0x16 ; Signed machine int
; VT_UINT = 0x17 ; Unsigned machine int
; VT_RECORD = 0x24 ; User-defined type -- NOT SUPPORTED
; VT_ARRAY = 0x2000 ; SAFEARRAY
; VT_BYREF = 0x4000 ; Pointer to another type of value
;
; VT_ARRAY and VT_BYREF are combined with another value (using bitwise OR)
; to specify the exact type. For instance, 0x2003 identifies a SAFEARRAY
; of 32-bit signed integers and 0x400C identifies a pointer to a VARIANT.
;---------------------------------------------------------------------------
; static InvKind := {1:"method", 2:"get", 4:"put", 8:"putref"}
; deb("ComObjType(pti) = " ComObjType(pti))
; if Com Object, get iTypeInfo Interface
if (ComObjType(pti) = 9)
{
ptr := ComObjValue(pti)
; Check if *ptr* has ITypeInfo Interface
GetTypeInfoCount := this.vTable(ptr, 3)
; deb("GetTypeInfoCount = " GetTypeInfoCount)
DllCall(GetTypeInfoCount, "ptr", ptr, "ptr*", HasITypeInfo)
; deb("HasITypeInfo = " HasITypeInfo)
if (! HasITypeInfo)
{
; MsgBox ITypeInfo Interface not supported
Members.Errors .= "ITypeInfo Interface not supported`n"
return Members
}
GetTypeInfo := this.vTable(ptr, 4)
; deb("GetTypeInfo = " GetTypeInfo)
Temp := DllCall(GetTypeInfo, "ptr", ptr, "uint", 0, "uint", 0, "ptr*", pti)
; deb("Temp = " Temp)
if (Temp != 0)
{
Members.Errors .= "GetTypeInfo != 0`n"
return Members
}
}
; Com Methods
GetTypeAttr := this.vTable(pti, 3)
ReleaseTypeAttr := this.vTable(pti, 19)
GetRefTypeOfImplType := this.vTable(pti, 8)
GetRefTypeInfo := this.vTable(pti, 14)
GetFuncDesc := this.vTable(pti, 5)
ReleaseFuncDesc := this.vTable(pti, 20)
GetDocumentation := this.vTable(pti, 12)
; deb("GetTypeAttr = " GetTypeAttr)
; deb("ReleaseTypeAttr = " ReleaseTypeAttr)
; deb("GetRefTypeOfImplType = " GetRefTypeOfImplType)
; deb("GetRefTypeInfo = " GetRefTypeInfo)
; deb("GetFuncDesc = " GetFuncDesc)
; deb("ReleaseFuncDesc = " ReleaseFuncDesc)
; deb("GetDocumentation = " GetDocumentation)
; get cFuncs (number of functions)
DllCall(GetTypeAttr, "ptr", pti, "ptr*", typeAttr)
cFuncs := NumGet(typeAttr + 0, 40 + A_PtrSize, "short")
cImplTypes := NumGet(typeAttr + 0, 44 + A_PtrSize, "short")
DllCall(ReleaseTypeAttr, "ptr", pti, "ptr", typeAttr)
; deb("cFuncs = " cFuncs)
; deb("cImplTypes = " cImplTypes)
; Get Inherited Class (cImplTypes should be true)
if (cImplTypes)
{
DllCall(GetRefTypeOfImplType, "ptr", pti, "int", 0, "int*", pRefType)
DllCall(GetRefTypeInfo, "ptr", pti, "ptr", pRefType, "ptr*", pti2)
DllCall(GetDocumentation, "ptr", pti2, "int", -1, "ptr*", Name, "ptr", 0, "ptr", 0, "ptr", 0) ; get Interface Name
; deb("Name = " Name, StrGet(Name), StrGet(Name) != "IDispatch")
; Reenter ?
if (StrGet(Name) != "IDispatch")
{
; deb("REENTER")
this.GetMembers(pti2, Members)
}
else
ObjRelease(pti2)
}
; get Member IDs
Loop, %cFuncs%
{
; deb("Loop, %cFuncs%", A_Index, cFuncs)
DllCall(GetFuncDesc, "ptr", pti, "int", A_Index - 1, "ptr*", FuncDesc)
ID := NumGet(FuncDesc + 0, "short") ; get Member ID
n := NumGet(FuncDesc + 0, 4 + 3 * A_PtrSize, "int") ; get InvKind
; Args := NumGet(FuncDesc + 0, 12 + 3 * A_PtrSize, "short") ; get Num of Args
; Opt := NumGet(FuncDesc + 0, 14 + 3 * A_PtrSize, "short") ; get Num of Opt Args
DllCall(ReleaseFuncDesc, "ptr", pti, "ptr", FuncDesc)
DllCall(GetDocumentation, "ptr", pti, "int", ID, "ptr*", Name, "ptr",0, "ptr",0, "ptr",0)
; deb("ID = " ID)
; deb("Name = " Name, StrGet(Name, "UTF-16"))
; Exclude Members that didn't return a Name
Member := {}
Member.ID := ID
Member.Name := StrGet(Name, "UTF-16")
; deb("Loop, %cFuncs%", A_Index, cFuncs, Member.Name)
if (Member.Name)
{
Member.Kind := this.GetInvKind(n)
; PCS(Member, "Member")
Members.Insert(Member)
Members.Length++
}
; break
}
; Cleanup
ObjRelease(pti)
; Sort Members
this.MembersSort(Members, "Lib_COM_OnMembersSort")
; Returns
; deb("Retuning Members")
return Members
}
;---------------------------------------------------------------------------
; vTable
;---------------------------------------------------------------------------
Lib.COM.vTable := Func("Lib_COM_vTable")
Lib_COM_vTable(this, ptr, n)
{
; deb("Lib_COM_vTable", "ptr = " ptr, "n = " n, "A_PtrSize = " A_PtrSize)
; See ComObjQuery documentation
return NumGet(NumGet(ptr+0), n * A_PtrSize)
}
;---------------------------------------------------------------------------
; GetInvKind
;---------------------------------------------------------------------------
Lib.COM.GetInvKind := Func("Lib_COM_GetInvKind")
Lib_COM_GetInvKind(this, n)
{
; deb("Lib_COM_GetInvKind", "n = " n, n = 1)
; static InvKind := {1:"method", 2:"get", 4:"put", 8:"putref"}
; return InvKind[n]
if (n = 1)
return "method"
if (n = 2)
return "get"
if (n = 4)
return "put"
if (n = 8)
return "putref"
return "unknown (" n ")"
}
;---------------------------------------------------------------------------
; OnSort Members
;---------------------------------------------------------------------------
Lib_COM_OnMembersSort(Member_I, Member_J)
{
; deb("Lib_COM_OnMembersSort", Member_I.ID, Member_J.ID)
; return -1
; ID
if (Member_I.ID < Member_J.ID)
return -1
if (Member_I.ID > Member_J.ID)
return 1
; Name
if (Member_I.Name < Member_J.Name)
return -1
if (Member_I.Name > Member_J.Name)
return 1
; Kind
;if (Member_I.Kind < Member_J.Kind)
; return -1
;if (Member_I.Kind > Member_J.Kind)
; return 1
; Equals !
return 0
}
;---------------------------------------------------------------------------
; Sort Members
;---------------------------------------------------------------------------
Lib.COM.MembersSort := Func("Lib_COM_MembersSort")
Lib_COM_MembersSort(this, Members, OnSort)
{
; deb("Lib_COM_MembersSort", "Members.Length = " Members.Length)
; return
M := Members.Length
; M := 5
Loop, % M - 1
{
I := A_Index
Loop, % M - I
{
J := A_Index + I
; deb(I, J)
Member_I := Members[I]
Member_J := Members[J]
Result := %OnSort%(Member_I, Member_J)
if (Result <= 0)
continue
Temp := Members[I]
Members[I] := Members[J]
Members[J] := Temp
}
}
}
;---------------------------------------------------------------------------
; Show COM Members
;---------------------------------------------------------------------------
Lib.COM.ShowMembers := Func("Lib_COM_ShowMembers")
Lib_COM_ShowMembers(this, pti, Caption = "") ; pti is ComObj pointer
{
; deb("Lib_COM_ShowMembers")
Members := this.GetMembers(pti)
; deb("Members.Length = " Members.Length)
; Loop
ToShow := "`n"
ToShow .= "=========== ShowMembers`n"
if (Caption != "")
{
ToShow .= "----------- Caption:`n"
ToShow .= Caption "`n"
ToShow .= "-----------`n"
}
if (Members.Errors != "")
{
ToShow .= "----------- Errors:`n"
ToShow .= Members.Errors
ToShow .= "-----------`n"
}
ToShow .= "Members.Length = " Members.Length "`n"
ToShow .= "Index`tID`tKind`tName`n"
ToShow .= "=====`t==`t====`t====`n"
Loop, % Members.Length
{
Member := Members[A_Index]
; deb("Member[" A_Index "], ID = " Member.ID ", Name = " Member.Name ", Kind = " Member.Kind)
; deb(Member.ID "`t" Member.Name "`t" Member.Kind)
ToShow .= A_Index "`t" Member.ID "`t" Member.Kind "`t" Member.Name "`n"
}
ToShow .= "===========`n"
deb(ToShow)
}
;###########################################################################
;###########################################################################
Output:
=========== ShowMembers
----------- Caption:
sd
-----------
Members.Length = 64
Index ID Kind Name
===== == ==== ====
1 -550 method Refresh
2 -525 get ReadyState
3 -515 get HWND
4 0 get Name
5 100 method GoBack
6 101 method GoForward
7 102 method GoHome
8 103 method GoSearch
9 104 method Navigate
10 105 method Refresh2
11 106 method Stop
12 200 get Application
13 201 get Parent
14 202 get Container
15 203 get Document
16 204 get TopLevelContainer
17 205 get Type
18 206 put Left
19 206 get Left
20 207 put Top
21 207 get Top
22 208 put Width
23 208 get Width
24 209 put Height
25 209 get Height
26 210 get LocationName
27 211 get LocationURL
28 212 get Busy
29 300 method Quit
30 301 method ClientToWindow
31 302 method PutProperty
32 303 method GetProperty
33 400 get FullName
34 401 get Path
35 402 put Visible
36 402 get Visible
37 403 put StatusBar
38 403 get StatusBar
39 404 put StatusText
40 404 get StatusText
41 405 put ToolBar
42 405 get ToolBar
43 406 put MenuBar
44 406 get MenuBar
45 407 put FullScreen
46 407 get FullScreen
47 500 method Navigate2
48 501 method QueryStatusWB
49 502 method ExecWB
50 503 method ShowBrowserBar
51 550 get Offline
52 550 put Offline
53 551 get Silent
54 551 put Silent
55 552 get RegisterAsBrowser
56 552 put RegisterAsBrowser
57 553 get RegisterAsDropTarget
58 553 put RegisterAsDropTarget
59 554 get TheaterMode
60 554 put TheaterMode
61 555 get AddressBar
62 555 put AddressBar
63 556 get Resizable
64 556 put Resizable
===========