Jump to content

Hooking into the IDispatch interface.


monoceres
 Share

Recommended Posts

$msgbox = MessageBox()

$msgbox.flag = 64
$msgbox.title = "Important Announcement"
$msgbox.text = "Object Orientation + AutoIt = True"
$msgbox.Display()

Func MessageBox()
    ; Construct a lookup table with properties and methods (methods are marked with @
    Local $members[4][2] = [["@Display", "MessageBox_Display"],["flag", 0],["title", ""],["text", ""]]
    Return CreateObject($members)
EndFunc ;==>MessageBox

Func MessageBox_Display($self)
    Return MsgBox($self.flag, $self.title, $self.text)
EndFunc ;==>MessageBox_Display

AWESOME work monoceres!!! ;)

This brings truly new level of power to Autoit!

I'm looking forward to see what Autoit developers say about it

and the effective way how to integrate this all stuff into Autoit syntax.

Question: Can this be used to work with IDispatch objects in GDI+?

EDIT: Your latest example (File object) worked on my WINXP compiled/uncompiled fine.

Edited by Zedna
Link to comment
Share on other sites

  • Replies 70
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

ProgAndy have done some amazing work. Fixing all shortcomings with my implementation. When presenting this everything must be perfect.

Don't you think they might have seen this already?:evil:

Edit: Sorry: This is great! ;)

Do you already have some other ideas what you can do with this? Besides OO.

Edited by Kip
Link to comment
Share on other sites

With the logic you are programming aren't you coming close to integrate .NET Classes and objects?

Just a bunch of ICorRuntimeHost and other Ixxx interfaces and you come close.

http://69.10.233.10/KB/cs/unmanagedtomanaged.aspx

http://msdn.microsoft.com/en-us/library/sd10k43k%28VS.71%29.aspx

http://www.mikevdm.com/Blog/tabid/55/EntryId/19/Using-NET-Classes-from-unmanaged-C-with-COM-Interop-What-Another-Post-About-This.aspx

edit: Some additional references (it will be tough)

http://msdn.microsoft.com/en-us/magazine/cc301479.aspx

http://msdn.microsoft.com/en-us/library/ms973872.aspx

http://msdn.microsoft.com/en-us/library/ms164320.aspx

edit 2: Just found a small example from another language (Clarion)

http://www.icetips.com/showarticle.php?articleid=416

Edited by junkew
Link to comment
Share on other sites

Thank for cool IDispath hooks sharing. Is there possibility to translate this code into AutoIt (registering in ROT)?

HRESULT hr;
    IMoniker* pMoniker = NULL;
    IRunningObjectTable* pROT = NULL;
    if(GetRunningObjectTable(0, &pROT) == S_OK)
    {
        CString str;
        str.Format(TEXT("AutoItObject %08x pid %08x"), (DWORD_PTR) pUnk, GetCurrentProcessId());
        if(CreateItemMoniker(L"AutoItObject", str.AllocSysString(), &pMoniker) == S_OK)
        {
            hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE/*0*/, pUnk, pMoniker, dwReg);
            pMoniker->Release();
        }
        pROT->Release();
    }

If so, then new AutoIt object could be accessible from other programs according

this

There are also the samples of Interprocess Communication Using the Running Object Table. For example here

The point of world view

Link to comment
Share on other sites

Thank for cool IDispath hooks sharing. Is there possibility to translate this code into AutoIt (registering in ROT)?

HRESULT hr;
    IMoniker* pMoniker = NULL;
    IRunningObjectTable* pROT = NULL;
    if(GetRunningObjectTable(0, &pROT) == S_OK)
    {
        CString str;
        str.Format(TEXT("AutoItObject %08x pid %08x"), (DWORD_PTR) pUnk, GetCurrentProcessId());
        if(CreateItemMoniker(L"AutoItObject", str.AllocSysString(), &pMoniker) == S_OK)
        {
            hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE/*0*/, pUnk, pMoniker, dwReg);
            pMoniker->Release();
        }
        pROT->Release();
    }

If so, then new AutoIt object could be accessible from other programs according

this

There are also the samples of Interprocess Communication Using the Running Object Table. For example here

This should be possible to implement, but first we (monoceres, trancexx and me) have to finish the Objects for AutoIt-internal use :D. Also, you need an additional UDF for this code in order to be able to call functions of non-IDispatch interfaces. I have the basics for that in my collection, but still it will be much work. Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

Link to comment
Share on other sites

I hope you don't mind, but I've edited it a little bit and added some of my own functions:

#include <Array.au3>

Global $hOle32 = DllOpen("Ole32.dll")
DllCall($hOle32, "long", "CoInitializeEx", "ptr", 0, "dword", 2)

Global Const $hOLEOUT = DllOpen("oleaut32.dll")


; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ___ConvertPtrToIDispatch($pIDispatch)
    ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
    ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
    Local $aCall = DllCall("kernel32.dll", "none", "RtlMoveMemory", _
    "idispatch*", 0, _
    "ptr*", $pIDispatch, _
    "dword", 4)

    If @error Then
    Return SetError(1, 0, 0)
    EndIf

    Return $aCall[1]

EndFunc ;==>ConvertPtrToIDispatch

