Zedna Posted January 9, 2010 Share Posted January 9, 2010 (edited) $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 January 9, 2010 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search Link to comment Share on other sites More sharing options...
Kip Posted January 9, 2010 Share Posted January 9, 2010 (edited) 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?Edit: Sorry: This is great! Do you already have some other ideas what you can do with this? Besides OO. Edited January 9, 2010 by Kip MailSpons: Fake SMTP server for safe email testing Dutch postcode & address API. Link to comment Share on other sites More sharing options...
junkew Posted January 9, 2010 Share Posted January 9, 2010 (edited) 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 January 9, 2010 by junkew FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets Link to comment Share on other sites More sharing options...
FuryCell Posted January 12, 2010 Share Posted January 12, 2010 This is amazing. Brings new found power long missing from autoit. Excellent work. HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code. Link to comment Share on other sites More sharing options...
ValeryVal Posted January 15, 2010 Share Posted January 15, 2010 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 thisThere 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 More sharing options...
ProgAndy Posted January 15, 2010 Share Posted January 15, 2010 (edited) 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 . 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 January 15, 2010 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 More sharing options...
James Posted January 16, 2010 Share Posted January 16, 2010 BRAINWAVE! This would be such a cool way of implementing things such as a JSON UDF... Blog - Seriously epic web hosting - Twitter - GitHub - Cachet HQ Link to comment Share on other sites More sharing options...
JRowe Posted January 16, 2010 Share Posted January 16, 2010 ProgAndy, Monoceres, and trancexx all deserve big kudos for this. This is gonna be fun [center]However, like ninjas, cyber warriors operate in silence.AutoIt Chat Engine (+Chatbot) , Link Grammar for AutoIt , Simple Speech RecognitionArtificial Neural Networks UDF , Bayesian Networks UDF , Pattern Matching UDFTransparent PNG GUI Elements , Au3Irrlicht 2Advanced Mouse Events MonitorGrammar Database GeneratorTransitions & Tweening UDFPoker Hand Evaluator[/center] Link to comment Share on other sites More sharing options...
Kip Posted January 17, 2010 Share Posted January 17, 2010 (edited) I hope you don't mind, but I've edited it a little bit and added some of my own functions: expandcollapse popup#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 January 17, 2010 by Kip MailSpons: Fake SMTP server for safe email testing Dutch postcode & address API. Link to comment Share on other sites More sharing options...
monoceres Posted January 17, 2010 Author Share Posted January 17, 2010 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 More sharing options...
Kip Posted January 17, 2010 Share Posted January 17, 2010 (edited) Great Edited January 17, 2010 by Kip MailSpons: Fake SMTP server for safe email testing Dutch postcode & address API. Link to comment Share on other sites More sharing options...
monoceres Posted January 18, 2010 Author Share Posted January 18, 2010 Great Hey, sorry, I know it sucks to do work when you get nothing to show for it.Want to see the current version? I can add you to the project? Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
Kip Posted January 18, 2010 Share Posted January 18, 2010 I'd love to MailSpons: Fake SMTP server for safe email testing Dutch postcode & address API. Link to comment Share on other sites More sharing options...
monoceres Posted January 18, 2010 Author Share Posted January 18, 2010 I'd love to PM invitation sent. Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
Quasar Jarosz Posted January 26, 2010 Share Posted January 26, 2010 PM invitation sent.Added to the project? How do I get added so I can take a look at the current version? Link to comment Share on other sites More sharing options...
spudw2k Posted January 26, 2010 Share Posted January 26, 2010 (edited) ...How do I get added so I can take a look at the current version? Step 1: Have something to contribute.Step 2: Ask monoceres. Edited January 26, 2010 by spudw2k Spoiler Things I've Made: Always On Top Tool ◊ AU History ◊ Deck of Cards ◊ HideIt ◊ ICU ◊ Icon Freezer ◊ Ipod Ejector ◊ Junos Configuration Explorer ◊ Link Downloader ◊ MD5 Folder Enumerator ◊ PassGen ◊ Ping Tool ◊ Quick NIC ◊ Read OCR ◊ RemoteIT ◊ SchTasksGui ◊ SpyCam ◊ System Scan Report Tool ◊ System UpTime ◊ Transparency Machine ◊ VMWare ESX Builder Misc Code Snippets: ADODB Example ◊ CheckHover ◊ Detect SafeMode ◊ DynEnumArray ◊ GetNetStatData ◊ HashArray ◊ IsBetweenDates ◊ Local Admins ◊ Make Choice ◊ Recursive File List ◊ Remove Sizebox Style ◊ Retrieve PNPDeviceID ◊ Retrieve SysListView32 Contents ◊ Set IE Homepage ◊ Tickle Expired Password ◊ Transpose Array Projects: Drive Space Usage GUI ◊ LEDkIT ◊ Plasma_kIt ◊ Scan Engine Builder ◊ SpeeDBurner ◊ SubnetCalc Cool Stuff: AutoItObject UDF ◊ Extract Icon From Proc ◊ GuiCtrlFontRotate ◊ Hex Edit Funcs ◊ Run binary ◊ Service_UDF Link to comment Share on other sites More sharing options...
monoceres Posted January 26, 2010 Author Share Posted January 26, 2010 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. Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
FuryCell Posted February 2, 2010 Share Posted February 2, 2010 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 More sharing options...
LarryDalooza Posted February 8, 2010 Share Posted February 8, 2010 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. AutoIt has helped make me wealthy Link to comment Share on other sites More sharing options...
monoceres Posted February 9, 2010 Author Share Posted February 9, 2010 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now