Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 03/29/2022 in all areas

  1. Latest update just released. See below for change log.
    2 points
  2. 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.7z
    1 point
  3. From MiniMax to Machine Learning ... Tic Tac Toe is a good game for studying AI algorithm because it's simple! I use Tabular Q Learning to implement this game, Every time a game finished, it will use the Q function to update the score of each steps it played. Q(S,A) = Q(S,A) + α ∗ (γ ∗ maxaQ(S′,a) − Q(S,A)) S being the current state, A the current action, S′ the state after doing A, α being the learning rate, γ being the discount factor, and maxaQ(S′,a) the highest Q value of any move in the next state S′, i.e. the Q value of the best move in the following state. It's funny to see that it plays better and better. That's why people were charmed by Machine Learning! Thank you! Download: tic_tac_toe.zip
    1 point
  4. Nine

    Date Range Picker

    In this thread, it was asked if there was a Date Range Picker somewhere. Couldn't find one. With @Zedna calendar with @maniootek proposal, I felt it could be fun to create one. So here it is. Like always, if you have some suggestions, I am open to any. Version 2022-04-10 *Window drag can now be performed anywhere with the background of the GUI (non-control space) * Clicking on the month label, select the whole month Version 2020-12-05 * Standardized presentation of month calendar where column 1 is Sunday and column 7 is Saturday. Version 2020-11-04 * Dates selection using Shift-Click inside a single month or between months * Auto-multi lingual Hope you like it. Date Range Picker.au3
    1 point
  5. You should know by now that providing a basic example (runable snippet of code) of the issue you are facing will greatly help us to help you.
    1 point
  6. Try with this line at the top of your script : If @OSArch = "X64" And Not @AutoItX64 Then _WinAPI_Wow64EnableWow64FsRedirection(False)
    1 point
  7. This is an example script, showing how to avoid having Richedit control stealing focus from other controls. I have seen several person on the forum having the same issue as me. When using a RichEdit Control in a chat software, RichEdit steals focus from the Input everytime a user posts a message. I think I found a work around : find a way to append the text without making a text selection, because the selection moves the caret in the richedit control. Problems and solutions I found : 1 - "_GUICtrlRichEdit_AppendText" Steals focus because there is "_GuiCtrlRichEdit_SetSel" in the function ( "_GuiCtrlRichEdit_SetSel" is used to input the text at the end of the richedit control, and also used to scroll the page to the last line ). --- > AppendText Solution = I use "_GUICtrlEdit_AppendText" from "GuiEdit.au3". It appends the text at the end of the Richedit Control, without moving the caret to the richedit control. --- > Scrolling Solution = I used "_GUICtrlRichEdit_ScrollLines" to scroll one line down. Later I'll try to find how many lines really need to be scrolled ( if multiline text ). 2 - "_GUICtrlRichEdit_SetCharColor" Also needs a selection to apply the color. ( _GUICtrlRichEdit_SetFont Doesn't need a selection ) --- > Color solution = I edited the "_GUICtrlRichEdit_SetCharColor" by Jpm ( and named it "_GUICtrlRichEdit_SetCharColor_No_Selection" ) and commented the _GuiCtrlRichEdit_GetSel lines. So the color needs to be chosen before appending the text. Here is an example script showing the problem ( I tried to simulate a chat situation ) : ;INCLUDES #include <GuiRichEdit.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ;OPT Opt("GUIOnEventMode", 1) ;VARIABLES GUI Global $GUI_SIZE_X = 600 Global $GUI_SIZE_Y = 600 Global $GUI_RICHEDIT_SIZE_X = $GUI_SIZE_X Global $GUI_RICHEDIT_SIZE_Y = $GUI_SIZE_Y / 3 ;GUI Global $GUI = GUICreate("Test", $GUI_SIZE_X, $GUI_SIZE_Y) ;RICHEDIT Global $GUI_RICHEDIT = _GUICtrlRichEdit_Create($GUI, "", 0, 0, $GUI_RICHEDIT_SIZE_X, $GUI_RICHEDIT_SIZE_Y * 2, BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY)) ;INPUT Global $sINPUT_TEXT = "Try to Type some text here ! (Then press ENTER to send)" & @CRLF & @CRLF & _ "It's IMPOSSIBLE !" & @CRLF & @CRLF & _ "the _GUICtrlRichEdit_AppendText steals focus from the input all the time, making RichEdit almost unusable in a chat software (Even if you use !" & @CRLF & @CRLF & _ "Also, _GUICtrlRichEdit_SetCharColor needs to have a selection to apply the color on the incoming text. If no Selection, then the color is applied on the whole control" & @CRLF & @CRLF & _ "Even with 'GUICtrlSetState ( $GUI_INPUT, $GUI_FOCUS )' it doesn't help" Global $GUI_INPUT = GUICtrlCreateInput($sINPUT_TEXT, 0, $GUI_RICHEDIT_SIZE_Y * 2, $GUI_SIZE_X, $GUI_RICHEDIT_SIZE_Y, $ES_MULTILINE) GUISetState() GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit") HotKeySet("{ENTER}", "_Send") ;LOOP While 1 ;HERE WE ADD RANDOM TEXT WITH RANDOM COLOR EVERY 'Random' ms (TRY TO SIMULATE A CHAT SITUATION) _Chat_Add_Line($GUI_RICHEDIT, _ "Chat Line " & Random(0, 999999), _ "0x" & StringFormat("%02d", Random(0, 99, 1)) & StringFormat("%02d", Random(0, 99, 1)) & StringFormat("%02d", Random(0, 99, 1)), _ 8) Sleep(Random(50, 2000, 1)) WEnd Func _Send() _Chat_Add_Line($GUI_RICHEDIT, "You Said : " & GUICtrlRead($GUI_INPUT), 0xFF0000, 12) GUICtrlSetState($GUI_INPUT, $GUI_FOCUS) GUICtrlSetData($GUI_INPUT, "") Return 1 EndFunc ;==>_Send Func _Chat_Add_Line($hWnd, $sMessage, $sColor, $iFont) StringReplace(_GUICtrlRichEdit_GetText($hWnd, True), @CRLF, "") Local $iLines = @extended Local $iStart = _GUICtrlRichEdit_GetTextLength($hWnd, True, True) - $iLines _GUICtrlRichEdit_PauseRedraw($hWnd) _GUICtrlRichEdit_AppendText($hWnd, $sMessage & @CRLF) _GUICtrlRichEdit_SetSel($hWnd, $iStart, -1, False) _GUICtrlRichEdit_SetCharColor($hWnd, $sColor) _GUICtrlRichEdit_SetFont($hWnd, $iFont) _GUICtrlRichEdit_Deselect($hWnd) _GUICtrlRichEdit_ResumeRedraw($hWnd) ;---> ( TRY TO UN-COMMENT THE NEXT LINE ) ; HERE WE EVEN TRY TO GIVE BACK THE FOCUS TO THE INPUT, BUT IT DOESN'T HELP ;~ GUICtrlSetState ( $GUI_INPUT, $GUI_FOCUS ) Return 1 EndFunc ;==>_Chat_Add_Line Func _Exit() _GUICtrlRichEdit_Destroy($GUI_RICHEDIT) Exit EndFunc ;==>_ExitAnd Here is my modified version : ;INCLUDES #include <GuiEdit.au3> #include <GuiRichEdit.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ;OPT Opt("GUIOnEventMode", 1) ;VARIABLES GUI Global $GUI_SIZE_X = 600 Global $GUI_SIZE_Y = 600 Global $GUI_RICHEDIT_SIZE_X = $GUI_SIZE_X Global $GUI_RICHEDIT_SIZE_Y = $GUI_SIZE_Y / 3 ;GUI Global $GUI = GUICreate("Test", $GUI_SIZE_X, $GUI_SIZE_Y) ;RICHEDIT Global $GUI_RICHEDIT = _GUICtrlRichEdit_Create($GUI, "", 0, 0, $GUI_RICHEDIT_SIZE_X, $GUI_RICHEDIT_SIZE_Y * 2, BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY)) ;INPUT Global $GUI_INPUT = GUICtrlCreateInput("Type some text here, then press Enter", 0, $GUI_RICHEDIT_SIZE_Y * 2, $GUI_SIZE_X, $GUI_RICHEDIT_SIZE_Y, $ES_MULTILINE) GUISetState() GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit") HotKeySet("{ENTER}", "_Send") ;LOOP While 1 ;HERE WE ADD RANDOM TEXT WITH RANDOM COLOR EVERY 'Random' ms (TRY TO SIMULATE A CHAT SITUATION) _Chat_Add_Line($GUI_RICHEDIT, _ "Chat Line " & Random(0, 999999), _ "0x" & StringFormat("%02d", Random(0, 99, 1)) & StringFormat("%02d", Random(0, 99, 1)) & StringFormat("%02d", Random(0, 99, 1)), _ 8) Sleep(Random(50, 1000, 1)) WEnd Func _Send() _Chat_Add_Line($GUI_RICHEDIT, "You Said : " & GUICtrlRead($GUI_INPUT), 0xFF0000, 12) GUICtrlSetState($GUI_INPUT, $GUI_FOCUS) GUICtrlSetData($GUI_INPUT, "") Return 1 EndFunc ;==>_Send Func _Chat_Add_Line($hWnd, $sMessage, $sColor, $iFont) _GUICtrlRichEdit_PauseRedraw($hWnd) ;SET THE COLOR FOR THE INCOMING TEXT USING THE MODIFIED _GUICtrlRichEdit_SetCharColor THAT DOESN'T STEAL INPUT FOCUS _GUICtrlRichEdit_SetCharColor_No_Selection($hWnd, $sColor) _GUICtrlRichEdit_SetFont($hWnd, $iFont) ;THE "_GUICtrlRichEdit_AppendText" STEALS FOCUS FROM THE INPUT (Because there is a _GuiCtrlRichEdit_SetSel in the function). ;SO I APPEND THE TEXT USING "_GUICtrlEdit_AppendText" FROM "GuiEdit.au3". _GUICtrlEdit_AppendText($hWnd, $sMessage & @CRLF) _GUICtrlRichEdit_ScrollLines($hWnd, 1) _GUICtrlRichEdit_ResumeRedraw($hWnd) Return 1 EndFunc ;==>_Chat_Add_Line ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GUICtrlRichEdit_SetCharColor ; Description....: Sets the color of incoming text inserted at the insertion point ; Syntax ........: _GUICtrlRichEdit_SetCharColor($hWnd[, $iColor]) ; Parameters.....: $hWnd - Handle to the control ; $iColor - one of the following: (Optional) ; |a number - a COLORREF value ; |Default keyword - the system color (default) ; Return values..: Success - True ; Failure - False and sets @error: ; |101 - $hWnd is not a handle ; |1022 - $iColor is invalid ; Authors........: Chris Haslam (c.haslam) ; Modified ......: Jpm, Jmon ; Remarks .......: This Function has been modified to avoid stealing focus from another control ; Related .......: _GUICtrlRichEdit_GetCharColor, _GUICtrlRichEdit_SetCharColor ; Link ..........: @@MsdnLink@@ EM_SETCHARFORMAT ; Example .......: Yes ; =============================================================================================================================== Func _GUICtrlRichEdit_SetCharColor_No_Selection($hWnd, $iColor = Default) If Not IsHWnd($hWnd) Then Return SetError(101, 0, False) Local $tCharFormat = DllStructCreate($tagCHARFORMAT) DllStructSetData($tCharFormat, 1, DllStructGetSize($tCharFormat)) If IsKeyword($iColor) Then DllStructSetData($tCharFormat, 3, $CFE_AUTOCOLOR) $iColor = 0 Else If BitAND($iColor, 0xff000000) Then Return SetError(1022, 0, False) EndIf DllStructSetData($tCharFormat, 2, $CFM_COLOR) DllStructSetData($tCharFormat, 6, $iColor) ;I COMMENTED THOSE NEXT LINES, OTHERWISE THE COLOR WOULD BE APPLIED TO THE WHOLE CONTROL ;~ Local $ai = _GuiCtrlRichEdit_GetSel($hWnd) ;~ If $ai[0] = $ai[1] Then ;~ Return _SendMessage($hWnd, $EM_SETCHARFORMAT, $SCF_ALL, DllStructGetPtr($tCharFormat)) <> 0 ;~ Else Return _SendMessage($hWnd, $EM_SETCHARFORMAT, $SCF_SELECTION, DllStructGetPtr($tCharFormat)) <> 0 ;~ EndIf EndFunc ;==>_GUICtrlRichEdit_SetCharColor_No_Selection Func _Exit() _GUICtrlRichEdit_Destroy($GUI_RICHEDIT) Exit EndFunc ;==>_Exit In Both Example, you can try to type some text in the Input, at the bottom. Use "Enter" to send the text in the Richedit control. Well I hope that solves the problems that others had before. [EDIT1] I ran "tidy" on the scripts for better formatting.
    1 point
  8. Thank you! Your code was really helpful for me. I've put it in a separate au3 header and did some minor changes (without changing any functionality). If anyone is interested: RichEditFocusFix.au3 #include-once #include <GuiEdit.au3> #include <GuiRichEdit.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GUICtrlRichEdit_AppendText_NoFocusSteal ; Description....: Append text to a RichEdit-control without stealing focus ; Authors........: Jmon ; Modified ......: ; Related .......: _GUICtrlRichEdit_SetCharColor_No_Selection ; Link ..........: https://www.autoitscript.com/forum/topic/136089-example-avoid-richedit-stealing-focus-from-other-controls/ ; =============================================================================================================================== Func _GUICtrlRichEdit_AppendText_NoFocusSteal($hWnd, $sMessage, $sColor, $iFontSize = Default) _GUICtrlRichEdit_PauseRedraw($hWnd) ;set the color for the incoming text using the modified _GUICtrlRichEdit_SetCharColor THAT DOESN'T STEAL INPUT FOCUS _GUICtrlRichEdit_SetCharColor_No_Selection($hWnd, $sColor) If $iFontSize <> Default Then _GUICtrlRichEdit_SetFont($hWnd, $iFontSize) ;the _GUICtrlRichEdit_AppendText also STEALS FOCUS FROM THE INPUT (because there is a _GuiCtrlRichEdit_SetSel in the function) ;so text is appended using _GUICtrlEdit_AppendText from "GuiEdit.au3" _GUICtrlEdit_AppendText($hWnd, $sMessage) _GUICtrlRichEdit_ScrollLines($hWnd, 1) _GUICtrlRichEdit_ResumeRedraw($hWnd) Return True EndFunc ;==>_Chat_Add_Line ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GUICtrlRichEdit_SetCharColor ; Description....: Sets the color of incoming text inserted at the insertion point ; Syntax ........: _GUICtrlRichEdit_SetCharColor($hWnd[, $iColor]) ; Parameters.....: $hWnd - Handle to the control ; $iColor - one of the following: (Optional) ; |a number - a COLORREF value ; |Default keyword - the system color (default) ; Return values..: Success - True ; Failure - False and sets @error: ; |101 - $hWnd is not a handle ; |1022 - $iColor is invalid ; Authors........: Chris Haslam (c.haslam) ; Modified ......: Jpm, Jmon ; Remarks .......: This Function has been modified to avoid stealing focus from another control ; Related .......: _GUICtrlRichEdit_GetCharColor, _GUICtrlRichEdit_SetCharColor ; Link ..........: @@MsdnLink@@ EM_SETCHARFORMAT ; Example .......: Yes ; =============================================================================================================================== Func _GUICtrlRichEdit_SetCharColor_No_Selection($hWnd, $iColor = Default) If Not IsHWnd($hWnd) Then Return SetError(101, 0, False) Local $tCharFormat = DllStructCreate($tagCHARFORMAT) DllStructSetData($tCharFormat, 1, DllStructGetSize($tCharFormat)) If IsKeyword($iColor) Then DllStructSetData($tCharFormat, 3, $CFE_AUTOCOLOR) $iColor = 0 Else If BitAND($iColor, 0xff000000) Then Return SetError(1022, 0, False) EndIf DllStructSetData($tCharFormat, 2, $CFM_COLOR) DllStructSetData($tCharFormat, 6, $iColor) Return _SendMessage($hWnd, $EM_SETCHARFORMAT, $SCF_SELECTION, DllStructGetPtr($tCharFormat)) <> 0 EndFunc ;==>_GUICtrlRichEdit_SetCharColor_No_Selection Note: use $WS_VSCROLL and $ES_MULTILINE as RichEdit-Styles (this should fix the scrolling issue that occurs with different font sizes, multi-line texts and wrapping lines)
    1 point
  9. It may not be possible with the subclassing method to intercept the right-click on a combo-box as I have not found the right notification to block it. But with this hook, it is working just fine : #include <WinAPIProc.au3> #include <GUIConstants.au3> #include <WinAPISys.au3> #include <WindowsConstants.au3> #include <WinAPIConstants.au3> #include <Array.au3> Global $hGui = GUICreate("Example") Global $TuneTypes = GUICtrlCreateCombo("", 20, 20, 247, 19) Global $aPos = ControlGetPos ($hGui, "", $TuneTypes) Global $hStub = DllCallbackRegister(MyProc, "LRESULT", "int;wparam;lparam") Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE, DllCallbackGetPtr($hStub), 0, _WinAPI_GetCurrentThreadId()) GUISetState(@SW_SHOW) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete($hGui) _WinAPI_UnhookWindowsHookEx($hHook) DllCallbackFree($hStub) Func MyProc($iMsg, $wParam, $lParam) If $iMsg = 0 Then If $wParam = $WM_RBUTTONDOWN Then Local $tPoint = DllStructCreate($tagPOINT, $lParam) _WinAPI_ScreenToClient($hGui, $tPoint) If $tPoint.X >= $aPos[0] And $tPoint.X < $aPos[0] + $aPos[2] And $tPoint.Y >= $aPos[1] And $tPoint.Y < $aPos[1] + $aPos[3] Then Return 1 EndIf EndIf EndIf Return _WinAPI_CallNextHookEx($hHook, $iMsg, $wParam, $lParam) EndFunc ;==>MyProc ps. next time please provide a runable script so we can test it and modify it without rewriting the whole script for you. Thanks in advance.
    1 point
  10. I don't think that this is something we need to avoid, because it's an internal website and they're meant to reach this website normally. If they were to use the existing profile, the password would be properly provided to the website. This doesn't seem to bypass anything and instead implements the recommended security measures Maybe I'm misunderstanding something and if so, please pm me to shut up
    1 point
  11. Try to use: #AutoIt3Wrapper_UseX64=N #include "wd_helper.au3" #include "wd_capabilities.au3" _Example_2() Func _Example_2() ;~ Local $sSession = _MY__WD_SetupFireFox(False) Local $sSession = _MY__WD_SetupChrome(True) If @error Then Return SetError(@error, @extended) _WD_Navigate($sSession, "https://www.lumex.com/lcd-displays-character-20x2+20x4.html") If @error Then _WD_Shutdown() Return EndIf ; https://www.w3.org/TR/webdriver/#print-page ; https://stackoverflow.com/a/68353518/5314940 ; http://www.polger.wroclaw.pl/Formaty-papieru,51.html Local $s_JSON_PrintOptions = StringReplace( _ ; TABLOID 279.4 x 431.8 = https://www.engineeringtoolbox.com/office-paper-sizes-d_213.html '{' & _ ' "page":{' & _ ' "width": 27.94' & _ ' ,"height": 43.18' & _ ' }' & _ ' ,"margin":{' & _ ' "top": 0' & _ ' ,"bottom": 0' & _ ' ,"left": 0' & _ ' ,"right": 0' & _ ' }' & _ ' ,"scale": 1.0' & _ ' ,"orientation":"portrait"' & _ ' ,"background": true' & _ ' ,"pageRanges": ["1-10"]' & _ '}', @TAB, '') Local $sFileFullPath = @ScriptDir & '\PackingSlip_1_A3.pdf' _Test($sSession, $s_JSON_PrintOptions, $sFileFullPath) _WD_Shutdown() EndFunc ;==>_Example_2 Func _Test($sSession, $sOptions, $sFileFullPath) Local $dBinaryDataToWrite = _WD_PrintToPdf($sSession, $sOptions) Local $hFile = FileOpen($sFileFullPath, $FO_OVERWRITE + $FO_BINARY) FileWrite($hFile, $dBinaryDataToWrite) FileClose($hFile) ShellExecute($sFileFullPath) EndFunc ;==>_Test Func _MY__WD_SetupChrome($b_Headless = False, $s_Download_dir = '', $_WD_DEBUG_LEVEL = Default, $s_Log_FileFullPath = Null) If $_WD_DEBUG_LEVEL = Default Then $_WD_DEBUG = $_WD_DEBUG_Error If Not @Compiled Then $_WD_DEBUG = $_WD_DEBUG_Info EndIf _WD_Option('Driver', 'chromedriver.exe') _WD_Option('Port', 9515) _WD_Option('DefaultTimeout', 1000) _WD_UpdateDriver('chrome') If @error Then Return SetError(@error, @extended, '') # !!! WARRNING !!! AS DEFAULT DO NOT USE '--log-path=' BECAUSE OF GDPR / RODO law rules If $s_Log_FileFullPath = Default Then Local $s_Default_Log_File = @ScriptDir & '\Log\' & @YEAR & @MON & @MDAY & '-' & @HOUR & @MIN & @SEC & ' WebDriver - Chrome - Testing.log' _WD_Option('DriverParams', '--log-path=' & '"' & $s_Default_Log_File & '"') ElseIf IsString($s_Log_FileFullPath) And StringLen($s_Log_FileFullPath) Then _WD_Option('DriverParams', '--log-path=' & '"' & $s_Log_FileFullPath & '"') EndIf _WD_CapabilitiesStartup() _WD_CapabilitiesAdd('alwaysMatch') _WD_CapabilitiesAdd('acceptInsecureCerts', True) _WD_CapabilitiesAdd('firstMatch', 'chrome') _WD_CapabilitiesAdd('browserName', 'chrome') _WD_CapabilitiesAdd('w3c', True) _WD_CapabilitiesAdd('args', 'user-data-dir', 'C:\Users\' & @UserName & '\AppData\Local\Google\Chrome\User Data\Default') _WD_CapabilitiesAdd('args', 'user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win' & StringReplace(@OSArch, 'X', '') & '; ' & @CPUArch & ') AppleWebKit/537.36 (KHTML, like Gecko) Chrome/' & _WD_GetBrowserVersion('chrome') & ' Safari/537.36') _WD_CapabilitiesAdd('args', '--profile-directory', Default) _WD_CapabilitiesAdd('args', 'start-maximized') _WD_CapabilitiesAdd('args', 'disable-infobars') _WD_CapabilitiesAdd('args', '--no-sandbox') _WD_CapabilitiesAdd('args', '--disable-blink-features=AutomationControlled') _WD_CapabilitiesAdd('args', '--disable-web-security') _WD_CapabilitiesAdd('args', '--allow-running-insecure-content') ; https://stackoverflow.com/a/60409220 _WD_CapabilitiesAdd('args', '--ignore-certificate-errors') ; https://stackoverflow.com/a/60409220 _WD_CapabilitiesAdd('prefs', 'credentials_enable_service', False) ; https://www.autoitscript.com/forum/topic/191990-webdriver-udf-w3c-compliant-version-12272021/?do=findComment&comment=1464829 If $b_Headless Then _ _WD_CapabilitiesAdd('args', '--headless') If $s_Download_dir Then _ _WD_CapabilitiesAdd('prefs', 'download.default_directory', $s_Download_dir) _WD_CapabilitiesAdd('excludeSwitches', 'disable-popup-blocking') ; https://help.applitools.com/hc/en-us/articles/360007189411--Chrome-is-being-controlled-by-automated-test-software-notification _WD_CapabilitiesAdd('excludeSwitches', 'enable-automation') _WD_CapabilitiesAdd('excludeSwitches', 'load-extension') _WD_CapabilitiesDump(@ScriptLineNumber & ':WebDriver: testing') Local $s_Capabilities = _WD_CapabilitiesGet() _WD_Startup() If @error Then Return SetError(@error, @extended) Local $WD_SESSION = _WD_CreateSession($s_Capabilities) Return SetError(@error, @extended, $WD_SESSION) EndFunc ;==>_MY__WD_SetupChrome Func _MY__WD_SetupFireFox($b_Headless, $s_Download_dir = '', $_WD_DEBUG_LEVEL = Default, $s_Log_FileFullPath = Null) If $s_Download_dir Then $s_Download_dir = StringReplace($s_Download_dir, '\', '\\') If $_WD_DEBUG_LEVEL = Default Then $_WD_DEBUG = $_WD_DEBUG_Error If Not @Compiled Then $_WD_DEBUG = $_WD_DEBUG_Info EndIf # !!! WARRNING !!! AS DEFAULT DO NOT USE '--log-path=' BECAUSE OF GDPR / RODO law rules If $s_Log_FileFullPath = Default Then Local $s_Default_Log_File = @ScriptDir & '\Log\' & @YEAR & @MON & @MDAY & '-' & @HOUR & @MIN & @SEC & ' WebDriver - FireFox - Testing.log' _WD_Option('DriverParams', '--log-path=' & '"' & $s_Default_Log_File & '"') ElseIf IsString($s_Log_FileFullPath) And StringLen($s_Log_FileFullPath) Then _WD_Option('DriverParams', '--log-path=' & '"' & $s_Log_FileFullPath & '"') EndIf _WD_Option('Driver', 'geckodriver.exe') ;~ _WD_Option('DriverParams', '--log trace --marionette-port 2828') _WD_Option('Port', 4444) _WD_Option('DefaultTimeout', 1000) _WD_Startup() If @error Then Return SetError(@error, @extended, '') _WD_CapabilitiesStartup() _WD_CapabilitiesAdd('alwaysMatch') _WD_CapabilitiesAdd('acceptInsecureCerts', True) _WD_CapabilitiesAdd('firstMatch', 'firefox') ;~ _WD_CapabilitiesAdd('args', '-profile') ;~ _WD_CapabilitiesAdd('args', @LocalAppDataDir & '\Mozilla\Firefox\Profiles\WD_Testing_Profile') ; CHANGE TO PROPER DIRECTORY PATH If $b_Headless Then _ _WD_CapabilitiesAdd('args', '--headless') _WD_CapabilitiesDump(@ScriptLineNumber & ':WebDriver') Local $s_Capabilities = _WD_CapabilitiesGet() _WD_Startup() If @error Then Return SetError(@error, @extended) Local $WD_SESSION = _WD_CreateSession($s_Capabilities) Return SetError(@error, @extended, $WD_SESSION) Return SetError(@error, @extended, $WD_SESSION) EndFunc ;==>_MY__WD_SetupFireFox switch between: ;~ Local $sSession = _MY__WD_SetupFireFox(False) Local $sSession = _MY__WD_SetupChrome(True) It is issue with "chromedriver.exe" https://bugs.chromium.org/p/chromium/issues/detail?id=1311166
    1 point
  12. As I mentioned, I had a short look at the source. As good as none dokumentation, the source of Actiona is straight C++ based on the QT-Framework. All parameters which goes in and come out of methods/functions are going through the QT. I am experienced with DLL (I did a quick look at this with IDA also) and I would trust myself to use a function of an Actiona-DLL but at what price?! Definetely you have to complete install Actiona to use one/some of the functions! And even then it would take much longer and would be more complicated than writing this function from scratch. An other idea could be to automate Actiona with an AutoIt-Script....🙄😱 @noellarkin, I would like to see an example or more of the images you are having trouble finding.
    1 point
  13. Here you have the openCV V4 UDF and when you search the forum for bitblt you can find many ways that are probably easier then to integrate the dll's (if they are documented it could be straight forward with dllcall function)
    1 point
  14. First I have to say, I am not a C/C++ Programmer, but after a quick look at the code in the git repository I noticed that Actiona uses OpenCV, especially the function matchTemplate (to find a image within an image) with various methods described here. AFAIK there is an OpenCV-UDF in AutoIt, which i would prefer rather than using lots of interdependent dll´s of a 3rd party program.
    1 point
  15. If you know the parameters of the DLL methods, you can call it directly with AutoIt DllCall function. With the help of the source code, that might be one simpler way, than investing days to translate something that may not work in pure AutoIt.
    1 point
  16. Actiona has an open-source C++ GitHub repository, so in theory it's possible to do what you want, provided: you are sufficiently competent in C++ (your AutoIt skills are almost irrelevant in this respect) and comfortable with MSVC or similar compiler environment the source is adequately documented (doesn't look like it) and modular (so the image-procesing part can be extracted easily; haven't checked this), C++ can be written in a variety of styles (heavily OOP or not, multi-threaded or not, integrated with other language-based components or not, template-library based or not, etc) Writing a c++ dll from scratch to integrate with AutoIt is fairly easy (example), but adapting someone else's existing code to function as a dll won't be, unless the original is already set up to be library/dll-based (if so, you'd just have to extract the required parts and write a wrapper library for it in AutoIt). The main problem I suspect will be the external parts your desired internal functions will rely on (the back-end of the back-end, if you will) which may be impossible/difficult to port to an AutoIt environment. My advice: investigate other image-processing options (existing AutoIt UDFs and/or dll's) rather than spending ages trying to analyse whether all hidden dependencies are actually portable/extractable. In most cases, there are plenty of alternative ways to skin any particular cat.
    1 point
  17. UAC determines whether you need to be admin. It's better than letting any script run, more secure, that's why--windows is protecting you same in Linux, have to run as su (super user) to do anything that affects the system that is how it should always be, not the wild wild west. following this practice leads to a pc with a long, reliable well configured life. stable OS in fact, you should never operate from an elevated account unless you are installing software or doing OS related maintenance, you should be logged in and running as a standard user--much more safe--need to install something (you probably just want to, not need to) --then log in as admin or elevate to admin temporarily
    1 point
  18. 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.7z
    1 point
  19. Subz

    ShellExecute parameters

    Could try: Run('Excel.exe /r "V:\AutoIt\QuickLaunch\somefile.xlsx") Or ShellExecute('Excel.exe', '/r "V:\AutoIt\QuickLaunch\somefile.xlsx"')
    1 point
  20. From time to time questions arise about listviews with multi-line headers or headers with increased height. Eg. these two questions: Multi-line listview column headings and Listview header height. To use a multi-line header in a listview the height of the header must be increased to make room for multiple lines, and it must be possible to display multiple text lines in the header items. Increase height of header control Because the header control is contained in a listview, the height of the header must be increased in such a way that the listview will be aware of the increased height. An easy and common method of increasing the height is to define a text font for the header with a suitable height. Increasing the height in this way requires that the header is not provided with any themes. However, it is possible to restore themes after the height is increased. A better but slightly more cumbersome method is based on HDM_LAYOUT messages. A HDM_LAYOUT message (implemented in _GUICtrlHeader_Layout) is used to retrieve information about the size of a header control. To use this message to define the height, the header control must be subclassed. The HDM_LAYOUT method is preferred in the examples. Two examples with the font height method are added in "Using font height" folder. Whichever method is chosen, the header height must be increased before rows are added to the listview. Subclassing controls After Windows XP the recommended way to subclass controls is to use the four functions SetWindowSubclass, GetWindowSubclass, RemoveWindowSubclass and DefSubclassProc (all implemented in WinAPIShellEx.au3). These functions are used in the examples. And they are much easier to use than the old SetWindowLong (_WinAPI_SetWindowLong) function. Since we are subclassing a header control contained in a listview this issue must be taking into account. I have verified that this is also an issue for _WinAPI_DefSubclassProc. The solution is the same as the solution in the link: ;Return _WinAPI_DefSubclassProc( ... ) ; Not so good Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", ... )[0] ; Much better Responding to HDM_LAYOUT messages HDM_LAYOUT messages are generated when columns are added to the listview with _GUICtrlListView_AddColumn. To respond to these messages the header control must be subclassed before columns are added: Local $pHeaderProc = DllCallbackGetPtr( DllCallbackRegister( "HeaderProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) _WinAPI_SetWindowSubclass( $hHeader, $pHeaderProc, 9999, $iHeaderHeight ) ; SubclassId = 9999, $pData = $iHeaderHeight If columns are added directly in GUICtrlCreateListView command, this code snippet (copied from _GUICtrlHeader_Create) can be used to generate a HDM_LAYOUT message: Local $tRect = _WinAPI_GetClientRect( $hListView ) Local $tWindowPos = _GUICtrlHeader_Layout( $hHeader, $tRect ) _WinAPI_SetWindowPos( $hHeader, DllStructGetData( $tWindowPos , "InsertAfter" ), _ DllStructGetData( $tWindowPos , "X" ), DllStructGetData( $tWindowPos , "Y" ), _ DllStructGetData( $tWindowPos , "CX" ), DllStructGetData( $tWindowPos , "CY" ), _ DllStructGetData( $tWindowPos , "Flags" ) ) This is the subclass callback function: Func HeaderProc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $iHeaderHeight ) #forceref $iSubclassId Switch $iMsg Case $HDM_LAYOUT Local $tHdLayout = DllStructCreate( $tagHDLAYOUT, $lParam ) Local $tRect = DllStructCreate( $tagRECT, DllStructGetData( $tHdLayout, "Rect" ) ) Local $tWindowPos = DllStructCreate( $tagWINDOWPOS, DllStructGetData( $tHdLayout, "WindowPos" ) ) ; Modify $tRect and $tWindowPos in $tHdLayout to increase Header height DllStructSetData( $tRect, "Top", $iHeaderHeight ) DllStructSetData( $tWindowPos, "X", DllStructGetData( $tRect, "Left" ) ) DllStructSetData( $tWindowPos, "Y", 0 ) DllStructSetData( $tWindowPos, "CX", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tRect, "Left" ) ) DllStructSetData( $tWindowPos, "CY", $iHeaderHeight ) DllStructSetData( $tWindowPos, "Flags", 0x0020 ) ; 0x0020 = $SWP_FRAMECHANGED Return True EndSwitch ; Call next function in subclass chain Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] EndFunc Multiple text lines in header items The items in a standard header control can display a single line of text. There seems not to be any options to change this. There is no word wrap option. Fortunately the header control supports both custom and owner drawn items. Custom drawn items are implemented through NM_CUSTOMDRAW notifications included in WM_NOTIFY messages. NM_CUSTOMDRAW notifications are generated automatically by the code in ComCtl32.dll when the header control is updated. Implementing custom drawn items is a matter of responding to these messages or not. Owner drawn items are implemented through WM_DRAWITEM messages. The HDF_OWNERDRAW flag must be set for the header items to generate WM_DRAWITEM messages. Custom drawn items are preferred in the examples. An example with owner drawn items is added in "Owner drawn" folder. Custom drawn items WM_NOTIFY (and WM_DRAWITEM) messages are send to the parent of the header control. The parent is usually an AutoIt GUI, and messages can be handled by a function registered with GUIRegisterMsg. In this case the listview is the parent of the header control. To catch header messages from the listview, the listview must be subclassed. Implement subclassing for the listview: Local $pListViewProc = DllCallbackGetPtr( DllCallbackRegister( "ListViewProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) _WinAPI_SetWindowSubclass( $hListView, $pListViewProc, 9999, 0 ) The subclass callback function looks like this: Func ListViewProc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData ) #forceref $iSubclassId, $pData Switch $iMsg Case $WM_NOTIFY Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Local $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Local $iCode = DllStructGetData( $tNMHDR, "Code" ) Switch $hWndFrom Case $hHeader Switch $iCode Case $NM_CUSTOMDRAW Local $tNMCustomDraw = DllStructCreate( $tagNMCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMCustomDraw, "dwDrawStage" ) Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify parent window of any item related drawing operations Case $CDDS_ITEMPREPAINT ; Before an item is drawn: Default painting (frames and background) Return $CDRF_NOTIFYPOSTPAINT ; Notify parent window of any post item related drawing operations Case $CDDS_ITEMPOSTPAINT ; After an item is drawn: Custom painting (item texts) Local $iIndex = DllStructGetData( $tNMCustomDraw, "dwItemSpec" ) ; Item index Local $hDC = DllStructGetData( $tNMCustomDraw, "hdc" ) ; Device context _WinAPI_SetBkMode( $hDC, $TRANSPARENT ) ; Transparent background DllStructSetData( $tNMCustomDraw, "Left", DllStructGetData( $tNMCustomDraw, "Left" ) + $aHdrInfo[$iIndex][1] ) ; Left margin DllStructSetData( $tNMCustomDraw, "Right", DllStructGetData( $tNMCustomDraw, "Right" ) - $aHdrInfo[$iIndex][1] ) ; Right margin DllStructSetData( $tNMCustomDraw, "Top", DllStructGetData( $tNMCustomDraw, "Top" ) + 2 ) ; 2 pixel top margin DllStructSetData( $tNMCustomDraw, "Bottom", DllStructGetData( $tNMCustomDraw, "Bottom" ) - 4 ) ; 4 pixel bottom margin DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aHdrInfo[$iIndex][0], "int", StringLen( $aHdrInfo[$iIndex][0] ), "struct*", DllStructGetPtr( $tNMCustomDraw, "Left" ), "uint", $aHdrInfo[$iIndex][2] ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch EndSwitch EndSwitch ; Call next function in subclass chain Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] EndFunc Default code in the $CDDS_ITEMPREPAINT stage draws the item frames and background. Code is added to the $CDDS_ITEMPOSTPAINT stage to draw the multi-line item texts. Since we are forced to use custom drawn (or owner drawn) items in any case, we might as well take the opportunity to use some of the options which custom drawn (or owner drawn) items offers. This includes various text styles and fonts, colored text and background, item icons or bitmaps and item frames. The picture shows some of the possibilities: Examples The examples are divided into four folders: Custom drawn contains the examples based on custom drawing. In these examples there is only added code to the $CDDS_ITEMPOSTPAINT stage to fill the inside of the item frames. Owner drawn folder contains an example that shows how to use an owner drawn header control. Two examples in Using font height shows how to use a font to increase the height of the header. Themes are disabled for the header control while the height is increased. Items are custom drawn. The first example restores the theme and draws multi-line texts in the $CDDS_ITEMPOSTPAINT stage. The second example draws entire header items including frames in the $CDDS_ITEMPREPAINT stage. Frames are drawn with _WinAPI_DrawFrameControl. Two examples in Using HDM_LAYOUT shows how to use HDM_LAYOUT messages to increase the height of the header when columns are added with _GUICtrlListView_AddColumn and directly with GUICtrlCreateListView. In all examples LVS_EX_HEADERDRAGDROP extended style is defined for the listview to be able to rearrange columns by drag-and-drop of header items. ListviewHeader.7z Custom drawn\ 1) Simple multi-line header.au3 2) Simple formatted text.au3 3) Styles, fonts, colors.au3 4) Icons and bitmaps.au3 Pattern.bmp Owner drawn\ 1) Simple multi-line header.au3 DrawItem.au3 Using font height\ 1) Restore header theme.au3 2) Drawing everything.au3 Using HDM_LAYOUT\ 1) Columns added with _GUICtrlListView_AddColumn.au3 2) Columns added with GUICtrlCreateListView.au3 ListviewHeader.7z Update 2015-11-24 I have made some tests with real listviews with more than 10 rows. It turns out that the method for increasing the height of the header has a significant impact on performance when rows are inserted in the listview. Increasing the height by responding to HDM_LAYOUT messages is a slow method. Each row inserted generates a HDM_LAYOUT message. This makes insertion slow if there are many rows. (HDM_LAYOUT method can still be used. But it should not be used when the header is contained in a listview.) Using a font to increase the height of the header does not have this negative effect on performance. The purpose of the examples is to be able to use multi-line headers in real listviews. I have updated the examples to use the faster font method to increase the height. A small UDF (GuiHeaderEx.au3) with one function is added to the zip: #include-once #include <WinAPITheme.au3> Func _GUICtrlHeader_SetItemHeightByFont( $hHeader, $iHeight, $bRestoreTheme = True ) ; Remove Header theme _WinAPI_SetWindowTheme( $hHeader, "", "" ) ; Get font of Header control ; Copied from _GUICtrlGetFont example by KaFu ; See https://www.autoitscript.com/forum/index.php?showtopic=124526 Local $hDC = _WinAPI_GetDC( $hHeader ), $hFont = _SendMessage( $hHeader, $WM_GETFONT ) Local $hObject = _WinAPI_SelectObject( $hDC, $hFont ), $lvLogFont = DllStructCreate( $tagLOGFONT ) _WinAPI_GetObject( $hFont, DllStructGetSize( $lvLogFont ), DllStructGetPtr( $lvLogFont ) ) Local $hHdrfont = _WinAPI_CreateFontIndirect( $lvLogFont ) ; Original Header font _WinAPI_SelectObject( $hDC, $hObject ) _WinAPI_ReleaseDC( $hHeader, $hDC ) ; Set height of Header items by applying text font with suitable height $hFont = _WinAPI_CreateFont( $iHeight, 0 ) _WinAPI_SetFont( $hHeader, $hFont ) _WinAPI_DeleteObject( $hFont ) ; Restore Header theme If $bRestoreTheme Then _ _WinAPI_SetWindowTheme( $hHeader ) ; Return original Header font Return $hHdrfont EndFunc ListviewHeader 2015-11-24.7z Custom drawn\ 1) Simple multi-line header.au3 2) Simple formatted text.au3 3) Styles, fonts, colors.au3 4) Icons and bitmaps.au3 5) Drawing everything.au3 GuiHeaderEx.au3 Pattern.bmp Owner drawn\ 1) Simple multi-line header.au3 GuiHeaderEx.au3 DrawItem.au3 You need AutoIt 3.3.10 or later. Tested on Windows 7 32/64 bit and Windows XP 32 bit. Comments are welcome. Let me know if there are any issues. (Set tab width = 2 in SciTE to line up comments by column) ListviewHeader 2015-11-24.7z
    1 point
×
×
  • Create New...