Func ___ConvertIDispatchToPtr($oIDispatch)

    Local $aCall = DllCall("kernel32.dll", "none", "RtlMoveMemory", _
    "ptr*", 0, _
    "idispatch*", $oIDispatch, _
    "dword", DllStructGetSize(DllStructCreate("ptr")))

    If @error Then
    Return SetError(1, 0, 0)
    EndIf

    Return $aCall[1]

EndFunc ;==>ConvertIDispatchToPtr

; Sets the MEM_EXECUTE_READWRITE flag on the specified memory. Use with care, I use because I'm lazy.
Func ___UnprotectMemory($pMem, $iSize)
    DllCall("Kernel32.dll", "int", "VirtualProtect", "ptr", $pMem, "long", $iSize, "dword", 0x40, "dword*", 0)
EndFunc ;==>UnprotectMemory

; Returns the pointer the passed pointer points to ;)
Func ___DereferencePointer($pPointer, $sType = "ptr")
    $hStruct = DllStructCreate($sType, $pPointer)
    Return DllStructGetData($hStruct, 1)
EndFunc ;==>DereferencePointer


; Moves the vtable to a new position. useful if you want to add more entries.
Func ___RelocateVTable($pObj, $pNew, $iVTable_Size)
    $hVTable = DllStructCreate("ptr", $pObj)
    DllCall("kernel32.dll", "none", "RtlMoveMemory", "ptr", $pNew, "ptr", DllStructGetData($hVTable, 1), "dword", $iVTable_Size)
    DllStructSetData($hVTable, 1, $pNew)
EndFunc ;==>RelocateVTable

; Allocate memory on the heap
Func ___DynAlloc($dwSize)
    $hHeap = DllCall("Kernel32.dll", "ptr", "GetProcessHeap")
    $hHeap = $hHeap[0]
    $hMem = DllCall("Kernel32.dll", "ptr", "HeapAlloc", "ptr", $hHeap, "dword", 0x8, "dword", $dwSize)
    DllCall("Kernel32.dll", "none", "CloseHandle", "ptr", $hHeap)
    Return $hMem[0]
EndFunc ;==>DynAlloc

; Fantastic function. Does not ask how many bytes that needs to be freed
Func ___DynFree($hMem)
    $hHeap = DllCall("Kernel32.dll", "ptr", "GetProcessHeap")
    $hHeap = $hHeap[0]
    $hMem = DllCall("Kernel32.dll", "int", "HeapFree", "ptr", $hHeap, "dword", 0, "ptr", $hMem)
    DllCall("Kernel32.dll", "none", "CloseHandle", "ptr", $hHeap)
    Return $hMem[0]
EndFunc ;==>DynFree




; Takes a pointer to the v-table in a class and replaces specified pointer in it to a new one.
Func ___ReplaceVTableEntry($pVTable, $iOffset, $pNew)
    ; Dereference the pointer


    $pEntry = ___DereferencePointer($pVTable) + $iOffset
    ; Make the memory free for all. Yay!
    ___UnprotectMemory($pEntry, DllStructGetSize(DllStructCreate("ptr")))
    $hEntry = DllStructCreate("ptr", $pEntry)
    $pOld = DllStructGetData($hEntry, 1)
    DllStructSetData($hEntry, 1, $pNew)
    Return $pOld
EndFunc ;==>ReplaceVTableEntry



Func ___CreateDynamicString($sString)
    $pDynamic = ___DynAlloc(StringLen($sString) + 1)
    DllStructSetData(DllStructCreate("char[" & StringLen($sString) + 1 & "]", $pDynamic), 1, $sString)
    Return $pDynamic
EndFunc ;==>CreateDynamicString



Func ___AddMembersToLookupTable($pObj, $aNames)
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
    
    ; Set point in vtable
    $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObj) + 4 * 7)


    If DllStructGetData($hVTable_Entry, 1) <> 0 Then

    $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))

    Local $aTemp[UBound($aNames) + DllStructGetData($hHeader, 1)][2]
    For $i = 0 To DllStructGetData($hHeader, 1) - 1
    $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, (DllStructGetData($hVTable_Entry, 1) + DllStructGetSize(DllStructCreate("ptr"))) + $LOOKUP_TABLE_ENTRY_SIZE * $i)
    $aTemp[$i][0] = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "name"))
    If StringLeft($aTemp[$i][0], 1) = "@" Or StringLeft($aTemp[$i][0], 1) = "~" or StringLeft($aTemp[$i][0], 1) = "*" Then
    $aTemp[$i][1] = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "value"))
    Else
    $aTemp[$i][1] = ___COMVariantToValue(DllStructGetData($hCurrent_Entry, "value"))
    EndIf

    Next
    For $i = 0 To UBound($aNames) - 1
    For $j = 0 To UBound($aTemp) - 1
    If $aTemp[$j][0] = $aNames[$i][0] Then
    $aTemp[$j][0] = $aNames[$i][0]
    $aTemp[$j][1] = $aNames[$i][1]
    ExitLoop
    ElseIf $aTemp[$j][0] = "" Then
    $aTemp[$j][0] = $aNames[$i][0]
    $aTemp[$j][1] = $aNames[$i][1]
    ExitLoop
    EndIf
    Next
    Next

    For $i = UBound($aTemp) - 1 To 0 Step -1
    If $aTemp[$i][0] <> "" Then ExitLoop
    _ArrayDelete($aTemp, $i)
    Next


    $aNames = $aTemp


    ___DynFree(DllStructGetData($hVTable_Entry, 1))

    EndIf

    ; Create dynamic memory for new lookup table
    $pMem = ___DynAlloc(DllStructGetSize(DllStructCreate("ptr")) + (UBound($aNames) * $LOOKUP_TABLE_ENTRY_SIZE))
    ; Create lookup table, first element is number of element
    ; Must be sorted!
    $hLookupTable = DllStructCreate("int;byte[" & $LOOKUP_TABLE_ENTRY_SIZE & "]", $pMem)
    ; Set size of lookup table
    DllStructSetData($hLookupTable, 1, UBound($aNames))
    ; Modify vtable to point to the lookup table
