Leaderboard
Popular Content
Showing content with the highest reputation on 12/25/2020 in all areas
-
The Running Object Table (ROT) is a system global table where objects can register themselves. This makes the objects accessible in processes other than the process where the object was created. IRunningObjectTable and related interfaces provides access to register and maintain objects in the ROT. ThreadsOther threads related to ROT objects: Non-blocking data display functions IPC Techniques through ROT Objects AutoIt and Perl integration through ROT objects Access AutoIt by trancexx is about executing AutoIt commands in other programming languages. The AutoIt command is executed by calling a Call method of the ROT object. The example is based on the AutoItObject UDF. Posts (2021-01-03)This is a list of the most interesting posts below: Usage section with typical examples of the use of ROT objects with the following subsections: Passing array between AutoIt programs Passing array between AutoIt and VBScript Passing data through ROT Objects Executing Object Methods through VBScript VBScript (2021-01-03)VBScript is used as a consistent programming language to demonstrate the ROT technique for communicating between AutoIt and other languages. This is a list of the VBScript posts: Passing array between AutoIt and VBScript (in middle of post) Executing Object Methods through VBScript BasicRegister an objectExamples\1) Basic\0) ROT_RegisterObject.au3 #include <Array.au3> #include "..\..\Includes\IRunningObjectTable.au3" Example() Func Example() Local $sNameId = "DataTransferObject" & ROT_CreateGUID() Local $iHandle = ROT_RegisterObject( Default, $sNameId ) ; Default => Object = Dictionary object If Not $iHandle Then Return ConsoleWrite( "ROT_RegisterObject ERR" & @CRLF ) ConsoleWrite( "ROT_RegisterObject OK" & @CRLF ) Local $aROT_List = ROT_Enumerate() _ArrayDisplay( $aROT_List, "ROT_RegisterObject" ) EndFunc Output in _ArrayDisplay looks like this: DataTransferObject-{05DCB964-FD4B-40EC-A95A-999491347D20} $sNameId (similar to ProgID) is the identification of the ROT object and is used in the ObjGet() function to access the object in this way: Local $oDataTransferObject = ObjGet( "DataTransferObject-{05DCB964-FD4B-40EC-A95A-999491347D20}" ) ROT_CreateGUID() is used to make $sNameId unique. See below. ROT_RegisterObject() is the function that registers the object in the ROT. The Dictionary object is the actual object that is registered in the ROT. The Add method allows you to add a new key/item pair to the object. The key is often a string. The item property can be any COM compatible data type which includes most AutoIt data types. An exception is the DllStruct type which must be converted to a compatible type. Because many different data types can be used in the item property and the item can be identified through a key, the Dictionary object is generally applicable for many different purposes. More information about registering objects in the ROT can be found in this Microsoft documentation. ROT_Enumerate() enumerate the objects, that are registered in the ROT. The program that registers an object in the ROT plays the role of server. One or more programs that access the ROT object with the ObjGet() function play the role of clients. The ROT object is only available as long as the server program is running or until the server program deletes the object with the ROT_Revoke() function. You can find examples of using the functions in Examples\1) Basic\. ROT objects (2020-07-11)The Dictionary object is the default object in the ROT_RegisterObject() function. The object that's passed to this function is the actual object that's registered in the ROT. The Dictionary object works fine when passing data between AutoIt scripts, between AutoIt and VBScript, and between AutoIt and Perl. However, situations may easily arise where it can be an advantage to pass data with a very simple object with just a single property. There are several options for creating such a simple object. This can be done through C# and VB.NET code, as demonstrated in Using C# and VB Code in AutoIt through .NET Framework. And it can be done through the AutoItObject UDF. Examples\4) ROT Objects\ contains examples for creating the ROT object in these three ways. Client.au3 is the same script in all examples: #include <Array.au3> Example() Func Example() Local $sNameId = "DataTransfer" Local $oDataTransfer = ObjGet( $sNameId ) Local $aArray = $oDataTransfer.Item _ArrayDisplay( $aArray ) EndFunc Create object with C# code CSharp\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "..\DotNetAll.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next Local $oNetCode = DotNet_LoadCScode( FileRead( "Object.cs" ), "System.dll" ) Local $oCSObject = DotNet_CreateObject( $oNetCode, "CSObjClass" ) $oCSObject.Item = $aArray Local $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oCSObject ), $sNameId ) RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) EndFunc CSharp\Object.cs: using System; public class CSObjClass { public object Item { get; set; } } Create object with VB.NET code VB.NET\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "..\DotNetAll.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next Local $oNetCode = DotNet_LoadVBcode( FileRead( "Object.vb" ), "System.dll" ) Local $oVBObject = DotNet_CreateObject( $oNetCode, "VBObjClass" ) $oVBObject.Item = $aArray Local $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oVBObject ), $sNameId ) RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) EndFunc VB.NET\Object.vb: Imports System Public Class VBObjClass Public Property Item As Object End Class In AutoIt/Perl integration, the very first attempts were performed with the VB.NET object. Check for recognition of the ROT object with this Client.pl script (copied from the AutoIt/Perl example) : use strict; use Win32::OLE; my $oObj = Win32::OLE->GetObject( "DataTransfer" ); Win32::OLE->EnumAllObjects( sub { my $Object = shift; my $Class = Win32::OLE->QueryObjectType( $Object ); printf "Object = %s, Class = %s\n", $Object, $Class; } ); Gave the following output: Object = Win32::OLE=HASH(0x72a51c), Class = _VBObjClass ; VB.NET object Object = Win32::OLE=HASH(0x71b5a8), Class = IDictionary ; Dictionary object Create object with AutoItObject AutoItObject\Server.au3: #include "..\..\..\Includes\IRunningObjectTable.au3" #include "AutoitObject.au3" Example() Func Example() Local $aArray[1000][10] For $i = 0 To 1000 - 1 For $j = 0 To 10 - 1 $aArray[$i][$j] = $i & "/" & $j Next Next _AutoItObject_StartUp() Local $oObject = NewObject(), $sNameId = "DataTransfer" ROT_RegisterObject( Ptr( $oObject ), $sNameId ) Local $oDataTransfer = ObjGet( $sNameId ) $oDataTransfer.Item = $aArray RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & "Client.au3" ) _AutoItObject_Shutdown() EndFunc Func NewObject() Local $oClassObject = _AutoItObject_Class() $oClassObject.AddProperty( "Item" ) Return $oClassObject.Object EndFunc Unique objectsWhen using ROT objects in real code, there is a particular question that needs to be addressed. The question is how to make sure that $sNameId, which clients use to access the object with the ObjGet() function, actually identifies a unique object. Running a server program twice in succession can easily create two ROT objects with the same $sNameId. But how do you actually access the ROT object that was created first and the ROT object that was created last? The answer to the question is to make sure that $sNameId also becomes unique so that you can distinguish between the two objects. To that end, the ROT_CreateGUID() function is created (copy of _WinAPI_CreateGUID()). The function can ensure a unique $sNameId as shown in the example above. The problem and solution is demonstrated in Examples\1) Basic\2) Multiple ROT objects.au3. Time stampsUsing the NoteChangeTime() and GetTimeOfLastChange() methods of the IRunningObjectTable interface, you can set and get timestamps on a ROT object. But these timestamps do not seem particularly useful. Therefore, the methods are not implemented. The UDFThe IRunningObjectTable UDF, Includes\IRunningObjectTable.au3, is a very small UDF with less than 150 lines of code: #include-once ; --- Interface definitions --- Global Const $sIID_IRunningObjectTable = "{00000010-0000-0000-C000-000000000046}" Global Const $dtag_IRunningObjectTable = _ "Register hresult(dword;ptr;ptr;dword*);" & _ "Revoke hresult(dword);" & _ "IsRunning hresult(ptr);" & _ "GetObject hresult(ptr;ptr*);" & _ "NoteChangeTime hresult(dword;struct*);" & _ "GetTimeOfLastChange hresult(ptr;ptr*);" & _ "EnumRunning hresult(ptr*);" Global Const $ROTFLAGS_REGISTRATIONKEEPSALIVE = 0x1 Global Const $ROTFLAGS_ALLOWANYCLIENT = 0x2 Global Const $sIID_IEnumMoniker = "{00000102-0000-0000-C000-000000000046}" Global Const $dtag_IEnumMoniker = _ "Next hresult(ulong;ptr*;ulong*);" & _ "Skip hresult(ulong);" & _ "Reset hresult();" & _ "Clone hresult(ptr*);" Global Const $sIID_IPersist = "{0000010C-0000-0000-C000-000000000046}" Global Const $dtag_IPersist = _ "GetClassID hresult(ptr*);" Global Const $sIID_IPersistStream = "{00000109-0000-0000-C000-000000000046}" Global Const $dtag_IPersistStream = $dtag_IPersist & _ "IsDirty hresult();" & _ "Load hresult(ptr);" & _ "Save hresult(ptr;bool);" & _ "GetSizeMax hresult(uint*);" Global Const $sIID_IMoniker = "{0000000F-0000-0000-C000-000000000046}" Global Const $dtag_IMoniker = $dtag_IPersistStream & _ "BindToObject hresult();" & _ "BindToStorage hresult();" & _ "Reduce hresult();" & _ "ComposeWith hresult();" & _ "Enum hresult();" & _ "IsEqual hresult();" & _ "Hash hresult();" & _ "IsRunning hresult(ptr;ptr;ptr);" & _ "GetTimeOfLastChange hresult(ptr;ptr;ptr);" & _ "Inverse hresult();" & _ "CommonPrefixWith hresult();" & _ "RelativePathTo hresult();" & _ "GetDisplayName hresult(ptr;ptr;wstr*);" & _ "ParseDisplayName hresult();" & _ "IsSystemMoniker hresult(ptr*);" ; --- Windows API functions --- Func ROT_GetRunningObjectTable() Return DllCall( "Ole32.dll", "long", "GetRunningObjectTable", "dword", 0, "ptr*", 0 )[2] EndFunc Func ROT_CreateFileMoniker( $sNameId ) Return DllCall( "Ole32.dll", "long", "CreateFileMoniker", "wstr", $sNameId, "ptr*", 0 )[2] EndFunc Func ROT_CreateBindCtx() Return DllCall( "Ole32.dll", "long", "CreateBindCtx", "dword", 0, "ptr*", 0 )[2] EndFunc ; --- UDF functions --- ; Failure: Returns 0 ; Success: Returns $iHandle ; Registers an object and its identifying moniker in the ROT Func ROT_RegisterObject( $pObject, $sNameId, $iFlags = $ROTFLAGS_REGISTRATIONKEEPSALIVE ) If $pObject = Default Then Local $oDict = ObjCreate( "Scripting.Dictionary" ) $pObject = Ptr( $oDict ) EndIf If Not $pObject Or Not $sNameId Then Return 0 Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Local $pMoniker = ROT_CreateFileMoniker( $sNameId ) If Not $pMoniker Then Return 0 Local $iHandle $oRunningObjectTable.Register( $iFlags, $pObject, $pMoniker, $iHandle ) Return $iHandle ? $iHandle : 0 EndFunc ; Returns unique GUID as string ; Copied from _WinAPI_CreateGUID Func ROT_CreateGUID() Local Static $tGUID = DllStructCreate( "struct;ulong Data1;ushort Data2;ushort Data3;byte Data4[8];endstruct" ) DllCall( "Ole32.dll", "long", "CoCreateGuid", "struct*", $tGUID ) Return "-" & DllCall( "Ole32.dll", "int", "StringFromGUID2", "struct*", $tGUID, "wstr", "", "int", 65536 )[2] EndFunc ; Failure: Returns 0 ; Success: Returns $aROT_List ; Enumerates objects and identifying monikers in the ROT Func ROT_Enumerate() Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Local $pEnumMoniker $oRunningObjectTable.EnumRunning( $pEnumMoniker ) Local $oEnumMoniker = ObjCreateInterface( $pEnumMoniker, $sIID_IEnumMoniker, $dtag_IEnumMoniker ) If Not IsObj( $oEnumMoniker ) Then Return 0 Local $pMoniker, $oMoniker, $pBindCtx, $sMonikerName, $i = 0 Local $oDict = ObjCreate( "Scripting.Dictionary" ) While( $oEnumMoniker.Next( 1, $pMoniker, NULL ) = 0 ) $pBindCtx = ROT_CreateBindCtx() $oMoniker = ObjCreateInterface( $pMoniker, $sIID_IMoniker, $dtag_IMoniker ) $oMoniker.GetDisplayName( $pBindCtx, NULL, $sMonikerName ) $oDict.Add( "Key" & $i, $sMonikerName ) $i += 1 WEnd Local $aROT_List = $oDict.Items() Return $aROT_List EndFunc ; Failure: Returns 0 ; Success: Returns 1 ; Removes an object and its identifying moniker from the ROT Func ROT_Revoke( $iHandle ) If Not $iHandle Then Return 0 Local $oRunningObjectTable = ObjCreateInterface( ROT_GetRunningObjectTable(), $sIID_IRunningObjectTable, $dtag_IRunningObjectTable ) If Not IsObj( $oRunningObjectTable ) Then Return 0 Return Not $oRunningObjectTable.Revoke( $iHandle ) * 1 EndFunc 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. IRunningObjectTable.7z1 point
-
Version 1.7.0.1
10,048 downloads
Extensive library to control and manipulate Microsoft Outlook. This UDF holds the functions to automate items (folders, mails, contacts ...) in the background. Can be seen like an API. There are other UDFs available to automate Outlook: OutlookEX_GUI: This UDF holds the functions to automate the Outlook GUI. OutlookTools: Allows to import/export contacts and events to VCF/ICS files and much more. Threads: Development - General Help & Support - Example Scripts - Wiki BTW: If you like this UDF please click the "I like this" button. This tells me where to next put my development effort KNOWN BUGS (last changed: 2020-02-09) None1 point -
Non-focusable GUI does not give focus after calling "evil" functions
Professor_Bernd reacted to mikell for a topic
Your analysis makes sense. Comments transmitted to a Dev Glad I could help anyway1 point -
Non-focusable GUI does not give focus after calling "evil" functions
Professor_Bernd reacted to mikell for a topic
I don't really understand the purpose of the thing but this seems to work Func _WinGetCaretPos() If GUIGetCursorInfo($hMy_GUI) <> null Then Return ...1 point -
Help understanding StringRegExp.
abberration reacted to Bert for a topic
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