Leaderboard
Popular Content
Showing content with the highest reputation on 06/21/2020 in all areas
-
IPC Techniques through ROT Objects
seadoggie01 and one other reacted to LarsJ for a topic
An obvious use of ROT objects is in connection with tasks such as inter-process communication (IPC). The advantage of using ROT objects for these tasks is partly that you can handle large amounts of data and partly that you can handle the vast majority of AutoIt data types. This thread implements a UDF for inter-process communication between two AutoIt scripts based on ROT objects. Simple exampleExamples\0) Sample\ is a simple example. There are 4 files in the folder: Sender.au3: #include "..\..\Includes\IPCROT_Sender.au3" Example() Func Example() ; Create array Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 9 $aArray[$i][$j] = $i & "/" & $j Next Next ; Send array IPCROT_Sender( "Example", $aArray ) MsgBox( 0, "Sender", "@error = " & @error & ", @extended = " & @extended & @CRLF ) $aArray = 0 EndFunc Receiver.au3: #include <Array.au3> #include "..\..\Includes\IPCROT_Receiver.au3" Example() Func Example() ; Get array Local $aArray IPCROT_Receiver( "Example", $aArray ) MsgBox( 0, "Receiver", "@error = " & @error & ", @extended = " & @extended & @CRLF ) _ArrayDisplay( $aArray, "Receiver" ) $aArray = 0 EndFunc Start1.au3: Run( @AutoItExe & " /AutoIt3ExecuteScript Sender.au3", "" ) Run( @AutoItExe & " /AutoIt3ExecuteScript Receiver.au3", "" ) Start2.au3: Run( @AutoItExe & " /AutoIt3ExecuteScript Receiver.au3", "" ) Run( @AutoItExe & " /AutoIt3ExecuteScript Sender.au3", "" ) Start1.au3 and Start2.au3 shows that it doesn't matter if you start Sender.au3 first or Receiver.au3 first. Another way to start the programs is to double-click Receiver.au3 and then double-click Sender.au3 within 10 seconds. Or double-click Sender.au3 and then double-click Receiver.au3 within 10 seconds. 10 seconds because the default timeout for both IPCROT_Sender() and IPCROT_Receiver() functions is 10 seconds. Timeout can be set via a parameter. Debug exampleExamples\1) Debug\ is a debug example. There are 3 files in the folder: Sender.au3: #include "..\..\Includes\IPCROT_SenderDebug.au3" Example() Func Example() ; Create array Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 9 $aArray[$i][$j] = $i & "/" & $j Next Next ; Send array Local $hDebug IPCROT_Sender( $hDebug, "Debug", $aArray ) MsgBox( 0, "Sender", "@error = " & @error & ", @extended = " & @extended & @CRLF ) EndFunc Receiver.au3: #include <Array.au3> #include "..\..\Includes\IPCROT_ReceiverDebug.au3" Example() Func Example() ; Get array Local $aArray, $hDebug IPCROT_Receiver( $hDebug, "Debug", $aArray ) MsgBox( 0, "Receiver", "@error = " & @error & ", @extended = " & @extended & @CRLF ) _ArrayDisplay( $aArray, "Receiver" ) $aArray = 0 EndFunc Start.au3: Run( @AutoItExe & " /AutoIt3ExecuteScript Sender.au3", "" ) Run( @AutoItExe & " /AutoIt3ExecuteScript Receiver.au3", "" ) The difference between the debug and non-debug versions is the include files and the way the IPCROT_Sender() and IPCROT_Receiver() functions are called. The debug functions must be called with an initial $hDebug parameter that is a reference to the debug window. The Debug window contains an Edit control to display debug information. If you run Start.au3, debug information is generated in this way: Sender Debug output: Establish communication with Receiver() function Info - Check that the (hidden) window "DebugIPCROT_SenderGui" doesn't exist Checking... Info - The (hidden) window "DebugIPCROT_SenderGui" doesn't exist Checked OK Info - Create window to establish communication between Sender and Receiver Creating... Info - "DebugIPCROT_SenderGui" to establish communication is created 0x002003BE Info - Get $hReceiverGui from "DebugIPCROT_ReceiverGui" window Get $hReceiverGui... Info - Got $hReceiverGui from "DebugIPCROT_ReceiverGui" window 0x000503B8 Info - Verify communication with Receiver by sending $hSenderGui to Receiver Verifying... Info - Communication with Receiver has been verified so far Verified OK Info - Sender has been running for a total of (milliseconds) 340.758703766091 Pass data from Sender() to Receiver() through ROT object Info - Register ROT object: $sROTNameId = Debug-{43EDDFE3-7803-402A-AC63-A122164C1853} Info - ROT object is registered: $sROTNameId = Debug-{43EDDFE3-7803-402A-AC63-A122164C1853} Info - Copy $sROTNameId to Receiver Copying... Info - $sROTNameId is copied to Receiver Copied OK Info - Get the ROT object Get ROT object... Info - Got the ROT object ROT object OK Info - Store data in ROT object, may be time consuming for large amounts of data Store data... Info - Data is stored in ROT object, the storing time is (milliseconds) 8.8428446044186 Info - Send "Data is ready message" to Receiver Data ready... Info - "Data is ready message" is send to Receiver Data ready OK Info - Idle loop until data is received by Receiver or an error has occurred Waiting (max 100 sec)... Info - Informed by Receiver that data is received Data received OK Info - Removing ROT object Removed OK Info - Sender has been running for a total of (milliseconds) 550.850650732295 Receiver Debug output: Establish communication with Sender() function Info - Check that the (hidden) window "DebugIPCROT_ReceiverGui" doesn't exist Checking... Info - The (hidden) window "DebugIPCROT_ReceiverGui" doesn't exist Checked OK Info - Create window to establish communication between Sender and Receiver Creating... Info - "DebugIPCROT_ReceiverGui" to establish communication is created 0x000503B8 Info - Get $hSenderGui from "DebugIPCROT_SenderGui" window Get $hSenderGui... Info - Got $hSenderGui from "DebugIPCROT_SenderGui" window 0x002003BE Info - Verify communication with Sender by sending $hReceiverGui to Sender Verifying... Info - Communication with Sender has been verified so far Verified OK Info - Receiver has been running for a total of (milliseconds) 342.119567626512 Receive data from Sender() through ROT object Info - Idle loop until data is ready for Receiver or an error has occurred Waiting (max 100 sec)... Info - $sROTNameId is received: $sROTNameId = Debug-{43EDDFE3-7803-402A-AC63-A122164C1853} Info - Received "Data is ready message" from Sender Data ready OK Info - Get the ROT object Get ROT object... Info - Got the ROT object ROT object OK Info - Load data from ROT object Load data... Info - Data is loaded from ROT object, the loading time is (milliseconds) 36.1543184155466 Info - Inform Sender that data has been received Data received OK Info - Receiver has been running for a total of (milliseconds) 508.463010656406 Note that there is no message loop in the debug windows. It's the MsgBoxes that keeps the debug windows open. When you close the Receiver MsgBox, the array received from the Sender() function is displayed with _ArrayDisplay(). Now, the _ArrayDisplay() function keeps the Receiver debug window open. When you close the _ArrayDisplay() window, the Receiver debug window also closes. When you close the Sender() MsgBox, the Sender debug window also closes. If you double-click Sender.au3 and wait for 10 seconds until timeout, you'll see this information. Sender Debug output: Establish communication with Receiver() function Info - Check that the (hidden) window "DebugIPCROT_SenderGui" doesn't exist Checking... Info - The (hidden) window "DebugIPCROT_SenderGui" doesn't exist Checked OK Info - Create window to establish communication between Sender and Receiver Creating... Info - "DebugIPCROT_SenderGui" to establish communication is created 0x0005039C Info - Get $hReceiverGui from "DebugIPCROT_ReceiverGui" window Get $hReceiverGui... Error - Couldn't get $hReceiverGui from "DebugIPCROT_ReceiverGui" window @error = 2, @extended = 0 Error - Sender has been trying until timeout after 10 seconds If you double-click Receiver.au3 and wait for 10 seconds until timeout, you'll see this information. Receiver Debug output: Establish communication with Sender() function Info - Check that the (hidden) window "DebugIPCROT_ReceiverGui" doesn't exist Checking... Info - The (hidden) window "DebugIPCROT_ReceiverGui" doesn't exist Checked OK Info - Create window to establish communication between Sender and Receiver Creating... Info - "DebugIPCROT_ReceiverGui" to establish communication is created 0x000603A6 Info - Get $hSenderGui from "DebugIPCROT_SenderGui" window Get $hSenderGui... Error - Couldn't get $hSenderGui from "DebugIPCROT_SenderGui" window @error = 2, @extended = 0 Error - Receiver has been trying until timeout after 10 seconds How does it work?From the debug information it should be possible to get an impression of how the code works. The code in both the IPCROT_Sender() and IPCROT_Receiver() functions is divided into two sections. The first section is about establishing communication with the other function. The second section is about the actual data transfer. Function header for IPCROT_Sender(): ; Success: Returns 1 ; Failure: Returns 0 ; Sets @error and @extended ; @error = 1: SenderGui error ; @error = 2: $hReceiverGui error ; @error = 3: Communication with Receiver cannot be verified ; @error = 4: ROT_RegisterObject error ; @error = 5: IPCROT_SendCopyData error ; @error = 6: Get the ROT object error ; @error = 7: Data is ready message error ; @error = 8: Error occured in Receiver() function ; @error = 9: Idle loop timeout, most likely an error ; @extended = zero based error occurrence Func IPCROT_Sender( _ ; Pass data (usually an array or object) from Sender to Receiver through ROT object. $sNameId, _ ; $sNameId is a unique identifier to secure multiple concurrent data communications. $vData, _ ; $vData is the data to be sent from Sender to Receiver, usually an array or object. $iTimeOut = 10 ) ; Time window to establish communication between Sender() and Receiver() functions. ; Does not include time for the actual data transfer. Time setting in seconds. Function header for IPCROT_Receiver(): ; Success: Returns 1 ; Failure: Returns 0 ; Sets @error and @extended ; @error = 1: ReceiverGui error ; @error = 2: $hSenderGui error ; @error = 3: Communication with Sender cannot be verified ; @error = 4: Error occured in Sender() function ; @error = 5: Get the ROT object error ; @error = 6: Idle loop timeout, most likely an error ; @extended = zero based error occurrence Func IPCROT_Receiver( _ ; Pass data (usually an array or object) from Sender to Receiver through ROT object. $sNameId, _ ; $sNameId is a unique identifier to secure multiple concurrent data communications. ByRef $vData, _ ; $vData is the data to be sent from Sender to Receiver, usually an array or object. $iTimeOut = 10 ) ; Time window to establish communication between Sender() and Receiver() functions. ; Does not include time for the actual data transfer. Time setting in seconds. Note that the debug versions of the functions have an additional $hDebug parameter as the first parameter. It's a reference to the debug window. Establish communication Sender-Receiver communication is established through simple Window automation. IPCROT_Sender() creates a (hidden) window titled $sNameId & "IPCROT_SenderGui". IPCROT_Receiver() creates a (hidden) window titled $sNameId & "IPCROT_ReceiverGui". The other function establishes communication by identifying this window. To establish communication between multiple Sender-Receiver pairs at once, $sNameId must be unique for each Sender-Receiver pair. And both the Sender and Receiver window must be opened within the timeout period. Data transfer When communication is established, it's the Sender who plays the role of server. Sender creates the ROT object, sends $sROTNameId to Receiver via a WM_COPYDATA message, stores data in the ROT object and sends a "Data is ready message" to the Receiver. $sROTNameId is created uniquely in this way: $sROTNameId = $sNameId & ROT_CreateGUID(). The Receiver plays the role of client. Once the Receiver has received the "Data is ready message", the Receiver accesses the ROT object with ObjGet() and retrieves the data. Receiver informs Sender that data has been received, which terminates the communication. Internal communication Information in the form of integers sent via WM_USER messages controls the internal communication between Sender and Receiver. IPCROT_Messages.au3: #include-once ; WM_USER messages Global Const $IPCROTMSG_iMsgToSender = 0x7FFF Global Const $IPCROTMSG_iMsgToReceiver = $IPCROTMSG_iMsgToSender - 1 ; Messages to Sender from Receiver Global Const $IPCROTMSG_iReceiverHandle = 1 Global Const $IPCROTMSG_iReceiverDataReceived = 2 Global Const $IPCROTMSG_iReceiverError = 3 Global $IPCROTMSG_iReceiverErrorValue = 4 Global Const $IPCROTMSG_iCommnError = 1 ; ReceiverErrorValue Global Const $IPCROTMSG_iGetROTobject = 4 ; Messages to Receiver from Sender ; $WM_COPYDATA to send $sROTNameId Global Const $IPCROTMSG_iSenderHandle = 5 Global Const $IPCROTMSG_iDataIsReady = 6 Global Const $IPCROTMSG_iSenderError = 7 Global $IPCROTMSG_iSenderErrorValue = 8 ;Global Const $IPCROTMSG_iCommnError = 1 ; SenderErrorValues Global Const $IPCROTMSG_iRegisterROTobject = 2 Global Const $IPCROTMSG_iCopyROTNameId = 3 ;Global Const $IPCROTMSG_iGetROTobject = 4 ; Sender/Receiver errors Global Const $IPCROTMSG_aErrorValues = [ _ "RegisterROTobject", _ "CopyROTNameId", _ "GetROTobject" ] Data typesExamples\2) Data types\ is about data types. The example is based on the example for the VarGetType() function in the help file. DataTypes.au3 is a slightly modified version of this example. Note that all remaining examples run in debug mode so it's possible to see what's going on. In Sender.au3, the various data types are stored in a dictionary object and sent in this way: Local $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( "$aArray" ) = $aArray $oDict( "$dBinary" ) = $dBinary $oDict( "$bBoolean" ) = $bBoolean $oDict( "$pPtr" ) = $pPtr $oDict( "$hWnd" ) = $hWnd $oDict( "$iInt" ) = $iInt $oDict( "$fFloat" ) = $fFloat $oDict( "$oObject" ) = $oObject $oDict( "$sString" ) = $sString $oDict( "$tStruct" ) = $tStruct $oDict( "$vKeyword" ) = $vKeyword $oDict( "$fuMsgBox" ) = $fuMsgBox $oDict( "$fuFunc" ) = $fuFunc $oDict( "$fuUserFunc" ) = $fuUserFunc ; Send $oDict Local $hDebug IPCROT_Sender( $hDebug, "DataTypes", $oDict ) Receiver.au3: #include "..\..\Includes\IPCROT_ReceiverDebug.au3" Example() Func Example() ; Get $oDict Local $oDict, $hDebug IPCROT_Receiver( $hDebug, "DataTypes", $oDict ) MsgBox( 0, "Receiver: Variable Types", _ "$aArray : " & @TAB & @TAB & VarGetType( $oDict( "$aArray" ) ) & " variable type." & @CRLF & _ "$dBinary : " & @TAB & @TAB & VarGetType( $oDict( "$dBinary" ) ) & " variable type." & @CRLF & _ "$bBoolean : " & @TAB & VarGetType( $oDict( "$bBoolean" ) ) & " variable type." & @CRLF & _ "$pPtr : " & @TAB & @TAB & VarGetType( $oDict( "$pPtr" ) ) & " variable type." & @CRLF & _ "$hWnd : " & @TAB & @TAB & VarGetType( $oDict( "$hWnd" ) ) & " variable type." & @CRLF & _ "$iInt : " & @TAB & @TAB & VarGetType( $oDict( "$iInt" ) ) & " variable type." & @CRLF & _ "$fFloat : " & @TAB & @TAB & VarGetType( $oDict( "$fFloat" ) ) & " variable type." & @CRLF & _ "$oObject : " & @TAB & VarGetType( $oDict( "$oObject" ) ) & " variable type." & @CRLF & _ "$sString : " & @TAB & @TAB & VarGetType( $oDict( "$sString" ) ) & " variable type." & @CRLF & _ "$tStruct : " & @TAB & @TAB & "Not recognized as a valid variable type." & @CRLF & _ "$vKeyword : " & @TAB & VarGetType( $oDict( "$vKeyword" ) ) & " variable type." & @CRLF & _ "fuMsgBox : " & @TAB & "Not recognized as a valid variable type." & @CRLF & _ "$fuFunc : " & @TAB & @TAB & "Not recognized as a valid variable type." & @CRLF & _ "$fuUserFunc : " & @TAB & "Not recognized as a valid variable type." ) EndFunc And this is the text in the Receiver MsgBox: $aArray : Array variable type. $dBinary : Binary variable type. $bBoolean : Bool variable type. $pPtr : Int32 variable type. $hWnd : Int32 variable type. $iInt : Int32 variable type. $fFloat : Double variable type. $oObject : Object variable type. $sString : String variable type. $tStruct : Not recognized as a valid variable type. $vKeyword : Keyword variable type. fuMsgBox : Not recognized as a valid variable type. $fuFunc : Not recognized as a valid variable type. $fuUserFunc : Not recognized as a valid variable type. Only the $tStruct and the function data types are not received correctly by the Receiver function. The Int32 types for $pPtr and $hWnd can easily be converted to pointer and window handles with the Ptr() and HWnd() functions. DllStructThe DllStruct data type ($tStruct in the example above) isn't a COM compatible data type and is therefore not received correctly by the Receiver function. But the Binary data type is received correctly. One way to handle the DllStruct is to convert it to a Binary before it's sent by the Sender() function. And then convert the Binary back to a DllStruct after it's received by the Receiver() function. Examples\3) DllStruct\ is about the DllStruct data type. Binary data What is Binary data and how is Binary data stored in internal AutoIt code? in Accessing AutoIt Variables in Tests\Examples\1) Simple variables\Example3.au3 all the data types in the example for the VarGetType() function are examined. This is the result for the Binary data type: $dBinary Type = Binary ptr = 0x009C59A0 ($pVariant) vt = 0x2011 (VT_ARRAY+VT_UI1, array of 1 byte unsigned integers) data = 0x009DABF8 This means that Binary data is stored internally as a safearray of bytes (also known as a bytearray). When Binary data is passed to a COM method as a parameter, the pointer to this safearray is passed in a variant. Sender and Receiver Sender.au3: #include "AccVars.au3" #include "..\..\Includes\IPCROT_SenderDebug.au3" Example() Func Example() Local Const $tagStruct = "struct;int var1;byte var2;uint var3;char var4[128];endstruct" Local $tStruct1 = DllStructCreate( $tagStruct ) DllStructSetData( $tStruct1, "var1", -1 ) DllStructSetData( $tStruct1, "var2", 255 ) DllStructSetData( $tStruct1, "var3", -1 ) ; The -1 (signed int) will be typecasted to unsigned int. DllStructSetData( $tStruct1, "var4", "Hello" ) ; Change data of element var4 (char) in $tStruct1, DllStructSetData( $tStruct1, "var4", Asc( "h" ), 1 ) ; at the index 1 of the char array (1 based index). Local $dBinary AccVars_DllStructToBinary( $tStruct1, $dBinary ) ; Convert DllStruct to Binary Local $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( "$tagStruct" ) = $tagStruct $oDict( "$dBinary" ) = $dBinary ; Send $oDict Local $hDebug IPCROT_Sender( $hDebug, "DllStruct", $oDict ) Local $iError = @error, $iExtended = @extended If $iError Then MsgBox( 0, "Sender", "@error = " & $iError & ", @extended = " & $iExtended & @CRLF ) Return EndIf MsgBox( 0, "Sender: $tStruct1", _ "Struct Size: " & DllStructGetSize( $tStruct1 ) & @CRLF & _ "Struct pointer: " & DllStructGetPtr( $tStruct1 ) & @CRLF & _ "Data:" & @CRLF & _ " " & DllStructGetData( $tStruct1, "var1" ) & @CRLF & _ " " & DllStructGetData( $tStruct1, "var2" ) & @CRLF & _ " " & DllStructGetData( $tStruct1, "var3" ) & @CRLF & _ " " & DllStructGetData( $tStruct1, "var4" ) ) EndFunc The DllStruct is copied from the example for the DllStructCreate() function in the help file. AccVars_DllStructToBinary() converts the DllStruct to Binary using the techniques from Accessing AutoIt Variables. The function is discussed below. $tagStruct and $dBinary are stored in a dictionary object and sent using the Sender() function. The original data in $tStruct1 looks like this in a MsgBox: Struct Size: 140 Struct pointer: 0x00B64EA8 Data: -1 255 4294967295 hello Receiver.au3: #include "..\..\Includes\IPCROT_ReceiverDebug.au3" Example() Func Example() ; Get $oDict Local $oDict, $hDebug IPCROT_Receiver( $hDebug, "DllStruct", $oDict ) Local $iError = @error, $iExtended = @extended If $iError Then MsgBox( 0, "Receiver", "@error = " & $iError & ", @extended = " & $iExtended & @CRLF ) Return EndIf Local $tagStruct = $oDict( "$tagStruct" ) Local $dBinary = $oDict( "$dBinary" ) ; Convert Binary to DllStruct Local $iSize = BinaryLen( $dBinary ) Local $tBytes = DllStructCreate( "byte[" & $iSize & "]" ) DllStructSetData( $tBytes, 1, $dBinary ) Local $tStruct2 = DllStructCreate( $tagStruct, DllStructGetPtr( $tBytes ) ) MsgBox( 0, "Receiver: $tStruct2", _ "Struct Size: " & DllStructGetSize( $tStruct2 ) & @CRLF & _ "Struct pointer: " & DllStructGetPtr( $tStruct2 ) & @CRLF & _ "Data:" & @CRLF & _ " " & DllStructGetData( $tStruct2, "var1" ) & @CRLF & _ " " & DllStructGetData( $tStruct2, "var2" ) & @CRLF & _ " " & DllStructGetData( $tStruct2, "var3" ) & @CRLF & _ " " & DllStructGetData( $tStruct2, "var4" ) ) EndFunc The dictionary object is received by the Receiver() function and $tagStruct and $dBinary are extracted. Converting the Binary data back to a DllStruct is straightforward. The received data in $tStruct2 looks like this in a MsgBox: Struct Size: 140 Struct pointer: 0x00C80510 Data: -1 255 4294967295 hello AccVars_DllStructToBinary() AccVars_DllStructToBinary() is included in AccVars.au3, which is a mini version of Accessing AutoIt Variables UDF. The function is used to convert a DllStruct to Binary. Func AccVars_DllStructToBinary( ByRef $tStruct, ByRef $dBinary ) ; Convert $tStruct to a DllStruct of bytes Local $iSize = DllStructGetSize( $tStruct ) Local $tByteArray = DllStructCreate( "byte[" & $iSize & "]", DllStructGetPtr( $tStruct ) ) ; Create a safearray to store the $tByteArray struct Local $tsaBound = DllStructCreate( $tagSAFEARRAYBOUND ) DllStructSetData( $tsaBound, "cElements", $iSize ) ; Size of safearray = size of $tByteArray struct DllStructSetData( $tsaBound, "lLbound", 0 ) Local $pSafeArray = SafeArrayCreate( $VT_UI1, 1, $tsaBound ) ; $VT_UI1 = safearray of bytes ; Get access to safearray data Local $pArrayData, $tArrayData SafeArrayAccessData( $pSafeArray, $pArrayData ) ; Get access to safearray data through an AutoIt DllStruct $tArrayData = DllStructCreate( "byte[" & $iSize & "]", $pArrayData ) ; Store $tByteArray in the safearray data area DllStructSetData( $tArrayData, 1, DllStructGetData( $tByteArray, 1 ) ) ; Unaccess safearray data SafeArrayUnaccessData( $pSafeArray ) ; Convert the safearray to the native AutoIt binary data type AccessVariables02( AccVars_ByteArrayToBinary, $pSafeArray, $dBinary ) EndFunc Func AccVars_ByteArrayToBinary( $pvSafeArray, $pvBinary ) ; $pvSafeArray is a variant that contains a pointer to a safearray Local $pSafeArray = DllStructGetData( DllStructCreate( "ptr", $pvSafeArray + 8 ), 1 ) ; Set $pvBinary to match a standard COM bytearray. A standard ; COM bytearray is a safearray of bytes stored inside a variant. ; Set vt element to $VT_ARRAY + $VT_UI1 (safearray of bytes) DllStructSetData( DllStructCreate( "word", $pvBinary ), 1, $VT_ARRAY + $VT_UI1 ) ; Set data element to safearray pointer DllStructSetData( DllStructCreate( "ptr", $pvBinary + 8 ), 1, $pSafeArray ) ; On function exit, the standard COM bytearray is converted to the native AutoIt binary data type ; This conversion is performed by internal AutoIt functions implemented as compiled C/C++ code EndFunc AccessVariables02() is defined in AccVars.au3. The whole purpose of using the techniques of Accessing AutoIt Variables is to exploit the internal COM conversions implemented in compiled C/C++ code to do all the hard work. Alternatively, it's possible to make the same conversions in a loop in (slow) interpreted AutoIt code. The Variant and Safearray UDFs are copied directly from Variants and Safearrays. Large array In Examples\4) Large array\, an array of 250,000 rows and 10 columns is created and sent from Sender to Receiver. In the debug windows you can see how long each sub-task takes. At the Receiver, the array is displayed in a virtual ArrayDisplay. The array is created with the functions of Fast Array Sorting and Management Functions UDF. Although this example is mostly about compiled code, most functions are also implemented in pure AutoIt code. One of these functions, FAS_Random2DArrayAu3(), is used to create the array. The function is found in Examples\Data Display\Resources\. A few code lines have been added to generate progress bar information. Examples\8) Two concurrent data transfers\ is also about large arrays. Other examples5) Array of arrays\ and 6) Array of objects\ is about arrays with embedded data. You can also create an array of embedded DllStructs. But then the DllStructs must be converted to Binary before the array is sent from Sender to Receiver. Arrays in the examples are 1D and 2D arrays. But it can also be 3D and 4D arrays. All valid AutoIt arrays are likely to work. 7) Two way data transfer\ demonstrates how to implement two-way data transfer. 7z-fileThe 7z-file contains source code for the UDF and examples. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. IPCviaROTobjects.7z2 points -
Regular expression, strip quoted string literals
Professor_Bernd reacted to guinness for a topic
Just wondering if there is another approach to replacing quoted string literals in an AutoIt Script file. #include <Constants.au3> Local $sData = FileRead(@ScriptFullPath) ; Strip double/single quote strings. Topic: http://stackoverflow.com/questions/4462646/how-can-i-remove-quoted-string-literals-from-a-string-in-c $sData = StringRegExpReplace($sData, "([""'])(?:(?!\1).)*\1(\h*)", "''\2") ; Modified by guinness. MsgBox($MB_SYSTEMMODAL, '', $sData)1 point -
different feature sets depending on the user's group membership - how?
argumentum reacted to orbs for a topic
@water, AD is not always present for my program. although the program is typically installed on domain pc's, there was a need to install it also on a standalone pc, and there may be other such installations. hence the resolution to use local groups, which makes the installation procedure identical for all pc's. for the sysadmin managing the permissions, the AD-dependent installations rely on the AD group membership, and non-AD installations rely on local groups. from the program perspective, there is no difference - only local permissions are examined. this simplifies the programming - i don't need to write extra code to distinguish between AD and standalone installations. the said folders have no use whatsoever except of checking the user permissions. the reports produced are sent to the user's documents folder (which is a show of bad taste on my part, i admit...). @argumentum, users neither know nor care of these folders, nor should they. these folders are for internal use only bt my program, and only for checking permissions. using a network share or other network resource (on which i can apply permissions) is not relevant for my case, because i must accommodate for standalone installations (without AD present). i realize this is not a normal or a standard scenario, and i am trying to explain it the best i can. the method i'm using is a crude workaround (work very far around it seems...), so i'm pretty much stuck with local groups. hence, let me rephrase my question: different feature sets depending on the user's local group membership - how?1 point -
UsageAn obvious use of ROT objects is in connection with tasks such as inter-process communication (IPC) and job processing. The advantage of using ROT objects for these tasks is partly that you can handle large amounts of data and partly that you can handle the vast majority of AutoIt data types. Using a ROT object it's very easy to transfer arrays between two different processes. At the same time, the internal data types of the array elements are preserved. If an array containing integers, floats, and strings is passed from a sender to a recipient, then it's still integers, floats, and strings at the recipient. This means that the recipient can sort the array with exactly the same result as a sort of the array at the sender. Not just simple data types are preserved. If an array element contains another array (embedded array) or an object (embedded object), then this embedded array or object is still valid at the recipient. ROT objects are based on COM techniques. How is it possible that proprietary AutoIt data types such as arrays, can be transferred between a sender process and a receiver process using a technique based on standard COM data types? This is possible because the AutoIt array is converted to a safearray of variants (default COM array) at the sender and converted back to an AutoIt array at the receiver. But en route between sender and recipient it's a safearray. These conversions are performed automatically by internal AutoIt code (compiled C/C++ code, very fast). If you are interested you can find more information on these topics in Accessing AutoIt Variables. Passing array between AutoIt programsExamples\2) IPC Demo\Array\ contains two files that very simply demonstrate the exchange of arrays between programs running in two different processes. The example is a copy of the example in this thread but implemented with the new IRunningObjectTable UDF. 1) Server.au3: #include <Array.au3> #include "..\..\..\Includes\IRunningObjectTable.au3" Example() Func Example() MsgBox( 0, "Server", "This is server" ) Local $sDataTransferObject = "DataTransferObject" & ROT_CreateGUID() ROT_RegisterObject( Default, $sDataTransferObject ) ; Default => Object = Dictionary object Local $oDataTransferObject = ObjGet( $sDataTransferObject ) ; Dictionary object ; Create array Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 9 $aArray[$i][$j] = $i & "/" & $j Next Next _ArrayDisplay( $aArray, "Array on server" ) ; Transfer data $oDataTransferObject.Add( "$aArray", $aArray ) ; Start client RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & '"2) Client.au3" ' & $sDataTransferObject ) ; ------- Server waiting while client is executing ------- MsgBox( 0, "Server", "This is server again" ) ; Receive data on server $aArray = $oDataTransferObject.Item( "$aArray" ) _ArrayDisplay( $aArray, "Modified array on server" ) EndFunc 2) Client.au3: #include <Array.au3> Example() Func Example() MsgBox( 0, "Client", "This is client" ) ; Data transfer object Local $sDataTransferObject = $CmdLine[1] Local $oDataTransferObject = ObjGet( $sDataTransferObject ) ; Receive data on client Local $aArray = $oDataTransferObject.Item( "$aArray" ) _ArrayDisplay( $aArray, "Array on client" ) ; Modify array on client For $i = 0 To 100 - 1 $aArray[$i][0] = "Modified" $aArray[$i][1] = "on" $aArray[$i][2] = "client" Next _ArrayDisplay( $aArray, "Modified array on client" ) ; Transfer data $oDataTransferObject.Item( "$aArray" ) = $aArray EndFunc Passing array between AutoIt and VBScriptBecause ROT objects are based on standard COM code, it's possible to exchange data between an AutoIt program and other COM compatible programs e.g. VBScript. The files in Examples\3) IPC Demo2\VBScript\ demonstrate this: 1) Server.au3: #include <GUIConstantsEx.au3> #include "..\..\..\Includes\IRunningObjectTable.au3" Example() Func Example() Local $sArray = "ArrayData" ROT_RegisterObject( Default, $sArray ) ; Default => Object = Dictionary object Local $oArray = ObjGet( $sArray ) ; Dictionary object Local $aArray = [ 123, 123.123, "This is data from AutoIt" ] $oArray( "Array" ) = $aArray Local $sText = "Data exchange between AutoIt and VBScript" Local $hGui = GUICreate( $sText, 400, 300 ) $sText = "Run Client.vbs:" & @CRLF & _ "Open a Command Prompt in the current folder." & @CRLF & _ "Key in ""wscript Client.vbs"" and hit the Enter key." & @CRLF & @CRLF & _ "When you have seen the information in the MsgBox, press the button below." GUICtrlCreateLabel( $sText, 20, 60, 360, 80 ) $sText = "Press Button to continue" Local $idButton = GUICtrlCreateButton( $sText, 20, 180, 360, 30 ) GUISetState( @SW_SHOW, $hGui ) While 1 Switch GUIGetMsg() Case $idButton $aArray = $oArray( "Array" ) MsgBox( 0, "AutoIt: Array from VBScript", "Int: " & $aArray[0] & " (" & VarGetType( $aArray[0] ) & ")" & @CRLF & _ "Flt: " & $aArray[1] & " (" & VarGetType( $aArray[1] ) & ")" & @CRLF & _ "Str: " & $aArray[2] & " (" & VarGetType( $aArray[2] ) & ")" ) Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd GUIDelete( $hGui ) EndFunc Client.vbs: Dim oArray, iAnswer Set oArray = GetObject( "ArrayData" ) iAnswer = MsgBox( "Int: " & oArray( "Array" )(0) & vbCrLf & _ "Flt: " & oArray( "Array" )(1) & vbCrLf & _ "Str: " & oArray( "Array" )(2), 0, "VBScript: Array from AutoIt" ) Dim aArray aArray = Array( 234, 234.234, "This is data from VBScript" ) oArray( "Array" ) = aArray Examples with programs like C# and VB.NET are probably more interesting than VBScript. This way, you can transfer (large) arrays from AutoIt to C# and VB.NET, perform array calculations in compiled code, and return arrays or results back to AutoIt. Here, the AutoIt and C#/VB.NET code are standalone programs that run in their own processes and are connected only through the ROT object. It's a new option to execute code sections that are bottlenecks in interpreted AutoIt code as compiled and possibly multithreaded C#/VB.NET code. Note that such a technique is very different from the technique in Using C# and VB Code in AutoIt through the .NET Framework, where all code runs in the same process. Passing data through ROT Objects (2020-07-11)In IPC Techniques through ROT Objects (Data types section) the AutoIt data types have been tested based on the example for the VarGetType() function in the help file. The data types are sent from Sender to Receiver with these results: $aArray : Array variable type. $dBinary : Binary variable type. $bBoolean : Bool variable type. $pPtr : Int32 variable type. $hWnd : Int32 variable type. $iInt : Int32 variable type. $fFloat : Double variable type. $oObject : Object variable type. $sString : String variable type. $tStruct : Not recognized as a valid variable type. $vKeyword : Keyword variable type. fuMsgBox : Not recognized as a valid variable type. $fuFunc : Not recognized as a valid variable type. $fuUserFunc : Not recognized as a valid variable type. Only the $tStruct and the function data types are not received correctly. The Int32 types for $pPtr and $hWnd can easily be converted to pointer and window handles with the Ptr() and HWnd() functions. In the following section (DllStruct section) it's shown how the $tStruct can be sent by converting the DllStruct to Binary data. In the Large array section (still in the IPC Techniques example) it's shown that even very large arrays can be passed with ROT objects. AutoIt/Perl integration is an example showing how to pass data back and forth between AutoIt and Perl scripts. Also between different programming languages, the data types are preserved with this technique.1 point
-
Message hook will let you do it : #include <WinAPI.au3> #include <GUIConstants.au3> GUICreate(" My GUI input control", 320, 120, @DesktopWidth / 2 - 160, @DesktopHeight / 2 - 45, -1) Local $idInput = GUICtrlCreateInput("", 10, 5, 300, 20) $wProcHandle = DllCallbackRegister("_WindowProc", "ptr", "hwnd;uint;wparam;lparam") $wProcOld = _WinAPI_SetWindowLong(GUICtrlGetHandle($idInput), $GWL_WNDPROC, DllCallbackGetPtr($wProcHandle)) GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd DllCallbackFree($wProcHandle) Func _WindowProc($hWnd, $Msg, $wParam, $lParam) If $hWnd = GUICtrlGetHandle($idInput) And $Msg = $WM_LBUTTONDOWN Then ConsoleWrite("-> Left mouse simple click" & @LF) EndIf Return _WinAPI_CallWindowProc($wProcOld, $hWnd, $Msg, $wParam, $lParam) EndFunc ;==>_WindowProc1 point
-
Hi @LarsJ, thanks for this udf, it looks very powerful ...I'm already playing it ... I'm posting this just for a small problem on the examples in the part that starts another script, namely: ; Start child ShellExecuteWait( "2) Child.au3" ) it may not work as expected if AutoIt was installed with the "edit a script" option instead of "running a script" on a double click or shellexecute() on an .au3 file (as in my case) in that case, you can use something like this instead using Run or RunWait as appropriate, i.e. depending on ShellExecute or ShellExecuteWait: ; Start child RunWait(@AutoItExe & " /AutoIt3ExecuteScript " & '"2) Child.au3"') Thanks again1 point
-
Regular expression, strip quoted string literals
Professor_Bernd reacted to czardas for a topic
I wrote this a while ago. It seems to work. I haven't looked closely at your RegExp versions, but perhaps the code is worth posting. ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __StripOutStrings ; Description ...: Removes all strings wrapped in quotes from the code. ; Syntax.........: __StripOutStrings(ByRef $sCodeStr) ; Parameters ....: $sCodeStr - The string to alter. ; Return values .: [ByRef] the string after removing all strings wrapped in quotes ; Author ........: czardas ; Modified.......: ; Remarks .......: ; Related .......: None ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __StripOutStrings(ByRef $sCodeStr) Local $foo, $bar, $iStart, $iEnd, $aQuot While 1 $foo = StringInStr($sCodeStr, '"') ; Double quote $bar = StringInStr($sCodeStr, "'") ; Single quote If $foo = 0 And $bar = 0 Then ExitLoop If $foo > $bar And $bar > 0 Then $iStart = $bar $sQuot = "'" Else $iStart = $foo $sQuot = '"' EndIf $iEnd = StringInStr($sCodeStr, $sQuot, 0, 2) If $iEnd = 0 Then ; Error Code??? $sCodeStr = StringLeft($sCodeStr, $iStart -1) Else $sCodeStr = StringLeft($sCodeStr, $iStart -1) & " " & StringRight($sCodeStr, StringLen($sCodeStr) - $iEnd) EndIf WEnd EndFunc ;==> __StripOutStrings1 point -
Regular expression, strip quoted string literals
Professor_Bernd reacted to PhoenixXL for a topic
Almost the same #include <Constants.au3> Local $sData = FileRead(@ScriptFullPath) $sData = StringRegExpReplace($sData, "([""']).*?\1", "") MsgBox($MB_SYSTEMMODAL, '', $sData)Have a look Check the function to strip the Comments and Strings Regards1 point