;~ MsgBox(0,"", $mem)
    DllStructSetData($hVTable_Entry, 1, $pMem)


    For $i = 0 To UBound($aNames) - 1
    $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, DllStructGetPtr($hLookupTable, 2) + $LOOKUP_TABLE_ENTRY_SIZE * $i)

    If StringLeft($aNames[$i][0], 1) = "@" Or StringLeft($aNames[$i][0], 1)="~" or StringLeft($aNames[$i][0], 1)="*" Then ; This is a method
    DllStructSetData($hCurrent_Entry, "name", ___CreateDynamicString($aNames[$i][0]))
    DllStructSetData($hCurrent_Entry, "value", ___CreateDynamicString($aNames[$i][1]))
    Else ; It's a property then.
    $pVariant = ___DynAlloc(16)
    ___ValueToCOMVariant($pVariant, $aNames[$i][1])
    DllStructSetData($hCurrent_Entry, "name", ___CreateDynamicString($aNames[$i][0]))
    DllStructSetData($hCurrent_Entry, "value", $pVariant)
    EndIf

    Next
EndFunc ;==>AddMembersToLookupTable

Func ___ChrPtrToString($pString)
    $iLength = ___strlen($pString)
    $hString = DllStructCreate("char[" & $iLength + 1 & "]", $pString)
    Return DllStructGetData($hString, 1)
EndFunc ;==>ChrPtrToString


Func ___FindNameInLookupTable($pObj, $sName)
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
    
    $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObj) + DllStructGetSize(DllStructCreate("ptr")) * 7) ; sizeof(ptr)*(num entries in idispatch)
    $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))
    $iLookupTable_Size = DllStructGetData($hHeader, 1)
    For $i = 0 To $iLookupTable_Size - 1
    $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, (DllStructGetData($hVTable_Entry, 1) + DllStructGetSize(DllStructCreate("ptr"))) + $LOOKUP_TABLE_ENTRY_SIZE * $i)
    If $sName = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "name")) Then Return $i
    Next
    Return -1
EndFunc ;==>FindNameInLookupTable

Func ___IDToValue($pObj, $iId,$sField="value")
;~ MsgBox(0,"",$id)
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
    
    $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObj) + DllStructGetSize(DllStructCreate("ptr")) * 7)
    $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))
    $iLookupTable_Size = DllStructGetData($hHeader, 1)


    If $iId < 0 Or $iId >= $iLookupTable_Size Then Return ""

    $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, (DllStructGetData($hVTable_Entry, 1) + DllStructGetSize(DllStructCreate("ptr"))) + $LOOKUP_TABLE_ENTRY_SIZE * $iId)

    $sMember_Name = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "name"))
    If StringLeft($sMember_Name, 1) = "@" Or StringLeft($sMember_Name, 1)="~" or StringLeft($sMember_Name, 1)="*" Then
    Return ___ChrPtrToString(DllStructGetData($hCurrent_Entry, $sField))
    Else
    Return DllStructGetData($hCurrent_Entry, $sField)
    EndIf
EndFunc ;==>IDToValue






;Func ForceExit($iExitCode=0)
    ;DllCall("Kernel32.dll", "none", "ExitProcess", "dword", $iExitCode)
;EndFunc



Func ___VTType2AutoitType($iVT_Type)
    
    Local $VT_BSTR = 8
    Local $VT_I2 = 2
    Local $VT_I4 = 3
    Local $VT_R8 = 5
    Local $VT_I1 = 16
    Local $VT_DISPATCH = 9
    
    ;ConsoleWrite("! " & $iVT_Type & @CRLF)
    Switch $iVT_Type
    Case $VT_I1
    Return "byte"
    Case $VT_I2
    Return "short"
    Case $VT_I4
    Return "int"
    Case $VT_BSTR
    Return "wstr"
    Case $VT_R8
    Return "double"
    Case $VT_DISPATCH
    Return "idispatch"
    EndSwitch
EndFunc ;==>VTType2AutoitType

Func ___AutoitType2VTType($sAutoit_Type)
    
    Local $VT_BSTR = 8
    Local $VT_I2 = 2
    Local $VT_I4 = 3
    Local $VT_R8 = 5
    Local $VT_I1 = 16
    Local $VT_DISPATCH = 9
    Local $VT_PTR = 26
    
    Switch $sAutoit_Type
    Case "byte"
    Return $VT_I1
    Case "short"
    Return $VT_I2
    Case "int"
    Return $VT_I4
    Case "wstr"
    Return $VT_BSTR
    Case "double"
    Return $VT_R8
    Case "ptr"
    Return $VT_PTR
    Case "idispatch"
    Return $VT_DISPATCH
    EndSwitch
