jugador Posted October 25, 2021 Share Posted October 25, 2021 (edited) Trying to understand how DllStructCreate & DllStructGetPtr work. why can't retrieve data from client side using DllStructGetPtr? Main.au3 Local $otext = "How are You?" Local $o_Buffer = "char[" & StringLen($otext) + 1 & "]" Local $o_Struct = DllStructCreate($o_Buffer) Local $o_Ptr = DllStructGetPtr($o_Struct) ConsoleWrite("GetSize-> " & DllStructGetSize($o_Struct) & @CRLF) ConsoleWrite("Ptr-> " & $o_Ptr & @CRLF) ;~ SetData DllStructSetData($o_Struct, 1, $otext) ConsoleWrite("GetData-> " & DllStructGetData($o_Struct, 1) & @CRLF) ; Start client RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & '"Client.au3" ' & $o_Buffer & " " & $o_Ptr) ConsoleWrite(@CRLF) ConsoleWrite("> ================ "& @CRLF) ;~ to check if convert Ptr to sting and again convert back to Ptr Local $to_String = String($o_Ptr) Local $to_Ptr = Ptr($to_String) Local $to_struct = DllStructCreate($o_Buffer, $to_Ptr) ConsoleWrite("GetSize-> " & DllStructGetSize($to_struct) & @CRLF) ConsoleWrite("Ptr-> " & DllStructGetPtr($to_struct) & @CRLF) ConsoleWrite("GetData-> " & DllStructGetData($to_struct, 1) & @CRLF) $to_struct = 0 $o_Struct = 0 Client.au3 #include <Array.au3> MsgBox( 0, "Client", "Client Started" ) ;_ArrayDisplay($CmdLine) Local $t_Buffer = $CmdLine[1] Local $t_Ptr = Ptr($CmdLine[2]) Local $t_struct = DllStructCreate($t_Buffer, $t_Ptr) If @error Then MsgBox(0, "", "Error in DllStructCreate, Code: " & @error) Exit EndIf MsgBox(0, "Client", "GetSize-> " & DllStructGetSize($t_struct)) MsgBox(0, "Client", "Ptr-> " & DllStructGetPtr($t_struct)) ;~ failed to get Data when DllStructGetPtr showing correct value MsgBox(0, "Client", "GetData-> " & DllStructGetData($t_struct, 1)) $t_struct = 0 MsgBox( 0, "Client", "client End" ) Edited October 25, 2021 by jugador Link to comment Share on other sites More sharing options...
RTFC Posted October 25, 2021 Share Posted October 25, 2021 (edited) If only it were that simple... You have to keep in mind that each process is allocated its own (virtual) memory region, with its own, unique, process-specific base address. Imagine what would happen if any process were able to read/write/erase any region in physical memory that might be concurrently used by several other processes... Instead you need to designate a specific memory region as shared between two (or more) processes. There are various examples on the forum (search for IPC (inter-process communication), memory-mapped files, etc). My own HighMem UDF, for example, provides some (heavily-annotated) functions to map/unmap process-external memory, convert absolute/relative offsets, and mutex handling to avoid race conditions. But if you just need to exchange a few variables between scripts, there are easier IPC options such as MailSlot to consider. Edited October 25, 2021 by RTFC Musashi and JockoDundee 2 My Contributions and Wrappers Spoiler BitMaskSudokuSolver BuildPartitionTable CodeCrypter CodeScanner DigitalDisplay Eigen4AutoIt FAT Suite HighMem MetaCodeFileLibrary OSgrid Pool RdRand SecondDesktop SimulatedAnnealing Xbase I/O Link to comment Share on other sites More sharing options...
LarsJ Posted October 26, 2021 Share Posted October 26, 2021 The example of _WinAPI_CreateFileMapping in the help file contains all the code you need. Study this Microsoft example, if you need more information about this memory sharing technique and the required API functions. jugador 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
jugador Posted October 26, 2021 Author Share Posted October 26, 2021 (edited) @LarsJ Thanks with _WinAPI_CreateFileMapping technique can I pass array Local $arry[][] = [["Blackberry",3],["Strawberry",4]] or object Local $oHttpObj = ObjCreate('WinHttp.WinHttpRequest.5.1') or this expandcollapse popupGlobal $oError = ObjEvent("AutoIt.Error", "_ErrFunc") __Example1() Func __Example1() Local $o_FakeObj Local $tFakeObj $o_FakeObj = _ObjectFromTag("__MyInterface_", "Message hresult(bstr)", $tFakeObj) $o_FakeObj.Message("Test message.....") If IsObj($o_FakeObj) Then $o_FakeObj = 0 EndFunc Func __MyInterface_QueryInterface($pSelf, $pRIID, $pObj) Local $tStruct = DllStructCreate("ptr", $pObj) DllStructSetData($tStruct, 1, $pSelf) Return 0 ; $S_OK EndFunc Func __MyInterface_AddRef($pSelf) Return 1 EndFunc Func __MyInterface_Release($pSelf) Return 1 EndFunc Func __MyInterface_Message($pSelf, $pString) Local $o_Data = DllStructGetData(DllStructCreate("wchar[" & _ DllStructGetData(DllStructCreate("dword", $pString - 4), 1) / 2 & "]", $pString), 1) MsgBox(0, 'FakeObj', $o_Data) Return 0 ; $S_OK EndFunc ; #FUNCTION# ============================================================================= ; Name...........: _ObjectFromTag ; ======================================================================================== Func _ObjectFromTag($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default If $bIsUnknown = Default Then $bIsUnknown = True Local $sInterface = $tagInterface ; copy interface description Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef dword();" & _ "Release dword();" ; Adding IUnknown methods If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface ; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3) Local $iUbound = UBound($aMethods) Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback ; Allocation $tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props If @error Then Return SetError(1, 0, 0) For $i = 0 To $iUbound - 1 $aSplit = StringSplit($aMethods[$i], "|", 2) If UBound($aSplit) <> 2 Then ReDim $aSplit[2] $sNamePart = $aSplit[0] $sTagPart = $aSplit[1] $sMethod = $sFunctionPrefix & $sNamePart If $fPrint Then Local $iPar = StringInStr($sTagPart, ";", 2), $t If $iPar Then $t = "Ret: " & StringLeft($sTagPart, $iPar - 1) & " " & _ "Par: " & StringRight($sTagPart, StringLen($sTagPart) - $iPar) Else $t = "Ret: " & $sTagPart EndIf Local $s = "Func " & $sMethod & _ "( $pSelf ) ; " & $t & @CRLF & _ "EndFunc" & @CRLF ConsoleWrite($s) EndIf $aTagPart = StringSplit($sTagPart, ";", 2) $sRet = $aTagPart[0] $sParams = StringReplace($sTagPart, $sRet, "", 1) $sParams = "ptr" & $sParams $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams) If @error Then ConsoleWrite('! ' & @error & ' ' & $sMethod & @CRLF & @CRLF) EndIf DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle Next DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1 DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object EndFunc ;==>ObjectFromTag Func _ErrFunc() ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF) Return EndFunc ;==>_ErrFunc @LarsJ can you show how to write DllStructCreate for the above array and object. Edited October 26, 2021 by jugador LarsJ 1 Link to comment Share on other sites More sharing options...
LarsJ Posted October 26, 2021 Share Posted October 26, 2021 (edited) For the examples above, you must use ROT objects. This is a server/client implementation of your FakeObj. Server.au3: expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include "IRunningObjectTable.au3" Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc") Example() Func Example() Local $tFakeObj, $oFakeObj $oFakeObj = _ObjectFromTag("__MyInterface_", "Message hresult(bstr)", $tFakeObj) $oFakeObj.Message("Test message from Server .....") ; Create a default ROT-object (Dictionary object) Local $sDataTransferObject, $oDataTransferObject $oDataTransferObject = ROT_CreateDefaultObject( $sDataTransferObject ) ; Create Dictionary object Local $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict.Item( "$oFakeObj" ) = $oFakeObj ; Add Dictionary object to ROT-object $oDataTransferObject.Add( "$oDict", $oDict ) ; Start the client script in a new process RunWait( @AutoItExe & " /AutoIt3ExecuteScript Client.au3" & " " & $sDataTransferObject ) EndFunc Func __MyInterface_QueryInterface($pSelf, $pRIID, $pObj) Local $tStruct = DllStructCreate("ptr", $pObj) DllStructSetData($tStruct, 1, $pSelf) Return 0 ; $S_OK #forceref $pRIID EndFunc Func __MyInterface_AddRef($pSelf) Return 1 #forceref $pSelf EndFunc Func __MyInterface_Release($pSelf) Return 1 #forceref $pSelf EndFunc Func __MyInterface_Message($pSelf, $pString) Local $o_Data = DllStructGetData(DllStructCreate("wchar[" & _ DllStructGetData(DllStructCreate("dword", $pString - 4), 1) / 2 & "]", $pString), 1) MsgBox(0, 'FakeObj', $o_Data) Return 0 ; $S_OK #forceref $pSelf EndFunc ; #FUNCTION# ============================================================================= ; Name...........: _ObjectFromTag ; ======================================================================================== Func _ObjectFromTag($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default If $bIsUnknown = Default Then $bIsUnknown = True Local $sInterface = $tagInterface ; copy interface description Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef dword();" & _ "Release dword();" ; Adding IUnknown methods If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface ; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3) Local $iUbound = UBound($aMethods) Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback ; Allocation $tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props If @error Then Return SetError(1, 0, 0) For $i = 0 To $iUbound - 1 $aSplit = StringSplit($aMethods[$i], "|", 2) If UBound($aSplit) <> 2 Then ReDim $aSplit[2] $sNamePart = $aSplit[0] $sTagPart = $aSplit[1] $sMethod = $sFunctionPrefix & $sNamePart If $fPrint Then Local $iPar = StringInStr($sTagPart, ";", 2), $t If $iPar Then $t = "Ret: " & StringLeft($sTagPart, $iPar - 1) & " " & _ "Par: " & StringRight($sTagPart, StringLen($sTagPart) - $iPar) Else $t = "Ret: " & $sTagPart EndIf Local $s = "Func " & $sMethod & _ "( $pSelf ) ; " & $t & @CRLF & _ "EndFunc" & @CRLF ConsoleWrite($s) EndIf $aTagPart = StringSplit($sTagPart, ";", 2) $sRet = $aTagPart[0] $sParams = StringReplace($sTagPart, $sRet, "", 1) $sParams = "ptr" & $sParams $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams) If @error Then ConsoleWrite('! ' & @error & ' ' & $sMethod & @CRLF & @CRLF) EndIf DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle Next DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1 DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object EndFunc ;==>ObjectFromTag Func _ErrFunc() ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF) Return EndFunc ;==>_ErrFunc Client.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Get default ROT-object (Dictionary object) Local $oDataTransferObject = ObjGet( $CmdLine[1] ) ; Get Dictionary object from ROT-object Local $oDict = $oDataTransferObject.Item( "$oDict" ) Local $oFakeObj = $oDict.Item( "$oFakeObj" ) $oFakeObj.Message("Test message from Client .....") EndFunc Run Server.au3. Come on. This is f ... (freezing) cool code. That was fun. All code in the 7z-file. FakeObj.7z You can try the other two examples yourself. Edited October 26, 2021 by LarsJ Musashi, junkew and jugador 2 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
jugador Posted October 26, 2021 Author Share Posted October 26, 2021 (edited) @LarsJ that's easy using your IRunningObjectTable Interface Udf. Already tested ScriptControl method to transfer Array & Object from Autoit to Jscript & Vbscript. but trying to find solution to pass object between two Autoit script. Thanks for this ROT objects concept. Edited October 26, 2021 by jugador Link to comment Share on other sites More sharing options...
jugador Posted October 27, 2021 Author Share Posted October 27, 2021 (edited) Memory read using Ptr this for string don't know how to pass Object and Array using this technique. example on Object and Array using this technique from fellow Autoit member would be nice . below code(by @Ascer) taken from this threadhttps://www.autoitscript.com/forum/topic/192339-reading-memory-double/?do=findComment&comment=1381902 Main.au3 Local $otext = "How are You?" Local $o_PID = WinGetProcess("AutoIt v3") Local $o_Buffer = "char[" & StringLen($otext) + 1 & "]" Local $o_Struct = DllStructCreate($o_Buffer) Local $o_Ptr = DllStructGetPtr($o_Struct) ;~ SetData DllStructSetData($o_Struct, 1, $otext) ; Start client RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & '"Client.au3" ' & $o_PID & " " & $o_Buffer & " " & $o_Ptr) $o_Struct = 0 Client.au3 MsgBox( 0, "Client", "Client.... Started" ) Local $t_Pid = Number($CmdLine[1]) Local $t_Buffer = $CmdLine[2] Local $t_Address = Number($CmdLine[3]) Local $hHandle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1F0FFF, 'int', 1, 'int', $t_Pid) If @error Then MsgBox( 0, "Client", "+++ Failed to open process memory for FULL_ACCESS. Error is " & @error ) Exit EndIf Local $sStruct = DllStructCreate($t_Buffer) If @error Then MsgBox( 0, "Client", "+++ Failed to create $sStruct. Error is " & @error ) Exit EndIf DllCall("kernel32.dll", 'int', 'ReadProcessMemory', 'int', $hHandle[0], 'int', $t_Address, 'ptr', DllStructGetPtr($sStruct), 'int', DllStructGetSize($sStruct), 'int', '') If @error Then MsgBox( 0, "Client", "+++ Failed to Read Process Memory. Error is " & @error ) Exit EndIf Local $vRet = DllStructGetData($sStruct, 1) If @error Then MsgBox( 0, "Client", "+++ Failed to Get data from $sStruct. Error is " & @error ) Exit EndIf MsgBox( 0, "Client", $vRet ) MsgBox( 0, "Client", "Client.... End" ) Edited October 27, 2021 by jugador robertocm 1 Link to comment Share on other sites More sharing options...
LarsJ Posted October 30, 2021 Share Posted October 30, 2021 This is a new version of the server/client example above based on the FakeObj object. Again, FakeObj is passed to the client through a ROT-object. Here, FakeObj can handle strings, doubles, integers and arrays. Server.au3: expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include <Array.au3> #include "AccVars.au3" #include "IRunningObjectTable.au3" Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc") Example() Func Example() ConsoleWrite( "Code running on server ..." & @CRLF ) Local $tFakeObj, $oFakeObj $oFakeObj = _ObjectFromTag("__MyInterface_", "Data hresult(variant)", $tFakeObj) $oFakeObj.Data("Test string from Server .....") $oFakeObj.Data( 123.123 ) $oFakeObj.Data( 123 ) Local $aArray = [ 123, 123.123, "Server test string" ] $oFakeObj.Data( $aArray ) ; Create a default ROT-object (Dictionary object) Local $sDataTransferObject, $oDataTransferObject $oDataTransferObject = ROT_CreateDefaultObject( $sDataTransferObject ) ; Create Dictionary object Local $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict.Item( "$oFakeObj" ) = $oFakeObj ; Add Dictionary object to ROT-object $oDataTransferObject.Add( "$oDict", $oDict ) ; Start the client script in a new process ConsoleWrite( @CRLF & "Code running on Client ..." & @CRLF ) RunWait( @AutoItExe & " /AutoIt3ExecuteScript Client.au3" & " " & $sDataTransferObject ) EndFunc Func __MyInterface_QueryInterface($pSelf, $pRIID, $pObj) Local $tStruct = DllStructCreate("ptr", $pObj) DllStructSetData($tStruct, 1, $pSelf) Return 0 ; $S_OK #forceref $pRIID EndFunc Func __MyInterface_AddRef($pSelf) Return 1 #forceref $pSelf EndFunc Func __MyInterface_Release($pSelf) Return 1 #forceref $pSelf EndFunc Func __MyInterface_Data($pSelf, $pVariant) ConsoleWrite( @CRLF & "$pVar = " & $pVariant & @CRLF ) Local $tVariant = DllStructCreate( $tagVARIANT, $pVariant ) Local $sAlign1 = " " & ( @AutoItX64 ? " " : "" ) Local $iVariantType = DllStructGetData( $tVariant, "vt" ) ConsoleWrite( "Type = 0x" & Hex( $iVariantType, 4 ) & " " & $sAlign1 ) ; 4 word elements before the data element = 8 bytes Local $pData = $pVariant + 8, $tPtr, $pPtr Switch $iVariantType Case $VT_I4 ; 4 bytes signed integer ConsoleWrite( "(VT_I4, 4 bytes signed integer)" & @CRLF ) ; The data element contains the integer in the 4 first bytes Local $tInt = DllStructCreate( "int", $pData ) Local $iInt = DllStructGetData( $tInt, 1 ) ConsoleWrite( "data = " & $iInt & @CRLF ) Case $VT_R8 ; 8 bytes double ConsoleWrite( "(VT_R8, 8 bytes double)" & @CRLF ) ; The data element contains the double in the 8 first bytes ; That's the entire data element on 32 bit and half the data element on 64 bit Local $tFlt = DllStructCreate( "double", $pData ) Local $fFlt = DllStructGetData( $tFlt, 1 ) ConsoleWrite( "data = " & $fFlt & @CRLF ) Case $VT_BSTR ; Basic string ConsoleWrite( "(VT_BSTR, basic string)" & @CRLF ) ; The data element contains a pointer to the BSTR $tPtr = DllStructCreate( "ptr", $pData ) $pPtr = DllStructGetData( $tPtr, 1 ) ConsoleWrite( "pBSTR = " & $pPtr & " (BSTR pointer)" & @CRLF ) ; The BSTR must be read with a proper BSTR-function (see Variant.au3) Local $sStr = SysReadString( $pPtr ) ConsoleWrite( "data = " & $sStr & @CRLF ) Case $VT_ARRAY + $VT_VARIANT ; Array of variants ConsoleWrite( "(VT_ARRAY+VT_VARIANT, array of variants, safearray)" & @CRLF ) ; The data element contains a pointer to the safearray in the 4/8 first bytes $tPtr = DllStructCreate( "ptr", $pData ) $pPtr = DllStructGetData( $tPtr, 1 ) ConsoleWrite( "data = " & $pPtr & " (pointer to safearray)" & @CRLF ) ; Print safearray data to console ConsoleWrite( @CRLF & "Safearray data:" & @CRLF ) PrintSafeArray1D( $pPtr ) ; Convert safearray to AutoIt array through internal COM conversions ; Display the AutoIt array with _ArrayDisplay( $aArray ) ConsoleWrite( @CRLF & "Convert safearray to AutoIt array" & @CRLF ) Local $aArray SafeArrayLock( $pPtr ) AccessVariables02( AccVars_SafeArrayToArray, $pPtr, $aArray ) SafeArrayUnlock( $pPtr ) ConsoleWrite( "_ArrayDisplay( <AutoIt array> ) ..." & @CRLF ) _ArrayDisplay( $aArray ) Case Else ConsoleWrite( "Variant type = " & DllStructGetData( $tVariant, "vt" ) & @CRLF ) ConsoleWrite( "Unhandled variant type" & @CRLF ) EndSwitch Return 0 ; $S_OK #forceref $pSelf EndFunc ; #FUNCTION# ============================================================================= ; Name...........: _ObjectFromTag ; ======================================================================================== Func _ObjectFromTag($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default If $bIsUnknown = Default Then $bIsUnknown = True Local $sInterface = $tagInterface ; copy interface description Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef dword();" & _ "Release dword();" ; Adding IUnknown methods If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface ; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3) Local $iUbound = UBound($aMethods) Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback ; Allocation $tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props If @error Then Return SetError(1, 0, 0) For $i = 0 To $iUbound - 1 $aSplit = StringSplit($aMethods[$i], "|", 2) If UBound($aSplit) <> 2 Then ReDim $aSplit[2] $sNamePart = $aSplit[0] $sTagPart = $aSplit[1] $sMethod = $sFunctionPrefix & $sNamePart If $fPrint Then Local $iPar = StringInStr($sTagPart, ";", 2), $t If $iPar Then $t = "Ret: " & StringLeft($sTagPart, $iPar - 1) & " " & _ "Par: " & StringRight($sTagPart, StringLen($sTagPart) - $iPar) Else $t = "Ret: " & $sTagPart EndIf Local $s = "Func " & $sMethod & _ "( $pSelf ) ; " & $t & @CRLF & _ "EndFunc" & @CRLF ConsoleWrite($s) EndIf $aTagPart = StringSplit($sTagPart, ";", 2) $sRet = $aTagPart[0] $sParams = StringReplace($sTagPart, $sRet, "", 1) $sParams = "ptr" & $sParams $hCallback = DllCallbackRegister($sMethod, $sRet, $sParams) If @error Then ConsoleWrite('! ' & @error & ' ' & $sMethod & @CRLF & @CRLF) EndIf DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle Next DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1 DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object EndFunc ;==>ObjectFromTag Func _ErrFunc() ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF) Return EndFunc ;==>_ErrFunc Func PrintSafeArray1D( $pSafeArray ) If Not IsPtr( $pSafeArray ) Then Return SetError(1,0,0) If Not SafeArrayGetDim( $pSafeArray ) = 1 Then Return SetError(2,0,0) Local $tSafeArray = DllStructCreate( $tagSAFEARRAY, $pSafeArray ) Local $iElemSize = DllStructGetData( $tSAFEARRAY, "cbElements" ) Local $iUBound, $pSafeArrayData, $vt, $data SafeArrayGetUBound( $pSafeArray, 1, $iUBound ) SafeArrayAccessData( $pSafeArray, $pSafeArrayData ) For $i = 0 To $iUBound $vt = DllStructGetData( DllStructCreate( "word", $pSafeArrayData ), 1 ) Switch $vt Case $VT_I4 ; 4 bytes signed integer $data = DllStructGetData( DllStructCreate( "int", $pSafeArrayData + 8 ), 1 ) Case $VT_R8 ; 8 bytes double $data = DllStructGetData( DllStructCreate( "double", $pSafeArrayData + 8 ), 1 ) Case $VT_BSTR ; Basic string $data = SysReadString( DllStructGetData( DllStructCreate( "ptr", $pSafeArrayData + 8 ), 1 ) ) Case Else $data = "" EndSwitch ConsoleWrite( $data & @CRLF ) $pSafeArrayData += $iElemSize Next SafeArrayUnaccessData( $pSafeArray ) EndFunc Func AccVars_SafeArrayToArray( $pvSafeArray, $pArray ) ; <<<< On function entry the native AutoIt array is converted to a safearray contained in a variant >>>> ; --- Get safearray information --- ; $pvSafeArray is a variant that contains a pointer Local $pSafeArray = DllStructGetData( DllStructCreate( "ptr", $pvSafeArray + 8 ), 1 ) ; Array type Local $iVarType SafeArrayGetVartype( $pSafeArray, $iVarType ) Switch $iVarType Case $VT_I2, $VT_I4 ; Signed integers Case $VT_R4, $VT_R8 ; 4/8 bytes floats Case $VT_BSTR ; Basic string Case $VT_BOOL ; Boolean Case $VT_UI4, $VT_UI8 ; 4/8 bytes unsigned integers Case $VT_VARIANT ; Variant Case Else Return SetError(1,0,0) EndSwitch ; --- Set $pArray to match an array --- ; Set vt element to $VT_ARRAY + $iVarType DllStructSetData( DllStructCreate( "word", $pArray ), 1, $VT_ARRAY + $iVarType ) ; Set data element to safearray pointer DllStructSetData( DllStructCreate( "ptr", $pArray + 8 ), 1, $pSafeArray ) ; <<<< On function exit the safearray contained in a variant is converted to a native AutoIt array >>>> EndFunc Client.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Get default ROT-object (Dictionary object) Local $oDataTransferObject = ObjGet( $CmdLine[1] ) ; Get Dictionary object from ROT-object Local $oDict = $oDataTransferObject.Item( "$oDict" ) Local $oFakeObj = $oDict.Item( "$oFakeObj" ) $oFakeObj.Data("Test string from Client .....") $oFakeObj.Data( 123.123 ) $oFakeObj.Data( 123 ) Local $aArray = [ 123, 123.123, "Client test string" ] $oFakeObj.Data( $aArray ) EndFunc Run Server.au3. Output in SciTE console: expandcollapse popupCode running on server ... $pVar = 0x000000000045ED30 Type = 0x0008 (VT_BSTR, basic string) pBSTR = 0x0000000000928EE8 (BSTR pointer) data = Test string from Server ..... $pVar = 0x000000000045ED30 Type = 0x0005 (VT_R8, 8 bytes double) data = 123.123 $pVar = 0x000000000045ED30 Type = 0x0003 (VT_I4, 4 bytes signed integer) data = 123 $pVar = 0x000000000045ED30 Type = 0x200C (VT_ARRAY+VT_VARIANT, array of variants, safearray) data = 0x000000000095C7B0 (pointer to safearray) Safearray data: 123 123.123 Server test string Convert safearray to AutoIt array _ArrayDisplay( <AutoIt array> ) ... Code running on Client ... $pVar = 0x000000000045E520 Type = 0x0008 (VT_BSTR, basic string) pBSTR = 0x0000000000926908 (BSTR pointer) data = Test string from Client ..... $pVar = 0x000000000045E520 Type = 0x0005 (VT_R8, 8 bytes double) data = 123.123 $pVar = 0x000000000045E520 Type = 0x0003 (VT_I4, 4 bytes signed integer) data = 123 $pVar = 0x000000000045E520 Type = 0x200C (VT_ARRAY+VT_VARIANT, array of variants, safearray) data = 0x000000000095E8F0 (pointer to safearray) Safearray data: 123 123.123 Client test string Convert safearray to AutoIt array _ArrayDisplay( <AutoIt array> ) ... All code in the 7z-file. FakeObj2.7z robertocm, jugador and junkew 3 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions 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