Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/03/2021 in all areas

  1. LarsJ

    RAGrid grid custom control

    tst00.au3 and tst00.vb based on DotNetAll.au3 and the techniques of Using C# and VB Code demonstrates how the example for the .NET DataGridView class can be run in an AutoIt script. The VB code in tst00.vb is slightly modified to run the code in AutoIt. See the comments at top and bottom of tst00.vb. tst00.au3 is the AutoIt code which, using DotNetAll.au3, executes the VB code in tst00.vb. Edit a cell: Left-click to select a row. Left-click again to select a cell. Enter/Escape to accept/cancel the text in the edit control. tst00.vb Imports System 'This line must be added to run the code in AutoIT. Imports System.Drawing Imports System.Windows.Forms Public Class Form1 Inherits System.Windows.Forms.Form Private buttonPanel As New Panel Private WithEvents songsDataGridView As New DataGridView Private WithEvents addNewRowButton As New Button Private WithEvents deleteRowButton As New Button Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As EventArgs) Handles MyBase.Load SetupLayout() SetupDataGridView() PopulateDataGridView() End Sub Private Sub songsDataGridView_CellFormatting(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) _ Handles songsDataGridView.CellFormatting If e IsNot Nothing Then If Me.songsDataGridView.Columns(e.ColumnIndex).Name = _ "Release Date" Then If e.Value IsNot Nothing Then Try e.Value = DateTime.Parse(e.Value.ToString()).ToLongDateString() e.FormattingApplied = True Catch ex As FormatException Console.WriteLine("{0} is not a valid date.", e.Value.ToString()) End Try End If End If End If End Sub Private Sub addNewRowButton_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles addNewRowButton.Click Me.songsDataGridView.Rows.Add() End Sub Private Sub deleteRowButton_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles deleteRowButton.Click If Me.songsDataGridView.SelectedRows.Count > 0 AndAlso _ Not Me.songsDataGridView.SelectedRows(0).Index = _ Me.songsDataGridView.Rows.Count - 1 Then Me.songsDataGridView.Rows.RemoveAt( _ Me.songsDataGridView.SelectedRows(0).Index) End If End Sub Private Sub SetupLayout() Me.Size = New Size(600, 500) With addNewRowButton .Text = "Add Row" .Location = New Point(10, 10) End With With deleteRowButton .Text = "Delete Row" .Location = New Point(100, 10) End With With buttonPanel .Controls.Add(addNewRowButton) .Controls.Add(deleteRowButton) .Height = 50 .Dock = DockStyle.Bottom End With Me.Controls.Add(Me.buttonPanel) End Sub Private Sub SetupDataGridView() Me.Controls.Add(songsDataGridView) songsDataGridView.ColumnCount = 5 With songsDataGridView.ColumnHeadersDefaultCellStyle .BackColor = Color.Navy .ForeColor = Color.White .Font = New Font(songsDataGridView.Font, FontStyle.Bold) End With With songsDataGridView .Name = "songsDataGridView" .Location = New Point(8, 8) .Size = New Size(500, 250) .AutoSizeRowsMode = _ DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders .ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single .CellBorderStyle = DataGridViewCellBorderStyle.Single .GridColor = Color.Black .RowHeadersVisible = False .Columns(0).Name = "Release Date" .Columns(1).Name = "Track" .Columns(2).Name = "Title" .Columns(3).Name = "Artist" .Columns(4).Name = "Album" .Columns(4).DefaultCellStyle.Font = _ New Font(Me.songsDataGridView.DefaultCellStyle.Font, FontStyle.Italic) .SelectionMode = DataGridViewSelectionMode.FullRowSelect .MultiSelect = False .Dock = DockStyle.Fill End With End Sub Private Sub PopulateDataGridView() Dim row0 As String() = {"11/22/1968", "29", "Revolution 9", _ "Beatles", "The Beatles [White Album]"} Dim row1 As String() = {"1960", "6", "Fools Rush In", _ "Frank Sinatra", "Nice 'N' Easy"} Dim row2 As String() = {"11/11/1971", "1", "One of These Days", _ "Pink Floyd", "Meddle"} Dim row3 As String() = {"1988", "7", "Where Is My Mind?", _ "Pixies", "Surfer Rosa"} Dim row4 As String() = {"5/1981", "9", "Can't Find My Mind", _ "Cramps", "Psychedelic Jungle"} Dim row5 As String() = {"6/10/2003", "13", _ "Scatterbrain. (As Dead As Leaves.)", _ "Radiohead", "Hail to the Thief"} Dim row6 As String() = {"6/30/1992", "3", "Dress", "P J Harvey", "Dry"} With Me.songsDataGridView.Rows .Add(row0) .Add(row1) .Add(row2) .Add(row3) .Add(row4) .Add(row5) .Add(row6) End With With Me.songsDataGridView .Columns(0).DisplayIndex = 3 .Columns(1).DisplayIndex = 4 .Columns(2).DisplayIndex = 0 .Columns(3).DisplayIndex = 1 .Columns(4).DisplayIndex = 2 End With End Sub <STAThreadAttribute()> _ Public Shared Sub Main() '<STAThreadAttribute()> and the Shared keyword doesn't work in AutoIt. Application.EnableVisualStyles() 'This means that the Main() function here cannot be executed directly. Application.Run(New Form1()) End Sub Public Sub RunMain() 'Add this function to execute Main() in AutoIt. Main() End Sub End Class tst00.au3 #include "DotNetAll.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() Local $oNetCode = DotNet_LoadVBcode( FileRead( "tst00.vb" ), "System.dll | System.Drawing.dll | System.Windows.Forms.dll" ) Local $oForm1 = DotNet_CreateObject( $oNetCode, "Form1" ) $oForm1.RunMain() EndFunc But I think the code in FirstTest.au3 and the GuiListViewSCN.au3 UDF works better. The code is an attempt to simulate a grid control with a listview. The selected cell is marked in yellow. It can be selected with left-click and moved with the arrow keys, Page Up/Down and Home/End. A double-click or Enter in the selected cell or a double-click in a non-selected cell will start editing the cell. Enter/Escape accepts/cancels the text in the edit control. The GuiListViewSCN.au3 UDF originates from a larger project and is still under development. Therefore, the UDF contains much more code than is needed for this small example. FirstTest.au3 #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y Opt( "MustDeclareVars", 1 ) ; Official includes #include <GuiEdit.au3> #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Global $iRows = 1000, $iCols = 15 ; Rows, Columns Global $idListView, $hListView ; ListView Global $iListViewWidth ; ListView Global $aData[$iRows][$iCols] ; Data ; Cell editing Global $hEdit, $idEditOpen, $idEditClose, $bEditOpen = False, $aEdit[4] Global $bEditOpenOnEnter = True, $bEditOpenOnSpace = False ; Open Edit control on Enter key and/or Space key Global $bEditOpenOnDoubleClick = True ; Open Edit control on double (True) or single (False) click in cell ; Project includes #include "GuiListViewSCN.au3" ; Single Cell Navigation Example() Func Example() ; Fill data For $i = 0 To $iRows - 1 For $j = 0 To $iCols - 1 $aData[$i][$j] = $i & "/" & $j Next Next ; Create GUI Local $iGuiWidth = $iCols * 90 + 40, $iGuiHeight = 788 + 20 Local $hGui = GUICreate( "Simulate Grid Control With ListView", $iGuiWidth, $iGuiHeight ) GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; WM_NOTIFY message handler ; Create ListView Default style Select one row Virtual Border $idListView = GUICtrlCreateListView( "", 10, 10, $iGuiWidth-19, $iGuiHeight-20, $GUI_SS_DEFAULT_LISTVIEW-$LVS_SINGLESEL+$LVS_OWNERDATA, $WS_EX_CLIENTEDGE ) GUICtrlSendMsg( $idListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, 0, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT+$LVS_EX_GRIDLINES ) $hListView = GUICtrlGetHandle( $idListView ) ; Reduce flicker Highlight entire row Grid lines $iListViewWidth = $iGuiWidth-19-20 ; Header handle Local $hHeader = GUICtrlSendMsg( $idListView, $LVM_GETHEADER, 0, 0 ) ; In a non-resizable GUI, column widths shouldn't be changeable by dragging header dividers ; _WinAPI_SetWindowLong( $hHeader, $GWL_STYLE, _WinAPI_GetWindowLong( $hHeader, $GWL_STYLE ) + $HDS_NOSIZING ) ; AutoIt 3.3.14.5 issue DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "SetWindowLongPtrW" : "SetWindowLongW", "hwnd", $hHeader, "int", $GWL_STYLE, "long_ptr", _ DllCall( "user32.dll", "long_ptr", @AutoItX64 ? "GetWindowLongPtrW" : "GetWindowLongW", "hwnd", $hHeader, "int", $GWL_STYLE )[0] + $HDS_NOSIZING ) ; Add columns Local $tBuffer = DllStructCreate( "wchar Text[10]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tColumn = DllStructCreate( $tagLVCOLUMN ), $pColumn = DllStructGetPtr( $tColumn ) DllStructSetData( $tColumn, "Mask", BitOR( $LVCF_FMT, $LVCF_WIDTH, $LVCF_TEXT ) ) DllStructSetData( $tColumn, "Text", $pBuffer ) DllStructSetData( $tColumn, "CX", 90 ) For $i = 0 To $iCols - 1 DllStructSetData( $tBuffer, "Text", "Col" & $i ) DllStructSetData( $tColumn, "TextMax", 2 * StringLen( "Col" & $i ) + 2 ) GUICtrlSendMsg( $idListView, $LVM_INSERTCOLUMNW, $i, $pColumn ) Next ; Set number of rows GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows, 0 ) ; Cell editing ; Edit control open and close events $idEditOpen = GUICtrlCreateDummy() $idEditClose = GUICtrlCreateDummy() ; Message handler for the Edit control Local $pEditHandler = DllCallbackGetPtr( DllCallbackRegister( "EditHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) ; Enable single cell navigation SCN_SingleCellNavigationEnable( $hGui, $idListView ) ; Show GUI GUISetState( @SW_SHOW ) Local $iRowsVis = GUICtrlSendMsg( $idListView, $LVM_GETCOUNTPERPAGE, 0, 0 ) ; Number of visible rows in ListView ConsoleWrite( "ListView height to fit " & $iRowsVis & " rows = " & _GUICtrlListViewWr_GetHeightToFitRows( $idListView, $iRowsVis ) & @CRLF ) ; Main loop While 1 Switch GUIGetMsg() ; Edit control open event from ListView Case $idEditOpen ; Create Edit control $hEdit = _GUICtrlEdit_Create( $hListView, "", $aEdit[0], $aEdit[1], $aEdit[2] - $aEdit[0], $aEdit[3] - $aEdit[1], $ES_AUTOHSCROLL ) _GUICtrlEdit_SetText( $hEdit, $aData[$SCN_iRowCur][$SCN_iColCur] ) _GUICtrlEdit_SetSel( $hEdit, 0, -1 ) ; Place mouse cursor in middle of Edit control Local $iMouseCoordMode = Opt( "MouseCoordMode", 2 ), $aPos = ControlGetPos( $hGui, "", $idListView ) MouseMove( $aEdit[0]+$aPos[0]+($aEdit[2]-$aEdit[0])/2, $aEdit[1]+$aPos[1]+($aEdit[3]-$aEdit[1])/2+2, 0 ) Opt( "MouseCoordMode", $iMouseCoordMode ) ; Message handler for the Edit control DllCall( "comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $hEdit, "ptr", $pEditHandler, "uint_ptr", 0, "dword_ptr", 0 ) ; $iSubclassId = 0, $pData = 0 ; Set focus to Edit control _WinAPI_SetFocus( $hEdit ) $bEditOpen = True ; Edit control close event Case $idEditClose If Not $bEditOpen Then ContinueLoop If GUICtrlRead( $idEditClose ) Then _ ; Store Edit text $aData[$SCN_iRowCur][$SCN_iColCur] = _GUICtrlEdit_GetText( $hEdit ) ; Delete Edit control DllCall( "comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", $hEdit, "ptr", $pEditHandler, "uint_ptr", 0 ) ; $iSubclassId = 0 _GUICtrlEdit_Destroy( $hEdit ) $bEditOpen = False Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup ; Disable single cell navigation SCN_SingleCellNavigationDisable() GUIDelete() EndFunc ; Fill in data in virtual ListView. Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hListView Switch DllStructGetData( $tNMHDR, "Code" ) Case $LVN_GETDISPINFOW Local $tDispInfo = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If Not BitAND( DllStructGetData( $tDispInfo, "Mask" ), $LVIF_TEXT ) Then Return 0 Local Static $tText = DllStructCreate( "wchar[50]" ), $pText = DllStructGetPtr( $tText ) DllStructSetData( $tText, 1, $aData[DllStructGetData($tDispInfo,"Item")][DllStructGetData($tDispInfo,"SubItem")] ) DllStructSetData( $tDispInfo, "Text", $pText ) Return 0 EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc The scripts has been tested on Windows 7. All code is contained in GridControls.7z: GridControls.7z VirtualKeyboard.au3 is contained in ListViewEditingCells.7z: ListViewEditingCells.7z
    4 points
  2. @OliverTonnYou have encountered a variable scoping issue. The variable $sDesiredCapabilities is blank after returning from SetupEdge because is was declared local to Main. Easiest solution is to declare the variable as Global instead of Local. P.S. You can use ConsoleWrite commands to help you identify bugs like this.
    1 point
  3. thanks TheXMan......I saw your post after I had already fixed my code and when I posted my reply I saw yours. Thanks a bunch!
    1 point
  4. You need to brush up on your debugging skills. The first thing you should want to know is what the generated command line looks like. You can easily do that by writing it out to the console. If you can't see the problem, then cut & paste the generated command line to a command console and run it. Do you see the problem, now? #include <Constants.au3> #include <GuiConstantsEx.au3> #include <WinAPIFiles.au3> Local $sCommand = 'PowerShell.exe -ExecutionPolicy bypass ' $sCommand &= "$file = $env:TEMP\true.dat" $sCommand &= ' ; ' $sCommand &= 'If (Test-Path "HKCU:\SOFTWARE\Classes\CLSID\{00425F68-FFC1-445F-8EDF-EF78B84BA1C7}"){New-Item $file}' $sCommand &= ' ; ' ConsoleWrite("Command Line = " & $sCommand & @CRLF) ;~ Run($sCommand, "", @SW_HIDE) Console Output: Command Line = PowerShell.exe -ExecutionPolicy bypass $file = $env:TEMP\true.dat ; If (Test-Path "HKCU:\SOFTWARE\Classes\CLSID\{00425F68-FFC1-445F-8EDF-EF78B84BA1C7}"){New-Item $file} ;
    1 point
  5. yeah, i looked at the source, it's a microsoft solution written in C++ and can be built in VS so AutoIt should be able to communicate and that was already proven above!
    1 point
  6. I don't have a clue about how the DLL actually works or interfaces with an osc-compatible app. However, the DLL does appear to work within AutoIt. You will need to do any further translation of the AHK code to AutoIt. Of course this also implies that you need to learn AutoIt. #include <Constants.au3> #cs Project: https://files.eleton-audio.de/gitea/Ludwig/OSC2AHK #ce osc2ahk_test() Func osc2ahk_test() Local $hDll, $hWnd Local $aResult If Not @AutoItX64 Then Exit MsgBox($MB_ICONWARNING + $MB_TOPMOST, "WARNING", "The DLL requires a 64bit execution environment.") ;Get any test hWnd (most likely would be hWnd of media app) $hWnd = WinGetHandle(AutoItWinGetTitle()) ConsoleWrite("OSC2AHK: $hWnd = " & $hWnd & @CRLF) ;Get a handle to DLL $hDll = DllOpen("OSC2AHK.dll") If $hDll = -1 Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "ERROR", "Unable to open DLL") ConsoleWrite("OSC2AHK: DLL successfully opened." & @CRLF) ;Open a listening port $aResult = DllCall($hDll, "int", "open", "handle", $hWnd, "uint", 7002) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "OSC2AHK ERROR", "Open DllCall failed.") ;DllCall failed ElseIf $aResult[0] <> 0 Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "OSC2AHK ERROR", "Open API failed.") ;API failed EndIf ConsoleWrite("OSC2AHK: Listening port successfully opened." & @CRLF) ;Close all listeners $aResult = DllCall($hDll, "int", "close", "uint", 1) If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "OSC2AHK ERROR", "Close DllCall failed.") ;DllCall failed ElseIf $aResult[0] <> 0 Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, "OSC2AHK ERROR", "Close API failed.") ;API failed EndIf ConsoleWrite("OSC2AHK: All listeners successfully closed." & @CRLF) ;Close DLL handle DllClose($hDll) ConsoleWrite("OSC2AHK: DLL closed." & @CRLF) EndFunc Console Output: OSC2AHK: $hWnd = 0x0000000000510716 OSC2AHK: DLL successfully opened. OSC2AHK: Listening port successfully opened. OSC2AHK: All listeners successfully closed. OSC2AHK: DLL closed.
    1 point
  7. I wonder if something like this would work in your situation -- $sElement = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//input[substring(@name, string-length(@name) - 2) = '_11']") $sName = _WD_ElementAction($sSession, $sElement, 'attribute', 'name') $sPrefix = StringTrimRight($sName, 3) Obviously needs some error checking. Once you have the correct prefix. you could use it to retrieve the desired element without the need to take a substring of the ID or name each time.
    1 point
  8. As long as the required Visual C runtime (vcruntime140_1.dll) can be found, the DLL opens without any errors.
    1 point
  9. You didn't provide enough details to know if no matching element was found or if the wrong element was found. I suspect that it may have been the later because there's a flaw in your process of checking for the trailing portion of the element's name, id, whatever. Here's proof from the HTML you just posted -- <div id="z8hY_3" class="innerdoc navcomp navroot baselayer covered-layer" style="z-index: 0" data-navcomp-type="layer"> <input id="in8hY_3" type="text" spellcheck="false" autocomplete="off" style="box-sizing:border-box;width:100%;vertical-align:top;color:inherit;" name="in8hY_13" class="navitem s_95" data-evt="Fi Fo" data-evh-fi="Pweb.input.inputTextFocusInWrapper" data-evh-fo="Pweb.input.inputTextFocusOutWrapper" data-evt-props="[&quot;altStyle&quot;]" data-befieldchanged-url="./000000000000o3ihg5.mthd" aria-labelledby="y8hY_1l"> Your xpath would return only the Div element, not the Input element. You can replace the "*" in your xpath with the actual element type, but that still won't guarantee that you get the desired element due to the possibility that there are still multiple matches.
    1 point
  10. You have several resources available to you -- wd_demo.au3 is intended to demonstrate some of the basic usage Wiki page, which is community maintained, gives a good overview of the UDF functionality This forum where you will find multiple threads related to the UDF usage W3C specs, which is he ultimate guide for how each Webdriver call is supposed to work Good luck! DanP
    1 point
  11. You can also add Using C# and VB Code in AutoIt through .NET Framework to the list of references above. However, an approach based on one of the options already mentioned is probably both cumbersome and time consuming. An easier solution is to try to simulate a grid control with a listview: Replace the entire row selection with a single cell selection, make it possible to move the selected cell around the listview with the arrow keys and finally make it possible to edit the selected cell. The listview should be a virtual listview with an array as the data source, so that when you edit a listview cell you store the new value directly in the data source.
    1 point
  12. taskkill /s remoteServer  /u userName /FI "IMAGENAME eq filename" Something to that extent can remotely kill the process if you have admin rights You can use Autoit to create a nice GUI so they can supply the credentials, but it can easily be done just in .bat file as well. Then on the remote machine, use Autoit to create some kind of Daemon that checks if the process is running and if not restarts it. Better yet, find a way to completely resolve the issue on the local machine rather than needing any remote interaction at all. Look at things like what changes when its in the "crashed" state, what kind of breadcrumb can you follow, like CPU usage, RAM usage, A service not responding, etc. ....and of course if you can get to the root cause and prevent it from crashing at all, that would be most ideal. Here is something I wrote for the helpdesk to restart the print spooler for a users computer that lets them use an AD search to find the computer and remotely restart the service. #Include <AD.au3> #Include <File.au3> #include <Constants.au3> #include <StaticConstants.au3> #include <ExtMsgBox.au3> #include <Array.au3> #include <Services.au3> HotKeySet("{ESC}", "_Terminate") ;Set ESC Key to Force Exit Program If Remote Computer Hangs Global $sINI = @ScriptDir & "\Config_StartServiceRemote.ini" If NOT FileExists($sINI) Then ;See if our configuration file exist, if not create it IniWrite($sINI, "CONFIG", "RemoteService", "spooler") IniWrite($sINI, "CONFIG", "ShowSplash", "1") IniWrite($sINI, "CONFIG", "Debug", "0") EndIf Global $iDebug = INIRead($sINI, "CONFIG", "Debug", "0") ; Set 0 for Normal Operation, Set 1 to See Debug Information Global $sService = INIRead($sINI, "CONFIG", "RemoteService", "spooler") ;Global Varible for Service we want to work with Global $iSplash = INIRead($sINI, "CONFIG", "ShowSplash", "1") ;Global Varible to Show or Hide Status Messages 0 Off 1 On $sPCN = InputBox("IIO Automation - Find Computer By PCN", "Input PCN To Search For", "") ;Ask user to input a PCN Value If @Error = 1 Then Exit $sResult = "" _AD_Open() ;Open Connection To AD GLOBAL $sOU = "OU=*snip*" ;Define a Specific OU To Search In GLOBAL $aObjects[0][0] ;Define The Array To Store Results $aObjects = _AD_GetObjectsInOU("", "(&(objectclass=computer)(sAMAccountName=*" & $sPCN & "*))", 2, "sAMAccountName") ;AD Query Searching for Computers and A Description Starting With X If @error > 0 Then ;If We Have No Results MsgBox(64, "Active Directory", "No Results Found or Bad Query") ;Show Error Message Exit Else For $i = 1 To $aObjects[0] $aObjects[$i] = StringTrimRight($aObjects[$i], 1) Next EndIf _AD_Close() ;Close Connection to AD If $aObjects[0] > 3 Then $aObjects[0] = 4 ;If element count is more than 4 than it will be reduced to only 4 If $iDebug = 1 then _ArrayDisplay($aObjects) $sObjects = _ArrayToString($aObjects, "|", 1, $aObjects[0]) ;This moves the array into a string for use as buttons; uses the element count to determin how many buttons If $iDebug =1 Then MsgBox("Show Array", "", $sObjects) _ExtMsgBoxSet(1, 2, 0x004080, 0xFFFF00, 10, "Comic Sans MS", 1000, 1200) ;Set our message box global style $sMsg = "Click The Computer You Want To Connect To" $iRetValue = _ExtMsgBox($EMB_ICONEXCLAM, $sObjects, "Found Computers by PCN", $sMsg, 0) If @Error Then MsgBox(0, "There Was An Error Code Returned", @Error) ConsoleWrite("Test 3 returned: " & $iRetValue & @CRLF) If $iRetValue = 0 Then Exit ; Reset to default _ExtMsgBoxSet(Default) If $iDebug = 1 Then MsgBox(0, "Computer Chosen", $aObjects[$iRetValue]) TCPStartup() $sComputerName = $aObjects[$iRetValue] $sComputerIP = TCPNameToIP($aObjects[$iRetValue]) TCPShutdown() If $iDebug = 1 Then MsgBox(0, "Computer IP", $sComputerIP) ;Returns Are $aObjects[$iRetValue] for Computer Name and $sComputerIP for IP Address $aStatus = _Service_QueryStatus($sService, $sComputerName) If $iDebug = 1 Then _ArrayDisplay($aStatus) If $aStatus[1] = $SERVICE_RUNNING Then $iResponce = MsgBox($MB_YESNO, "IIO Automation", "Service " & $sService & " Is Already Running" & @CRLF & "Try To Restart?") If $iResponce = $IDYES Then _RestartServiceX() Else Exit EndIf EndIf _StartServiceX() Func _RestartServiceX() _Service_Stop($sService, $sComputerName) If $iSplash =1 Then SplashTextOn("IIO Automation", "Stopping " & $sService & " Service" & @CRLF & "Press Escape To Cancel", 500, 100) Do Sleep(100) $aStatus = _Service_QueryStatus($sService, $sComputerName) Until $aStatus[1] = $SERVICE_STOPPED SplashOff() ;_StartServiceX() EndFunc Func _StartServiceX() _Service_Start($sService, $sComputerName) If $iSplash = 1 Then SplashTextOn("IIO Automation", "Starting " & $sService & " Service" & @CRLF & "Press Escape To Cancel", 500, 100) Do Sleep(100) $aStatus = _Service_QueryStatus($sService, $sComputerName) Until $aStatus[1] = $SERVICE_RUNNING SplashOff() MsgBox($MB_OK, "IIO Automation", $sService & " Service Has Been Started on " & $sComputerName) Exit EndFunc Func _Terminate() Exit EndFunc
    1 point
  13. GUIRegisterMsg() subclasses an AutoIt GUI. Ie. a window created with GuiCreate(). A few issues are related to GUIRegisterMsg(): It cannot subclass a control Some messages cannot be handled Only one function for a specific message These issues cannot be described as errors. They are probably consequences of a design choice to limit the complexity of the function. A few issues are related to the subclassing technique in general: _WinAPI_SetWindowLong() The Subclassing bug GUIRegisterMsg20() addresses all these issues. 2020-02-23: It's probably not true that GUIRegisterMsg() is based on the subclassing technique. The messages handled by GUIRegisterMsg() are more likely to originate from the message loop in the window procedure (implemented in internal code) of the main GUI window. What is subclassing? Subclassing is a technique to get information from standard controls through Windows messages, and to modify the functionality of standard controls by responding to these messages. Eg. to change the background color of listview cells. GUIRegisterMsg20 GUIRegisterMsg20.au3 is a small UDF implemented in 100 code lines. This is the documentation for GUIRegisterMsg20(): ; Register a message handler function for a window or control message ; GUIRegisterMsg20( $vWinOrCtrl, _ ; Window handle or control ID/handle ; $WM_MESSAGE, _ ; Window message or control message ; $hFunction ) ; User supplied message handler func ; ; $vWinOrCtrl GUI handle as returned by GUICreate, controlID as returned by GUICtrlCreate<Control> functions ; or control handle as returned by _GUICtrl<Control>_Create UDF functions or GUICtrlGetHandle. ; ; $WM_MESSAGE A Windows message code as listed in Appendix section in help file. Or a control message code ; eg. a LVM_MESSAGE or TVM_MESSAGE as listed in ListViewConstants.au3 or TreeViewConstants.au3. ; This parameter is only checked to be within the valid range of Windows and control messages: ; 0x0000 - 0x7FFF. ; ; $hFunction The user supplied function (not the name but the FUNCTION) to call when the message appears. ; The function is defined in exactly the same way as the function for the official GUIRegisterMsg: ; Takes four input parameters ($hWnd, $iMsg, $wParam, $lParam) and returns $GUI_RUNDEFMSG to conti- ; nue with default message handling, or a specific value if the message is handled by the function. ; ; Error code in @error Return value ; 1 => Invalid window handle or control ID/handle Success => 1 ; 2 => Invalid Window or control message Failure => 0 ; 3 => Invalid function handle ; 4 => Too many subclasses And this is the very central internal function that is called directly from the code in ComCtl32.dll: Func GUIRegisterMsg20_Handler( $hWnd, $iMsg, $wParam, $lParam, $idx, $pData ) If $iMsg <> $aGUIRegisterMsg20[$idx][3] Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Local $vRetVal = $aGUIRegisterMsg20[$idx][4]( $hWnd, $iMsg, $wParam, $lParam ) ; Execute user supplied message handler function If $vRetVal == "GUI_RUNDEFMSG" Then Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] Return $vRetVal #forceref $pData EndFunc It's rarely necessary to call GUIUnRegisterMsg20(). Message handlers are unregistered when the program exits. An exception is a situation where message handles are registered and unregistered on the fly, eg. due to user actions. Message monitor When it comes to topics like subclassing, a message monitor is required eg. Windows Message Monitor. ListView example Listview example is a custom drawn listview with colored cells. If we focus on subclass implementation, this is the difference between GUIRegisterMsg() and GUIRegisterMsg20() code. GUIRegisterMsg(): ; ... GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; ... GUIRegisterMsg20(): #include "..\..\Includes\GUIRegisterMsg20.au3" ; ... GUIRegisterMsg20( $hGui, $WM_NOTIFY, WM_NOTIFY ) ; ... GUIRegisterMsg20() takes $hGui as first parameter. The message handler function in third parameter is a function variable. Not a string. The message handler function, WM_NOTIFY, is exactly the same in the two examples. If you run the scripts that contains message monitor code, you will notice a remarkable difference between the two scripts. In the GUIRegisterMsg20() script, there are no NM_CUSTOMDRAW notifications in the monitor. What's the reason? All GUIRegisterMsg() examples in help file that looks like this: ; ... GUIRegisterMsg( $WM_MESSAGE, "WM_MESSAGE" ) ; ... Can be implemented with GUIRegisterMsg20() this way: ; ... GUIRegisterMsg20( $hGui, $WM_MESSAGE, WM_MESSAGE ) ; ... Input example Input example is based on this forum thread. Run Input.au3 to see the issues: You can paste a number into the control, a context menu shows up on right click, and a tooltip is displayed if you press a letter. Let's see what's going on with the message monitor. When you solve issues with a message monitor, you are generally interested in finding a particular message or a pattern of a few messages. If there are multiple instances of the message or pattern, it's easier to find. The action that generates the message or pattern should be repeated 3 - 4 times. Run "Input, wmm.au3", paste a number into the control 3 - 4 times eg. 18 (result = 18181818), right click 3 - 4 times, press a letter 3 - 4 times. Press Esc to delete Input GUI and start WMM GUI. Scroll down until you see tomato red messages. You'll see the messages WM_PASTE, WM_CONTEXTMENU and EM_SHOWBALLOONTIP. Note that all three messages are received by the Input control. This means that GUIRegisterMsg() cannot be used. It can only handle messages received by the GUI. Because all messages are received by the Input control you can register three message handlers this way in "Input, subclass.au3": ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, WM_PASTE ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, WM_CONTEXTMENU ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, EM_SHOWBALLOONTIP ) To implement message handler functions you have to read Microsoft documentation. Only for EM_SHOWBALLOONTIP it's completely clear that the message is suppressed by returning False or 0. For all three messages, however, you must return 0 to suppress the message: ; WM_PASTE message handler function Func WM_PASTE( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; WM_CONTEXTMENU message handler function Func WM_CONTEXTMENU( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc ; EM_SHOWBALLOONTIP message handler function Func EM_SHOWBALLOONTIP( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc As all three functions are the same, the code can be reduced a little bit in "Input, final.au3": ; GUICtrlCreateInput - Disable copy/ paste, right click menu and balloon pop-up ; https://www.autoitscript.com/forum/index.php?showtopic=179052 #include <GuiEdit.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "..\..\Includes\GUIRegisterMsg20.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Create GUI GUICreate( "Input (numbers only)", 300, 118 ) ; Create Input Local $idInput = GUICtrlCreateInput( "", 50, 50, 200, 18, $GUI_SS_DEFAULT_INPUT+$ES_NUMBER ) ; Create Label GUICtrlCreateLabel( "No paste, no context menu, no balloontip", 50, 70, 200, 18 ) ; Subclass Input GUIRegisterMsg20( $idInput, $WM_PASTE, InputFunc ) GUIRegisterMsg20( $idInput, $WM_CONTEXTMENU, InputFunc ) GUIRegisterMsg20( $idInput, $EM_SHOWBALLOONTIP, InputFunc ) ; Show GUI GUISetState() ; Msg loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete() EndFunc ; Input message handler function Func InputFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 0 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. Header example The width of listview columns can be changed by dragging header item separators with the mouse. If you want to disable this feature you have to suppress HDN_BEGINTRACK notifications from the header control. They are contained in WM_NOTIFY messages. And you have to suppress WM_SETCURSOR messages when the mouse cursor hover over header item separators. This prevents a cursor shape indicating that separators can be dragged. Run "ListView header, wmm.au3". Drag the header item separators forth and back. This generates a huge number of messages. Press Esc to delete GUI and start WMM GUI. Scroll down until you see tomato red messages. Note that HDN_BEGINTRACK notifications in WM_NOTIFY messages are sent first to the listview and then to the GUI. They can be catched by GUIRegisterMsg(). Here they'll be catched by GUIRegisterMsg20() from the listview. WM_SETCURSOR messages must be catched from the header: ; Subclass ListView and Header GUIRegisterMsg20( $idListView, $WM_NOTIFY, ListViewFunc ) GUIRegisterMsg20( $hHeader, $WM_SETCURSOR, HeaderFunc ) Handler functions: ; ListView message handler function Func ListViewFunc( $hWnd, $iMsg, $wParam, $lParam ) If $HDN_BEGINTRACKW = DllStructGetData( DllStructCreate( $tagNMHEADER, $lParam ), "Code" ) Then Return 1 Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc ; Header message handler function Func HeaderFunc( $hWnd, $iMsg, $wParam, $lParam ) Return 1 #forceref $hWnd, $iMsg, $wParam, $lParam EndFunc Again, just by looking at the code (including UDF in top, registering and implementing message handlers in middle and bottom) it seems not to be that hard. 2020-02-23: Note that if you want to prevent the width of the listview columns from being changed you can simply add the HDS_NOSIZING style to the header control. I wasn't aware of that when I made the example. TreeView example (2018-08-15) TreeView example is based on this forum thread. Run TreeView.au3 (copied from first post in thread) to see the issue: No WM_COMMAND messages are received on right click in treeview. "TreeView, wmm.au3" shows the problem: WM_COMMAND messages generated on right clicks are sent to the treeview and not the main GUI. This means that GUIRegisterMsg() isn't able to catch the messages. To solve the problem include GUIRegisterMsg20.au3 in top of script and use GUIRegisterMsg20() to subclass the treeview as it's done in "TreeView, subclass.au3": ;... #include "..\..\Includes\GUIRegisterMsg20.au3" ;... GUIRegisterMsg20( $g_hTreeView, $WM_COMMAND, WM_COMMAND ) The existing WM_COMMAND() message handler is reused. That was two code lines to solve the problem. It can hardly be easier. Too much code (2018-09-30) A custom drawn listview generates a lot of WM_NOTIFY messages. If custom draw code is used to draw selected items with GDI-functions in the post paint drawing stage, much code will be executed to respond to all these messages. If it's also a virtual listview, it'll double the number of messages (Examples\5) Too much code\ListView.au3): Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local Static $tText = DllStructCreate( "wchar[100]" ), $pText = DllStructGetPtr( $tText ) Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ) Switch DllStructGetData( DllStructCreate( $tagNMHDR, $lParam ), "Code" ) Case $LVN_GETDISPINFOW ; Fill virtual listview Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If Not BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Return Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO,"Item")][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return Case $NM_CUSTOMDRAW ; Draw back colors Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" ), $iItem Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) If GUICtrlSendMsg( $idListView, $LVM_GETITEMSTATE, $iItem, $LVIS_SELECTED ) Then Return $CDRF_NOTIFYPOSTPAINT ; Selected item DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", $aColors[$iItem][DllStructGetData($tNMLVCUSTOMDRAW,"iSubItem")] ) ; Normal item Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem Local $hDC = DllStructGetData( $tNMLVCUSTOMDRAW, "hdc" ) ; Subitem rectangle $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) Local $iSubItem = DllStructGetData( $tNMLVCUSTOMDRAW, "iSubItem" ) DllStructSetData( $tRect, "Left", $LVIR_LABEL ) DllStructSetData( $tRect, "Top", $iSubItem ) GUICtrlSendMsg( $idListView, $LVM_GETSUBITEMRECT, $iItem, $pRect ) DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + 2 ) DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Right" ) - 2 ) DllStructSetData( $tRect, "Bottom", DllStructGetData( $tRect, "Bottom" ) - 1 ) ; Subitem back color Local $hBrush = DllCall( "gdi32.dll", "handle", "CreateSolidBrush", "int", $aColors[$iItem][$iSubItem] )[0] ; _WinAPI_CreateSolidBrush DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "bool", "DeleteObject", "handle", $hBrush ) ; _WinAPI_DeleteObject ; Draw subitem text DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0 ) ; _WinAPI_SetTextColor DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItems[$iItem][$iSubItem], "int", -1, "struct*", $tRect, "uint", $DT_CENTER ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch Return $GUI_RUNDEFMSG #forceref $hWnd, $iMsg, $wParam EndFunc If there are a lot of messages and some messages perform quite a lot of code, you can end up in a situation where more code is performed than there's time for. The result is that the WM_NOTIFY messages are blocked and the code fails: You can provoke the error this way: Click a row in the listview (not one of the very top rows). Press Shift+Down arrow to select multiple rows. The problem will arise after just a few rows. Press Ctrl+Break in SciTE to stop the code. 2020-02-23: The only solution to the problem is probably to implement the WM_NOTIFY() function in compiled code as demonstrated here. Message flow (update 2018-09-30) In these examples, the message flow is examined with left and right mouse clicks. Several message handles are implemented. A standard AutoIt message loop (MessageLoop Mode) where messages are received with GUIGetMsg(). A message handler based on GUIRegisterMsg(). And a message handler created with GUIRegisterMsg20(). In addition, there is the internal AutoIt message handler (C++ code). The purpose is to determine in which order a message is received by all these different message handlers. Script 1) implements the three message handlers. By examining the message flow with the monitor we can see that the messages are received in this order: Script 2) implements an additional GUIRegisterMsg20() message handler for the same mouse click messages but with another message handler function. It seems that the last created GUIRegisterMsg20() handler, is the first to receive the mouse clicks. In script 3) mouse clicks are performed in an Edit control instead of an empty GUI. The GUIRegisterMsg() message handler does not receive the mouse clicks. At what point in the flow chart does the message monitor hook into the message flow? Since message detection is implemented through subclassing it hooks into the message flow just before the internal AutoIt message handler. Now we can answer the question from the listview example above: Why do we not see any NM_CUSTOMDRAW notifications in the message monitor from the GUIRegisterMsg20() script. Because these notifications are all answered with one of the custom draw return values and not $GUI_RUNDEFMSG. The custom draw return values goes directly back to the operating system and the messages are no longer forwarded in the message chain. The message flow stops already at the GUIRegisterMsg20() message handler function and never reaches the internal AutoIt message handler. Therefore, the messages do not reach the monitor either. The issues The listview example at the top shows that GUIRegisterMsg20() is very similar to GUIRegisterMsg(). You can do the same things with GUIRegisterMsg20() as you can do with GUIRegisterMsg(). This means that you can use GUIRegisterMsg20() in a UDF, while the user can use GUIRegisterMsg() in his own code exactly as described in the help file. From the flow chart above you know that the GUIRegisterMsg20() message handler function will receive messages before the GUIRegisterMsg() message handler function. Let's review the issues mentioned in beginning of post. Only GUIRegisterMsg20() can subclass a control and receive control messages. This is demonstrated in the input example. The mouse clicks in the edit control discussed above shows that GUIRegisterMsg() isn't receiving all WM_MESSAGEs and therefore cannot handle these messages. The mouse clicks in the section above also shows that GUIRegisterMsg20() can use several functions for the same message. Because GUIRegisterMsg20() uses SetWindowSubclass to implement subclassing, problems related to _WinAPI_SetWindowLong() are avoided. Because GUIRegisterMsg20() returns directly from the DefSubclassProc DllCall, the subclassing bug never comes into play. Conclusion GUIRegisterMsg20 UDF takes care of the tedious and cumbersome task of configuring subclassing. Ie. to set up SetWindowSubclass, DefSubclassProc and RemoveWindowSubclass functions. It uses a message handler function that is very similar to the function used in the official GUIRegisterMsg(). You can concentrate on analyzing the message flow and code the message handler function. 7z-file You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Note that the contents of the Includes folder in the Windows Message Monitor 7z-file must be installed in the WMMincl directory to use Windows Message Monitor. Comments are welcome. Let me know if there are any issues. GUIRegisterMsg20.7z
    1 point
  14. LarsJ

    Windows Message Monitor

    In a Windows GUI like an AutoIt GUI, functionality and user actions are largely controlled through Windows messages. Therefore, it's interesting to monitor Windows messages. That's the purpose of this example. How does it work? This is a simple example (Examples\1) Native controls\GUICtrlCreateButton.au3): #include <GUIConstantsEx.au3> #include "..\..\Includes\WinMsgMon_Button.au3" ; <<<<<<<<<<<<<<<<<<<< WinMsgMon_InitMsgs( "..\..\Includes" ) ; <<<<<<<<<<<<<<<<<<<< Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) WinMsgMon_GetMsgs( $hGUI, "$hGUI" ) ; <<<<<<<<<<<<<<<<<<<< ; Create button controls. Local $idMsgBox = GUICtrlCreateButton("Open MsgBox", 120, 170, 85, 25) WinMsgMon_GetMsgs( $idMsgBox, "$idMsgBox" ) ; <<<<<<<<<<<<<<<<<<<< Local $idClose = GUICtrlCreateButton("Close", 210, 170, 85, 25) WinMsgMon_GetMsgs( $idClose, "$idClose" ) ; <<<<<<<<<<<<<<<<<<<< ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $idMsgBox WinMsgMon_UserMsg( $idMsgBox, $WM_USER0, _ ; <<<<<<<<<<<<<<<<<<<< "Before MsgBox" ) MsgBox( 0, "Title", "One second timeout", 1 ) WinMsgMon_UserMsg( $idMsgBox, $WM_USER1, _ ; <<<<<<<<<<<<<<<<<<<< "After MsgBox" ) Case $GUI_EVENT_CLOSE, $idClose WinMsgMon_UserMsg( $idClose, $WM_USER0, _ ; <<<<<<<<<<<<<<<<<<<< "Before ExitLoop" ) ExitLoop EndSwitch WEnd ; Delete GUI and all controls. GUIDelete($hGUI) WinMsgMon_ViewMsgs( Example ) ; <<<<<<<<<<<<<<<<<<<< EndFunc ;==>Example Include UDF In this example WinMsgMon UDF is included as WinMsgMon_Button.au3 and not just WinMsgMon.au3. Because this is a button example, WinMsgMon_Button.au3 is included to be able to get detail information about button messages. WinMsgMon_InitMsgs() WinMsgMon_InitMsgs() is called immediately after inclusion of the UDF. The function sets up the path used to find text files with message information. In addition to the path, WinMsgMon_InitMsgs() can take an optional $iFlags parameter as input. See WinMsgMon.au3 and Rerun in Toolbar buttons section for more information. WinMsgMon_GetMsgs() WinMsgMon_GetMsgs() is the central function that collects messages. It takes two parameters: A window or control and optionally the name of the window or control. In the example above the function is called three times to be able to collect messages sent to the main GUI and two buttons. While messages are collected and stored, info is simultaneously written to SciTE console. The specified window or control names are used in console output and in WinMsgMon GUI. If no names are specified, the names Window1, Button1 and Button2 are used instead. WinMsgMon_UserMsg() WinMsgMon_UserMsg() sends user messages to the two buttons. 16 user messages are defined: $WM_USER0 - $WM_USERF. In the example $WM_USER0 and $WM_USER1 are send to $idMsgBox button before and after the MsgBox is opened and closed. And $WM_USER0 is send to $idClose button immediately before ExitLoop. This way it's easy to recognize the button clicks among the messages. WinMsgMon_ViewMsgs() WinMsgMon_ViewMsgs() is the central function that displays the messages in WinMsgMon GUI. In the example WinMsgMon_ViewMsgs() is called with Example function as parameter. The function parameter is optional and is used in relation to the Rerun button to be able to run Example once more. See Rerun in Toolbar buttons section. WinMsgMon_ViewMsgs() is called as the last line in Example() function. It does not necessarily have to be the last line. But it must definitely be after GUIDelete(). WinMsgMon_ViewMsgs() may well be called before a final long term calculation or file update. In simple situations you may have sufficient information in SciTE console output. In such cases you can omit the WinMsgMon_ViewMsgs() function. GUI window This is a small part of the messages generated by the example above as shown in WinMsgMon GUI: First column in main listview is message number. Note that the message number in first and second row is 220 and 225. This is because some messages eg. WM_MOUSEMOVE are unchecked in WM_MESSAGEs toolbar listview and therefore not displayed in main listview. Second column shows the window or control that receives the message. Name of idMsgBox button, of interest here, is written on a wheat colored background. Message column shows WM_MESSAGEs and control messages. Some messages are particularly interesting. They are written on a colored background. Notification column displays notifications contained in WM_NOTIFY and WM_COMMAND messages. The info columns shows information provided along with the messages. Console output The same messages as shown in SciTE console (long lines shortened): [ 220] idMsgBox WM_PAINT [ 221] idMsgBox WM_NCHITTEST [ 222] idMsgBox WM_SETCURSOR [ 223] hGUI WM_SETCURSOR [ 224] idMsgBox WM_MOUSEMOVE [ 225] hGUI WM_NOTIFY BCN_HOTITEMCHANGE From = idMsgBox HICF_ENTERING [ 226] idMsgBox WM_PAINT [ 227] idMsgBox WM_ERASEBKGND [ 228] hGUI WM_ERASEBKGND [ 229] hGUI WM_CTLCOLORDLG [ 230] hGUI WM_PRINTCLIENT [ 231] hGUI WM_CTLCOLORBTN [ 232] hGUI WM_NOTIFY NM_CUSTOMDRAW From = idMsgBox CDDS_PREERASE [ 233] hGUI WM_NOTIFY NM_CUSTOMDRAW From = idMsgBox CDDS_PREPAINT [ 234] idMsgBox WM_GETTEXTLENGTH [ 235] idMsgBox WM_GETTEXT [ 236] idMsgBox WM_USER1 [ 237] idMsgBox WM_PAINT Toolbar listviews The five toolbar buttons before the first separator opens five listviews. The buttons are hot-track enabled with the technique used in this example. Wins/Ctrls In Wins/Ctrls listview you check the window or control where from you want to see messages. Here messages from all windows and controls are shown: Because some messages eg. WM_MOUSEMOVE are unchecked only 742 of 1315 messages are shown. Click the checkmark or select the row and press Space key to show all messages. When a row is checked, main listview is updated instantly. Unchecked messages in other toolbar listviews are reset. See Set in Toolbar buttons section for an easy way to uncheck messages. Click the color cell or select the row and press Enter key to set background color. The combo control is implemented with the technique demonstrated in this example. The background color for all windows and controls (first row) cannot be set. Note that only single selection is enabled in this toolbar listview. In the other four listviews multiple selections are enabled. To close a toolbar listview click in main listview, click the toolbar button, move mouse pointer above titlebar or press Esc. WM_MESSAGEs In WM_MESSAGEs listview you uncheck messages that you don't want to see. WM_MOUSEMOVE and WM_NCHITTEST messages are already unchecked. WM_NOTIFY messages are written on an aquamarine background: To uncheck or set background color for all WM_NC-messages select the six rows and press Space or Enter key. When a message is un- or in-checked nothing happens until the listview is closed. Then the Refresh button is enabled. Before you click the Refresh button you can un- or in-check messages in other listviews. Click Refresh button to update main listview. When a color is set main listview is updated instantly. Control Msgs The Control Msgs listview is used to manage control messages: WM_0xC09B is an application defined and unregistered message and is shown as the message code. The two user messages are written on a tomato red background. WM_NOTIFYs and WM_COMMANDs WM_NOTIFYs and WM_COMMANDs listviews are used to manage notifications contained in WM_NOTIFY and WM_COMMAND messages. Toolbar listviews 2 - 5 Messages and notifications in toolbar listviews 2 - 5 are grouped by checked/unchecked items. Unchecked items in bottom of listviews. Update 2018-08-15. A Search can be initiated by double-clicking a message or notification in toolbar listviews 2 - 5. Update 2018-08-04. Toolbar buttons Click Refresh to update main listview after messages and notifications are un- or in-checked in toolbar listviews. Click Rerun to run the script and perform message collection once more. A submenu shows up with "Rerun script", "Write messages to console" and "Detail message information" items. The two last items are the same options as can be set through flag values in WinMsgMon_InitMsgs(). In the example in top of post WinMsgMon_ViewMsgs() takes Example as an input parameter. This is the function that will be executed when you click "Rerun script". The function parameter is optional. If not specified, Rerun button is disabled. The Search group is used to search for messages and notifications. When you click the Search button the Search listview shows up. Double click or press Enter key on an item in the listview to start a search. A search for WM_USER1 messages looks this way in main listview: Use Reset button to reset a search. A search can also be initiated by double-clicking a message or notification in toolbar listviews 2 - 5. Update 2018-08-04. Copy button copies text in selected rows to clipboard. Set button applies settings defined in WinMsgMon.ini. See below. A submenu shows up with Uncheck and Colors items. Click Uncheck to uncheck messages defined in ini-file. Colors are already set through GUI creation. Reset shows a submenu with Uncheck, Colors and Search items. Click an item to reset the feature. Use Set button to apply the feature again. Code info A few notes about the code in relation to toolbar listviews and buttons. All listviews are virtual listviews. Through message collection, indexes are created to display data in main listview and to perform searches. Several set of indexes are created. A set for all windows and controls at once. And a set for each single window and control. When a row in Wins/Ctrls toolbar listview (the leftmost listview) is checked, messages are displayed in main listview through one of these precalculated indexes. That's the reason why it's possible to display the messages in the same moment as the row is checked. Search indexes are created for each single message and notification in the Search listview. A set for all windows and controls at once. And a set for each single window and control. That's a lot of search indexes. In the example above, there are around 100 - 150 search indexes. Calculation of indexes is performed through dictionary objects. When you perform a search the matching rows in main listview are instantly drawn with the yellow background color through a precalculated search index. Next and Prev buttons also takes advantage of the indexes. As soon as a message or notification is unchecked in toolbar listviews 2 - 5 none of these precalculated indexes can be used any more. When you click Refresh a new index is calculated to be able to display the messages in main listview. When you start a search a new index is calculated to be able to display matching messages with the yellow background color, and to be able to use Next and Prev buttons. Up to 10,000 messages, performance should not be a problem. So far, no more messages have been tested. Arrays are dimensioned to a maximum of 100,000 messages. The number of windows and controls in leftmost toolbar listview is limited to 20. When you check an item in leftmost toolbar listview all unchecked messages and notifications are reset and the precalculated indexes can be used again. Functions Most functions have already been described through review of the example in top of post. There are only a few left: WinMsgMon_LoadMsgs() When the message flow from an application is monitored, usually only messages for a single control and main GUI is monitored at a time. However, there will nevertheless often be messages from eg. buttons that are very common controls. If button messages are not registered with WinMsgMon_GetMsgs( $idButton ), messages will appear with the code instead of the name. It's actually the notifications that will appear with the code instead of the name. Use WinMsgMon_LoadMsgs() to load notification names this way: #include "..\..\Includes\WinMsgMon.au3" WinMsgMon_InitMsgs( "..\..\Includes" ) WinMsgMon_LoadMsgs( "BCN_Notifications.txt" ) ; Button control notifications WinMsgMon_LoadMsgs( "EN_Notifications.txt" ) ; Edit control notifications WinMsgMon_RemMsgs() WinMsgMon_RemMsgs() removes all message monitors registered with WinMsgMon_GetMsgs(). WinMsgMon_RemMsgs() is called as the first command in WinMsgMon_ViewMsgs(). It's only necessary to call WinMsgMon_RemMsgs() if WinMsgMon_ViewMsg() isn't called. Ie. if the messages are written to SciTE console only. And only if code is executed after GUIDelete(). Detail info Detail info is information in columns named Info 1 - 4 in WinMsgMon GUI. This is information that can be extracted through wParam and lParam parameters in a message handler function. Detail info for WM_NOTIFY and WM_COMMAND messages is always extracted. Detail info for other window and control messages is depending on specific message handlers (script files). In this version only a few message handlers are implemented and only for a limited number of messages. To be able to collect detail info the message handler must be included in the script. In the example in top of post WinMsgMon_Button.au3 is included instead of WinMsgMon.au3 to be able to collect detail info for buttons. WinMsgMon.ini Includes\WinMsgMon.ini is included in the zip-file. If a copy of this file is placed in the same folder as the running script, the copy will be used instead. You can edit the copy to your own needs. An empty file disables all settings in Includes\WinMsgMon.ini. Includes\WinMsgMon.ini: [Apply Settings] Uncheck=True Colors=True [WM_MESSAGEs Uncheck] WM_ERASEBKGND=1 WM_IME_NOTIFY=1 WM_MOUSEMOVE=1 WM_MOVE=1 WM_MOVING=1 WM_NCHITTEST=1 WM_NCMOUSEMOVE=1 WM_PAINT=1 WM_PRINTCLIENT=1 WM_SETCURSOR=1 WM_TIMER=1 WM_WINDOWPOSCHANGED=1 WM_WINDOWPOSCHANGING=1 [WM_MESSAGEs Colors] WM_NOTIFY=Aquamarine WM_COMMAND=Aquamarine WM_KEYDOWN=Bisque WM_KEYUP=Bisque WM_CHAR=Bisque WM_DEADCHAR=Bisque WM_SYSKEYDOWN=Bisque WM_SYSKEYUP=Bisque WM_SYSCHAR=Bisque WM_SYSDEADCHAR=Bisque WM_LBUTTONDOWN=Khaki WM_LBUTTONUP=Khaki WM_LBUTTONDBLCLK=Khaki WM_RBUTTONDOWN=Khaki WM_RBUTTONUP=Khaki WM_RBUTTONDBLCLK=Khaki WM_MBUTTONDOWN=Khaki WM_MBUTTONUP=Khaki WM_MBUTTONDBLCLK=Khaki WM_MOUSEWHEEL=Khaki WM_XBUTTONDOWN=Khaki WM_XBUTTONUP=Khaki WM_XBUTTONDBLCLK=Khaki WM_CONTEXTMENU=LightPink WM_INITMENU=LightPink WM_INITMENUPOPUP=LightPink WM_MENUSELECT=LightPink WM_MENUCHAR=LightPink WM_MENURBUTTONUP=LightPink WM_MENUGETOBJECT=LightPink WM_UNINITMENUPOPUP=LightPink WM_MENUCOMMAND=LightPink WM_ENTERMENULOOP=LightPink WM_EXITMENULOOP=LightPink WM_NEXTMENU=LightPink [Control Messages Uncheck] [Control Messages Colors] WM_USER0=Tomato WM_USER1=Tomato WM_USER2=Tomato WM_USER3=Tomato WM_USER4=Tomato WM_USER5=Tomato WM_USER6=Tomato WM_USER7=Tomato WM_USER8=Tomato WM_USER9=Tomato WM_USERA=Tomato WM_USERB=Tomato WM_USERC=Tomato WM_USERD=Tomato WM_USERE=Tomato WM_USERF=Tomato [WM_NOTIFY Notifications Uncheck] [WM_NOTIFY Notifications Colors] [WM_COMMAND Notifications Uncheck] [WM_COMMAND Notifications Colors] "Uncheck=True" in "Apply Settings" section in WinMsgMon.ini means that unchecked messages are removed from main listview through GUI creation. As soon as an item in Wins/Ctrls toolbar listview (leftmost) is checked the removed messages are redisplayed. Click Set | Uncheck to remove the messages again. "Colors=True" in "Apply Settings" section means that colors are set through GUI creation. Examples Examples\ 1) Native controls - GUICtrlCreate<Control> examples supplied with message monitor code 2) UDF controls - _GUICtrl<Control>_Create examples (not included above) supplied with message monitor code 3) Miscellaneous Combo\ - ComboBox example including the corresponding Edit and ListBox controls. ListView\ - Four ListView examples with a standard ListView, a custom drawn ListView, a virtual ListView and a virtual and custom drawn ListView. Window\ - An example that shows how mouse clicks generates AutoIt messages ($GUI_EVENT_MESSAGEs). Two examples regarding blocked and paused GUIs. Includes Includes\ WinMsgMon.au3 - Main include file, collects messages WinMsgMon_Button.au3 - Button controls, detail information WinMsgMon_ComboBoxEx.au3 - ComboBoxEx controls, detail information WinMsgMon_ListBox.au3 - ListBox controls, detail information WinMsgMon_ListView.au3 - ListView controls, detail information WinMsgMon.ini - ini-file, colors and unchecked messages Internal\ - Internal files, implements the GUI Messages\ - Message info files CTRL_Information.txt - Info file for AutoIt window and 23 controls WM_Messages.txt - Common Windows messages CCM_Messages.txt - Common control messages <???>_Messages.txt - Messages for specific controls WM_NOTIFY\ NM_Notifications.txt - Common Windows notifications <???>_Notifications.txt - WM_NOTIFY notifications for specific controls WM_COMMAND\ <???>_Notifications.txt - WM_COMMAND notifications for specific controls 7z-file The 7z contains source code and message data. 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. WinMsgMon.7z
    1 point
  15. @nguyenthaiytcc This isn't something that I've needed to do previously, but I believe this would be the basic syntax -- $sAction = '{"actions":[{"type": "key", "id": "keyboard_1", "actions": [{"type": "keyDown", "value": "\uE00F"}, {"type": "keyUp", "value": "\uE00F"}]}]}' _WD_Action($sSession, "actions", $sAction) Please give it a try and report back with your results.
    1 point
  16. The Webdriver automatically attempts to scroll the element into view if needed. This is likely the scrolling you are observing since the _WD_ExecuteScript is actually failing. Looks like you need to modify the value representing the element being passed as a parameter. I tested the following and it executed correctly -- _WD_ExecuteScript($sSession, "arguments[0].scrollIntoView(true);", '{"' & $_WD_ELEMENT_ID & '":"' & $sElement & '"}')
    1 point
  17. An example of how to remove blanks using only the original array. Func _ArryRemoveBlanks(ByRef $arr) $idx = 0 For $i = 0 To UBound($arr) - 1 If $arr[$i] <> "" Then $arr[$idx] = $arr[$i] $idx += 1 EndIf Next ReDim $arr[$idx] EndFunc ;==>_ArryRemoveBlanks ;Some code just to show it working #include <array.au3> Dim $arr1[10] $arr1[0] = "" $arr1[1] = "ABC" $arr1[2] = "" $arr1[3] = "xyz" $arr1[4] = "def" $arr1[5] = "" $arr1[6] = "" $arr1[7] = "ffr" $arr1[8] = "" $arr1[9] = "Z33" _ArrayDisplay($arr1, "Before") _ArryRemoveBlanks($arr1) _ArrayDisplay($arr1, "After")
    1 point
×
×
  • Create New...