EndFunc ;==>AutoitType2VTType


; Find out length of string. I do not trust autoit to do this.
Func ___wcslen($pWString)
    $aCall = DllCall("ntdll.dll", "dword:cdecl", "wcslen", "ptr", $pWString)
    Return $aCall[0]
EndFunc ;==>wcslen

; Find out length of string. I do not trust autoit to do this.
Func ___strlen($pString)
    $aCall = DllCall("ntdll.dll", "dword:cdecl", "strlen", "ptr", $pString)
    Return $aCall[0]
EndFunc ;==>strlen

Func ___SysAllocString($sString)
    $aCall = DllCall("oleaut32.dll", "ptr", "SysAllocString", "wstr", $sString)
    Return $aCall[0]
EndFunc ;==>SysAllocString

Func ___SysFreeString($pBStr)
    $aCall = DllCall("oleaut32.dll", "dword", "SysAllocString", "ptr", $pBStr)
    Return $aCall[0]
EndFunc ;==>SysFreeString




Func ___COMVariantToValue($pVariant)
    
    Local $tagVARIANT = "ushort vt;ushort r1;ushort r2;ushort r3;uint64 data"
    Local $hVariant = DllStructCreate($tagVARIANT, $pVariant)
    ; Translate the vt id to a autoit dllcall type
    $sType = ___VTType2AutoitType(DllStructGetData($hVariant, "vt"))


    If $sType = "wstr" Then
    $pString = DllStructCreate("ptr", DllStructGetPtr($hVariant, "data"))
    ; Getting random crashes when trusting autoit to automatically use right size.
    ; doing it myself instead (also, it should be a BSTR, but it's not. Is autoit not obeying the rules!?
    $iString_Size = ___wcslen(DllStructGetData($pString, 1))

    ; Sorry trancexx, doesn't seem to work on large strings (crashes like crazy when trying to use on 1 MB string)
    ;$tSub = DllStructCreate("dword", DllStructGetData($str_ptr, 1) - 4) ; <- move pointer back 4 bytes!

    $hData = DllStructCreate("wchar[" & $iString_Size & "]", DllStructGetData($pString, 1))

    ElseIf $sType = "idispatch" Then

    Return ___ConvertPtrToIDispatch(DllStructGetData(DllStructCreate("ptr", DllStructGetPtr($hVariant, "data")), 1))

    Else
    $hData = DllStructCreate($sType, DllStructGetPtr($hVariant, "data"))
    EndIf

    Return DllStructGetData($hData, 1)
EndFunc ;==>COMVariantToValue





Func ___ValueToCOMVariant($pVariant, $vValue)
    Local $tagVARIANT = "ushort vt;ushort r1;ushort r2;ushort r3;uint64 data"
    $hVariant = DllStructCreate($tagVARIANT, $pVariant)

    If IsInt($vValue) Then
    $iVT_Type = ___AutoitType2VTType("int")
    $vData = $vValue
    ElseIf IsString($vValue) Then
    $iVT_Type = ___AutoitType2VTType("wstr")
    $vData = ___SysAllocString($vValue)
    ElseIf IsObj($vValue) Then
    $iVT_Type = ___AutoitType2VTType("idispatch")
    $vData = ___ConvertIDispatchToPtr($vValue)

    EndIf
    DllStructSetData($hVariant, "vt", $iVT_Type)
    DllStructSetData(DllStructCreate("int", DllStructGetPtr($hVariant, "data")), 1, $vData)

EndFunc ;==>ValueToCOMVariant






; Everytime autoit wants to call a method, get or set a property in a object it needs to go to
; IDispatch::GetIDsFromNames. This is our version of that function, note that by defining this ourselves
; we can fool autoit to believe that the object supports a lot of different properties/methods.
Func ___IDispatch_GetIDsFromNames($pSelf, $pRefIID, $pString_Array, $iArray_Size, $iContext, $pOut_Array)
    ; It's self explainable that autoit only asks for one member
    
    Local $DISP_E_UNKNOWNNAME = 2147614726
    Local $DISPID_UNKNOWN = 4294967295 ; = -1
    Local $S_OK = 0
    
    $hMemberName = DllStructCreate("wchar[256]", ___DereferencePointer($pString_Array))
    $sMemberName = DllStructGetData($hMemberName, 1)
    ;ConsoleWrite("AutoIt wants to look up: " & DllStructGetData($hMemberName, 1) & " (in object: " & $pSelf & ")" & @CRLF)

    ; Autoit gave us an array with one element ready to accept the id of the member it requested.
    $hID = DllStructCreate("long", $pOut_Array)
    
    
    $iId = ___FindNameInLookupTable($pSelf, "@" & $sMemberName)
    If $iId = -1 Then $iId = ___FindNameInLookupTable($pSelf, $sMemberName)
    If $iId <> -1 Then
    DllStructSetData($hID, 1, $iId)
    Return $S_OK
    Else
    ;MsgBox(0,"sdsd",$sMemberName)
        
        Local $sNewMembers[1][2]
        $sNewMembers[0][0] = "*"&$sMemberName
        $sNewMembers[0][1] = $sMemberName
        
        
        ___AddMembersToLookupTable( $pSelf , $sNewMembers)
        
        $iGetmemberID = ___FindNameInLookupTable($pSelf,"*"&$sMemberName)
        
        if $iGetmemberID <> -1 Then
            
            DllStructSetData($hID, 1, $iGetmemberID)
            Return $S_OK
            
        EndIf
        
    DllStructSetData($hID, 1, $DISPID_UNKNOWN)
    Return $DISP_E_UNKNOWNNAME
    EndIf
    
    
    
EndFunc ;==>IDispatch_GetIDsFromNames
; Create the callback so we have a pointer to this function.



; This is called when a method is called, a property is set or get.
; This call also contains arguments returns and a lot other stuff.
; However in this trivial example we don't return anything and we don't take any arguments. Puh, could get messy
Func ___IDispatch_Invoke($pSelf, $iDispID, $pRefIID, $iLCID, $wFlags, $pDispParams, $pVarResult, $pExceptInfo, $puArgErr)
    ;; Dump all parameters to console.
    
    Local $S_OK = 0
    Local $DISPATCH_METHOD = 0x1
    Local $DISPATCH_PROPERTYGET = 0x2
    Local $DISPATCH_PROPERTYPUT = 0x4
    Local $DISPATCH_PROPERTYPUTREF = 0x8
    Local $tagDISPPARAMS = "ptr rgvargs;ptr rgdispidNamedArgs;dword cArgs;dword cNamedArgs;"
    Local $DISP_E_MEMBERNOTFOUND = 2147614723
    
    ;ConsoleWrite("DispID: " & $iDispID & @CRLF & "RIID: " & $pRefIID & @CRLF & "LCID: " & $iLCID & @CRLF & "wFlags: " & $wFlags & @CRLF & _
    ;"pDispParams: " & $pDispParams & @CRLF & "pVarResult: " & $pVarResult & @CRLF & "pExceptInfo: " & $pExceptInfo & @CRLF & "puArgError: " & $puArgErr & @CRLF)


    $vMemberValue = ___IDToValue($pSelf, $iDispID)
    
    If $vMemberValue = "" Then Return $DISP_E_MEMBERNOTFOUND ; Should NEVER happen. But, you never know!
    
    ;$vMemberName = ___IDToValue($pSelf, $iDispID,"name")
    ;MsgBox(0,"sds",$wFlags)

    $hDispParams = DllStructCreate($tagDISPPARAMS, $pDispParams)

    ; AutoIt is pretty sneaky methinks, oring these together..
    If $wFlags = BitOR($DISPATCH_METHOD, $DISPATCH_PROPERTYGET) Then
        
    
    If IsString($vMemberValue) Then ; $DISPATCH_METHOD
            
            
    $oSelf = ___ConvertPtrToIDispatch($pSelf)
    $sCall = $vMemberValue & "($oSelf"
            
    If $pDispParams <> 0 And DllStructGetData($hDispParams, "cArgs") > 0 Then
    Local $aParams[DllStructGetData($hDispParams, "cArgs")]
    ; Fetch all arguments
    For $i = 0 To UBound($aParams) - 1
    ; Save the values backwards (that's how autoit do it)
    $aParams[(UBound($aParams) - 1) - $i] = ___COMVariantToValue(DllStructGetData($hDispParams, "rgvargs") + ($i * 16)) ; i*sizeof(VARIANT)
    $sCall &= ",$aParams[" & $i & "]"
    Next
    EndIf
    $sCall &= ")"
    ;ConsoleWrite("Calling function: " & $sCall & @CRLF)
    $vReturn = Execute($sCall)
    ; Set return value.
    ___ValueToCOMVariant($pVarResult, $vReturn)
    ; Give autoit the message that everything went according to plan
    Return $S_OK
            
            
    Else ; $DISPATCH_PROPERTYGET
            
    $vValue = ___COMVariantToValue($vMemberValue)
    ; I have no idea why this is needed. Shouldn't AutoIt increase the ref count when it is getting my object!?
    If IsObj($vValue) Then
    ___IUnknown_AddRef(___ConvertIDispatchToPtr($vValue))
    EndIf

    ___ValueToCOMVariant($pVarResult, $vValue)
    Return $S_OK
    EndIf

    ElseIf $wFlags = $DISPATCH_PROPERTYPUT Or $wFlags = $DISPATCH_PROPERTYPUTREF Then

    ___DeleteCOMVariant($vMemberValue,False)
;~  $vOld_Value = COMVariantToValue($vMemberValue)
;~  If IsObj($vOld_Value) Then IUnknown_Release(ConvertIDispatchToPtr($vOld_Value))


    $vNewValue = ___COMVariantToValue(DllStructGetData($hDispParams, "rgvargs"))
    If IsObj($vNewValue) Then ; If saving a object in a property we need to increase its ref count
    ___IUnknown_AddRef(___ConvertIDispatchToPtr($vNewValue))
    EndIf

    ___ValueToCOMVariant($vMemberValue, $vNewValue)
    Return $S_OK
    EndIf


EndFunc ;==>IDispatch_Invoke
; Create callback




Func ___DeleteCOMVariant($pVariant,$fFreeMem=True)
    
    Local $tagVARIANT = "ushort vt;ushort r1;ushort r2;ushort r3;uint64 data"
    Local $VT_BSTR = 8
    Local $VT_DISPATCH = 9
    
    $hVariant = DllStructCreate($tagVARIANT, $pVariant)
    Switch DllStructGetData($hVariant, "vt")
    Case $VT_DISPATCH
    ___IUnknown_Release(___DereferencePointer(DllStructGetPtr($hVariant, "data")))
    Case $VT_BSTR
    ___SysFreeString(___DereferencePointer(DllStructGetPtr($hVariant, "data")))
    EndSwitch
    If $fFreeMem Then ___DynFree($pVariant)
EndFunc ;==>DeleteCOMVariant



Func DeleteObject($pObject)
    ;ConsoleWrite("! Deleting: " & $pObject & @CRLF)
    
    Local $iSizeOfPtr = DllStructGetSize(DllStructCreate("ptr"))
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))

    $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObject) + DllStructGetSize(DllStructCreate("ptr")) * 7)
    $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))
    $iLookupTable_Size = DllStructGetData($hHeader, 1)


    For $i = 0 To $iLookupTable_Size - 1
    $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, (DllStructGetData($hVTable_Entry, 1) + DllStructGetSize(DllStructCreate("ptr"))) + $LOOKUP_TABLE_ENTRY_SIZE * $i)
    $sMemberName = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "name"))
    ___DynFree(DllStructGetData($hCurrent_Entry, "name"))
    If StringLeft($sMemberName, 1) = "@" Then
    ___DynFree(DllStructGetData($hCurrent_Entry, "value"))
    Else
    ___DeleteCOMVariant(DllStructGetData($hCurrent_Entry, "value"))
    EndIf
    Next
    ___DynFree(___DereferencePointer(___DereferencePointer($pObject) + $iSizeOfPtr * 7))
    ___DynFree(___DereferencePointer(___DereferencePointer($pObject) + $iSizeOfPtr * 8))
    ___DynFree(___DereferencePointer($pObject))


EndFunc ;==>DeleteObject


Func ___IUnknown_AddRef($pObject)
    
    Local $tagOBJECT_INFO = "dword refcount;ptr release;"
    
    $hObject_Info = DllStructCreate($tagOBJECT_INFO, ___DereferencePointer(___DereferencePointer($pObject) + 8*DllStructGetSize(DllStructCreate("ptr"))))
;~ ConsoleWrite("Adding object (" & $pObject & ") Ref count: " & " " & DllStructGetData($hObject_Info, "refcount") & " -> " & DllStructGetData($hObject_Info, "refcount") + 1 & @CRLF)
    DllStructSetData($hObject_Info, "refcount", DllStructGetData($hObject_Info, "refcount") + 1)
    Return DllStructGetData($hObject_Info, "refcount")
EndFunc ;==>IUnknown_AddRef


Func ___IUnknown_Release($pObject)
    
    Local $tagOBJECT_INFO = "dword refcount;ptr release;"
    
    $hObject_Info = DllStructCreate($tagOBJECT_INFO, ___DereferencePointer(___DereferencePointer($pObject) + 8*DllStructGetSize(DllStructCreate("ptr"))))
;~ ConsoleWrite("Releasing object (" & $pObject & ") Ref count: " & DllStructGetData($hObject_Info, "refcount") & " -> " & DllStructGetData($hObject_Info, "refcount") - 1 & @CRLF)
    DllStructSetData($hObject_Info, "refcount", DllStructGetData($hObject_Info, "refcount") - 1)

    If DllStructGetData($hObject_Info, "refcount") = 0 Then

    $iDestructorID = -1
    While True
    $iDestructorID+=1
    ;ConsoleWrite($iDestructorID&@CRLF)
    $sMethodName = ___IDToValue($pObject,$iDestructorID,"name")
    If $sMethodName="" Then ExitLoop
    if StringLeft($sMethodName,1)="~" Then
    ; Make sure ref count stays stable during deconstructor call
    DllStructSetData($hObject_Info,"refcount",2^16)
    Call(___IDToValue($pObject,$iDestructorID),___ConvertPtrToIDispatch($pObject))

    EndIf
    WEnd
        
        
        
    DeleteObject($pObject)
    EndIf



    Return DllStructGetData($hObject_Info, "refcount")
EndFunc ;==>IUnknown_Release


Func ___ObjGetRefCount($vObject)
    If IsObj($vObject) Then $vObject = ___ConvertIDispatchToPtr($vObject)
    ___IUnknown_AddRef($vObject)
    Return ___IUnknown_Release($vObject)
EndFunc ;==>ObjGetRefCount




Func ___CreateIDispatch()

    $aCall = DllCall($hOLEOUT, "int", "CreateDispTypeInfo", _
    "ptr", 0, _
    "dword", 0x400, _ ; LOCALE_SYSTEM_DEFAULT
    "idispatch*", 0)

    If @error Or $aCall[0] Then
    Return SetError(1, 0, 0)
    EndIf

    Return $aCall[3]

EndFunc ;==>CreateIDispatch




Func ObjCreateEx( $oBaseClass = "")
    
    Local $tagOBJECT_INFO = "dword refcount;ptr release;"
    Local $iSizeOfPtr = DllStructGetSize(DllStructCreate("ptr"))
    
    ; Create a victim. Could be any COM object that inherits from IDispatch
    Local $oRetObject
    Local $pObject
    Local $oRetObject = 0
    
    If Not IsObj($oBaseClass) Then
        
        Local $IUnknown_Release_Callback = DllCallbackRegister("___IUnknown_Release", "dword", "ptr")
        Local $IUnknown_Release_Callback_Ptr = DllCallbackGetPtr($IUnknown_Release_Callback)

        Local $IDispatch_GetIDsFromNames_Callback = DllCallbackRegister("___IDispatch_GetIDsFromNames", "long", "ptr;ptr;ptr;int;int;ptr")
        Local $IDispatch_GetIDsFromNames_Callback_Ptr = DllCallbackGetPtr($IDispatch_GetIDsFromNames_Callback)

        Local $IDispatch_Invoke_Callback = DllCallbackRegister("___IDispatch_Invoke", "long", "ptr;dword;ptr;dword;ushort;ptr;ptr;ptr;ptr")
        Local $IDispatch_Invoke_Callback_Ptr = DllCallbackGetPtr($IDispatch_Invoke_Callback)

        Local $IUnknown_AddRef_Callback = DllCallbackRegister("___IUnknown_AddRef", "dword", "ptr")
        Local $IUnknown_AddRef_Callback_Ptr = DllCallbackGetPtr($IUnknown_AddRef_Callback)
        
    $oRetObject = ___CreateIDispatch()
    $pObject = ___ConvertIDispatchToPtr($oRetObject)
    ; Hook into the object
    ; Offset 20 & 24 is fifth entry in vtable. Look at IDispatch and IUnknown interfaces to see why
    ___ReplaceVTableEntry($pObject, 5*$iSizeOfPtr, $IDispatch_GetIDsFromNames_Callback_Ptr)
    ___ReplaceVTableEntry($pObject, 6*$iSizeOfPtr, $IDispatch_Invoke_Callback_Ptr)


    ; Create space for a new bigger vtable
    Local $pNewVTable = ___DynAlloc(9*$iSizeOfPtr) ; sizeof(ptr)*(num entirs in dispatch)+sizeof(ptr)+sizeof(ptr)
    ___RelocateVTable($pObject, $pNewVTable, $iSizeOfPtr * 7)

    Local $pObject_Info = ___DynAlloc(DllStructGetSize(DllStructCreate($tagOBJECT_INFO)))
    Local $hObject_Info = DllStructCreate($tagOBJECT_INFO, $pObject_Info )
    DllStructSetData($hObject_Info, "refcount", 1)
    ___ReplaceVTableEntry($pObject, 8*$iSizeOfPtr, $pObject_Info)
    ___ReplaceVTableEntry($pObject, $iSizeOfPtr, $IUnknown_AddRef_Callback_Ptr)
    ___ReplaceVTableEntry($pObject, 2*$iSizeOfPtr, $IUnknown_Release_Callback_Ptr)
        
    Else
    $pObject = ___ConvertIDispatchToPtr($oBaseClass)
    $oRetObject = $oBaseClass
    EndIf
    
    
    ;___AddMembersToLookupTable($pObject, $aMembers)
    
    
    
    Return $oRetObject
EndFunc ;==>CreateObject


Func ObjAddMethod($oObj, $sExportName, $sFunctionName) ; Adds a method to the object
    
    Local $sNewMembers[1][2]
    $sNewMembers[0][0] = "@"&$sExportName
    $sNewMembers[0][1] = $sFunctionName
    
    $pObj = ___ConvertIDispatchToPtr($oObj)
    
    ___AddMembersToLookupTable( $pObj , $sNewMembers)
    
EndFunc

Func ObjAddDestructor($oObj, $sFunctionName) ; Sets the destructor of the object
    
    Local $sNewMembers[1][2]
    $sNewMembers[0][0] = "~Deconstructor"
    $sNewMembers[0][1] = $sFunctionName
    
    $pObj = ___ConvertIDispatchToPtr($oObj)
    
    ___AddMembersToLookupTable( $pObj , $sNewMembers)
    
EndFunc

Func ObjAddProperty($oObj, $sExportName, $vDefault=0) ; Adds a property (with the value of $vDefault) to the object.
    
    Local $sNewMembers[1][2]
    $sNewMembers[0][0] = $sExportName
    $sNewMembers[0][1] = $vDefault
    
    $pObj = ___ConvertIDispatchToPtr($oObj)
    
    ___AddMembersToLookupTable( $pObj , $sNewMembers)
    
EndFunc

Func ObjMemberCount($oObj) ; Returns how many members the object has.
    
    Local $pObj = ___ConvertIDispatchToPtr($oObj)
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
    
    local $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObj) + DllStructGetSize(DllStructCreate("ptr")) * 7)
    local $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))
    
    Return DllStructGetData($hHeader, 1)
    
EndFunc



Func ObjMemberID($oObj, $sName) ; Returns the ID of the member
    
    Local $pObj = ___ConvertIDispatchToPtr($oObj)
    Local $iID
    
    $iID = ___FindNameInLookupTable($pObj, $sName)
    if $iID = -1 Then $iID = ___FindNameInLookupTable($pObj, "@"&$sName)
    
    Return $iID
    
EndFunc


Func ObjMemberType($oObj, $vMember) ; $vMember: either the member name or the ID ; Returns: 1(property), or 2(method)
    
    Local $pObj = ___ConvertIDispatchToPtr($oObj)
    
    If IsString($vMember) Then $vMember = ___FindNameInLookupTable($pObj, $vMember)
    
    
    $vMemberValue = ___IDToValue($pObj, $vMember)
    If StringLeft($vMemberValue,1) = "@" then return 2
    
    return 1
    
    
EndFunc


Func ObjNameFromID($oObj, $iId)
    
    Local $pObj = ___ConvertIDispatchToPtr($oObj)
    
    Local $tagLOOKUP_TABLE_ENTRY = "ptr name;ptr value;dword flags;"
    Local $LOOKUP_TABLE_ENTRY_SIZE = DllStructGetSize(DllStructCreate($tagLOOKUP_TABLE_ENTRY))
    
    Local $hVTable_Entry = DllStructCreate("ptr", ___DereferencePointer($pObj) + DllStructGetSize(DllStructCreate("ptr")) * 7)
    Local $hHeader = DllStructCreate("int", DllStructGetData($hVTable_Entry, 1))
    Local $iLookupTable_Size = DllStructGetData($hHeader, 1)
    
    
    If $iId < 0 Or $iId >= $iLookupTable_Size Then Return ""
    
    Local $hCurrent_Entry = DllStructCreate($tagLOOKUP_TABLE_ENTRY, (DllStructGetData($hVTable_Entry, 1) + DllStructGetSize(DllStructCreate("ptr"))) + $LOOKUP_TABLE_ENTRY_SIZE * $iId)
    
    Local $sName = ___ChrPtrToString(DllStructGetData($hCurrent_Entry, "name"))
    
    If StringLeft($sName,1) = "@" then $sName = StringTrimLeft($sName,1)
    
    Return $sName
    
EndFunc 





Func File($filename,$accessmode=0)
    
    $fhandle = FileOpen($filename,$accessmode)
    If @error Then Return
    
    
    $oFile = ObjCreateEx()
        ObjAddProperty($oFile,  "handle", $fhandle)
        
        ObjAddMethod($oFile,    "read",         "File_Read")
        ObjAddMethod($oFile,    "readline",     "File_ReadLine")
        ObjAddMethod($oFile,    "write",        "File_Write")
        ObjAddMethod($oFile,    "writeline",    "File_WriteLine")
        
    ObjAddDestructor($oFile, "File_Deconstructor")
    
    Return $oFile
EndFunc



main()
Exit

Func main()
    
    $File = File("somefile.txt",1)
    
    
    for $iID = 0 to ObjMemberCount($File)-1
        
        MsgBox(0,"sdsd", ObjNameFromID($File, $iID) )
        
    Next

    
EndFunc







Func File_Read($self,$numbytes=0)
    
    Return FileRead( $self.handle, $numbytes )
EndFunc


Func File_ReadLine($self)
    
    Return FileReadLine( $self.line )
EndFunc


Func File_Write($self,$data)
    
    FileWrite( $self.handle, $data )
EndFunc


Func File_WriteLine($self,$line)
    
    FileWriteLine( $self.handle, $line )
EndFunc


Func File_Deconstructor($self)
    
    FileClose( $self.handle )
EndFunc
Edited by Kip
Link to comment
Share on other sites

Great to see you're interested in this.

However the version available here is pretty much ancient, and the current version is pretty much nothing like the one available here.

A believe a new public version will be available very soon.

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

  • 2 weeks later...

...How do I get added so I can take a look at the current version? :D

Step 1: Have something to contribute.

Step 2: Ask monoceres.

Edited by spudw2k
Link to comment
Share on other sites

Currently there are four people attached to the project. Loads of work have been done, and a release is to be expected in reasonable time.

Great news.

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.
Link to comment
Share on other sites

Before I research and develop, I thought I would tap the experience outlined in this topic regarding the information at this link...

http://msdn.microsoft.com/en-us/library/aa446864(VS.85).aspx

Would the information in this topic be applicable to acheiving Task Scheduler task enumeration as shown in the link above?

Thanks brother.

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Before I research and develop, I thought I would tap the experience outlined in this topic regarding the information at this link...

http://msdn.microsoft.com/en-us/library/aa446864(VS.85).aspx

Would the information in this topic be applicable to acheiving Task Scheduler task enumeration as shown in the link above?

Thanks brother.

Lar.

Yes it could. However it's not directly connected. This topic describes and go under the hood of the IDispatch interface. The ITaskService interface does not inherit from IDispatch and only from IUnknown.

This means you cannot determine members of the object during runtime. This makes all all COM features in autoit useless.

To overcome this problem you need to build the lookup table manually in memory, query the right pointers and call the methods by pointer. As you probably understand this is tedious work and require extensive understanding of compiled C++ code. An example that is directly relevant for your example is this Direct3D example by ProgAndy (the Direct3D interfaces also only inherits from IUnknown).

However there is good news; currently we're also working with the ability of wrapping interfaces of IUnknown type into IDispatch types. This will be done by supplying the methods syntax, kinda like DllCall.

So soon it should be possible to use:

$pTaskCollection.get_Item

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...