-
Posts
32 -
Joined
-
Last visited
Profile Information
-
Location
Las Vegas, NV
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
Decibel's Achievements

Seeker (1/7)
10
Reputation
-
Decibel reacted to a post in a topic: Using UI Automation Code in AutoIt
-
Decibel reacted to a post in a topic: ArrayMultiColSort -New Release 06 April 2019
-
Decibel reacted to a post in a topic: For loop and _ArrayDelete
-
Decibel reacted to a post in a topic: AutoIt Snippets
-
Decibel reacted to a post in a topic: ITaskbarList4 interface
-
This isn't a big deal to me, but I noticed this and am curious how APIGdiConstants.au3 could still work when the MS docs show a different enum value. I'm running AutoIt 3.3.16.1 on Win11 x64. APIGdiConstants.au3 has the following lines (75-87) that sets the first enum $DWMWA_NCRENDERING_ENABLED = 1: ; _WinAPI_DwmGetWindowAttribute(), _WinAPI_DwmSetWindowAttribute() Global Const $DWMWA_NCRENDERING_ENABLED = 1 Global Const $DWMWA_NCRENDERING_POLICY = 2 Global Const $DWMWA_TRANSITIONS_FORCEDISABLED = 3 Global Const $DWMWA_ALLOW_NCPAINT = 4 Global Const $DWMWA_CAPTION_BUTTON_BOUNDS = 5 Global Const $DWMWA_NONCLIENT_RTL_LAYOUT = 6 Global Const $DWMWA_FORCE_ICONIC_REPRESENTATION = 7 Global Const $DWMWA_FLIP3D_POLICY = 8 Global Const $DWMWA_EXTENDED_FRAME_BOUNDS = 9 Global Const $DWMWA_HAS_ICONIC_BITMAP = 10 Global Const $DWMWA_DISALLOW_PEEK = 11 Global Const $DWMWA_EXCLUDED_FROM_PEEK = 12 Microsoft (dated 07/10/2023) has the following Syntax that I assume is starting at zero, setting DWMWA_NCRENDERING_ENABLED = 0 typedef enum DWMWINDOWATTRIBUTE { DWMWA_NCRENDERING_ENABLED, DWMWA_NCRENDERING_POLICY, DWMWA_TRANSITIONS_FORCEDISABLED, DWMWA_ALLOW_NCPAINT, DWMWA_CAPTION_BUTTON_BOUNDS, DWMWA_NONCLIENT_RTL_LAYOUT, DWMWA_FORCE_ICONIC_REPRESENTATION, DWMWA_FLIP3D_POLICY, DWMWA_EXTENDED_FRAME_BOUNDS, DWMWA_HAS_ICONIC_BITMAP, DWMWA_DISALLOW_PEEK, DWMWA_EXCLUDED_FROM_PEEK, DWMWA_CLOAK, DWMWA_CLOAKED, DWMWA_FREEZE_REPRESENTATION, DWMWA_PASSIVE_UPDATE_MODE, DWMWA_USE_HOSTBACKDROPBRUSH, DWMWA_USE_IMMERSIVE_DARK_MODE = 20, DWMWA_WINDOW_CORNER_PREFERENCE = 33, DWMWA_BORDER_COLOR, DWMWA_CAPTION_COLOR, DWMWA_TEXT_COLOR, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_LAST } ; What really throws me is that the APIGdiConstants.au3 lines just below the set above (89-91) do correlate to what Microsoft says and they work as expected: Global Const $DWMNCRP_USEWINDOWSTYLE = 0 Global Const $DWMNCRP_DISABLED = 1 Global Const $DWMNCRP_ENABLED = 2 Microsoft (dated 02/22/2024): typedef enum DWMNCRENDERINGPOLICY { DWMNCRP_USEWINDOWSTYLE, DWMNCRP_DISABLED, DWMNCRP_ENABLED, DWMNCRP_LAST } ; AutoIt Code Example: Opt("MustDeclareVars", 1);require variables to be declared #include <GUIConstantsEx.au3> #include <WinAPIGdi.au3> ;*** Create a GUI with various controls. Local $hGUI = GUICreate("Example", 400, 400) ;*** Display the GUI. GUISetState(@SW_SHOW, $hGUI) ConsoleWrite("$DWMWA_NCRENDERING_POLICY: '" & $DWMWA_NCRENDERING_POLICY & "' (expecting 2, but MS says 1)" & @CRLF) ConsoleWrite("$DWMNCRP_DISABLED: '" & $DWMNCRP_DISABLED & "' (expecting 1 per AutoIt and MS)" & @CRLF) #Region - Uncomment the block for the scenario that you want to see ;*** Demonstrate that APIGdiConstants.au3 declaration of $DWMWA_NCRENDERING_POLICY = 2 instead of Microsoft's enum = 1 works ConsoleWrite("Before: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 1)" & @CRLF) _WinAPI_DwmSetWindowAttribute($hGUI, $DWMWA_NCRENDERING_POLICY, $DWMNCRP_DISABLED) ConsoleWrite("After: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 0)" & @CRLF) ;~ ;*** Demonstrate that the value for APIGdiConstants.au3 declaration of $DWMWA_NCRENDERING_POLICY = 2 instead of Microsoft's enum = 1 works ;~ ConsoleWrite("Before: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 1)" & @CRLF) ;~ _WinAPI_DwmSetWindowAttribute($hGUI, 2, $DWMNCRP_DISABLED) ;~ ConsoleWrite("After: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 0)" & @CRLF) ;~ ;*** Demonstrate that Microsoft's enum = 1 does not work because APIGdiConstants.au3 has it mapped to $DWMWA_NCRENDERING_ENABLED ;~ ConsoleWrite("Before: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 1)" & @CRLF) ;~ _WinAPI_DwmSetWindowAttribute($hGUI, 1, $DWMNCRP_DISABLED) ;~ ConsoleWrite("After: '" & _WinAPI_DwmGetWindowAttribute ( $hGUI, $DWMWA_NCRENDERING_ENABLED ) & "' (expecting 0)" & @CRLF) #EndRegion - Uncomment the block for the scenario that you want to see ;*** Delete the previous GUI and all controls. GUIDelete($hGUI) Here is my online C++ attempt to understand/confirm how C++ enumerations work, and they seem to work exactly how I understand (I.e. start at 0 unless differently declared). Edit: This stemmed from an example about how to force rounded corners, of which I actually wanted the opposite, and achieved it from that code.
-
Decibel reacted to a post in a topic: Rounded corners on Windows 11
-
Decibel reacted to a post in a topic: FileSetTime() Bug?
-
Decibel reacted to a post in a topic: Mouse click plus UDF
-
Decibel reacted to a post in a topic: Kind LarsJ, how does UIA Spy identify these windows?
-
Decibel reacted to a post in a topic: Manipulate system tray program? (right click, choose option)
-
Interesting. I modified this UIA approach a few years ago (has it really been that long?!!) to mouse over (MouseMove) all of the icons to get rid of phantom ones left behind when a process is killed.
-
That's pretty fun. It ran fine without those includes (Math and Array) in 3.3.16.1. Here's a little demo that will start Paint (Win10), if it's not already running, and wait a bit for you to click inside of it to start drawing from where you clicked. By checking for Paint to already be running, you can click in a slightly different starting point to draw lines like in your example images to watch the "human" variations. ;*** The usual configurations Opt("MustDeclareVars", 1) ;require variables to be declared Opt("WinTitleMatchMode", 1) ;(default) Match the title from the start (case-sensitive) Opt("MouseCoordMode", 1) ;(default) absolute screen coordinates Opt("PixelCoordMode", 1) ;(default) absolute screen coordinates ;*** Set up drawing environment in Paint Local $sWindowTitle = "Untitled - Paint" If WinExists($sWindowTitle) = False Then Run("C:\Windows\system32\mspaint.exe", @ScriptDir, @SW_MAXIMIZE) WinWait($sWindowTitle) WinActivate("Program Manager") ;take the focus away from Paint ;*** Wait some time for you to aim then click where you want to start drawing If WinWaitActive($sWindowTitle, "", 10) = 0 Then Exit ;*** Figure out the starting and ending points Local $aiPos = MouseGetPos() Local $iPixelsAcross = 1000 ;negative moves left Local $iPixelsDown = -100 ;negative moves upward ;*** Move it, move it MouseDown("left") MoveMouse($aiPos[0], $aiPos[1], $aiPos[0] + $iPixelsAcross, $aiPos[1] + $iPixelsDown) MouseUp("left")
-
TheDcoder reacted to a post in a topic: Extended Message Box - New Version: 16 Feb 24
-
Extended Message Box - New Version: 16 Feb 24
Decibel replied to Melba23's topic in AutoIt Example Scripts
Hey Melba, I'm using the latest version (19 Nov 21) on AutoIt 3.3.16.0. I added this to a script that doesn't have an AutoIt GUI involved and hit a small nuisance. I dug into it and found that it's because none of the chained #include <ExtMsgBox.au3> have any references to $SS_LEFT, $SS_CENTER, $SS_RIGHT for use as the 2nd parameter ($iJust) of _ExtMsgBoxSet(). I prefer using constants for readability, and these are referenced as being allowed. Did you put that in there just to see if anyone reads the docs? 🤓 Possible solutions are these in my recommended order: Remove the mention of $SS_LEFT, $SS_CENTER, $SS_RIGHT from the _ExtMsgBoxSet() function header in ExtMsgBox.au3 (I.e. Delete line 98), and from being used your ExtMsgBox_Example_1.au3 and ExtMsgBox_Example_3.au3. Add #include <StaticConstants.au3> to ExtMsgBox.au3. I'm currently adding this as an #include to my scripts beneath ExtMsgBox.au3 as you did in Examples 1 & 3. Add $SS_LEFT, $SS_CENTER, $SS_RIGHT as Global Const in ExtMsgBox.au3. It's messy using the same names that exist elsewhere though. Not a big deal, but if you're looking to post an updated version any time soon this might help some others from hitting this bump. I got lucky with the first script that I used your UDF with because I had #include <GUIConstants.au3> in it, which includes StaticConstants.au3 so everything "just worked." Thanks for this UDF! -
Extended Message Box - New Version: 16 Feb 24
Decibel replied to Melba23's topic in AutoIt Example Scripts
@Melba23, I'm totally facepalming right now. Of course _ExtMsgBoxSet is where it should live so that setting persists in all subsequent _ExtMsgBox calls. Nicely done. I didn't fully understand how to leverage _ExtMsgBoxSet that first night and pry barred a fix into _ExtMsgBox. Always learning. -
Extended Message Box - New Version: 16 Feb 24
Decibel replied to Melba23's topic in AutoIt Example Scripts
I love this UDF, and your coding style and naming convention for variables. The _ExtMsgBox parameter of $bMain = True was the clincher for me. The countdown timer from $vIcon = 128 was the gravy. I made a tweak to it to allow for specifying a title bar icon file so that the _ExtMsgBox can match the parent window's icon. I had to do it in a manual sort of way because trying to get the icon out of the parent window was a bit much to do for running out of SciTE and running from a compiled exe. This did not require my exe to carry the ico file alongside it for distribution to other PCs. Overview of _ExtMsgBox changes: 1. Appended to the function comments, parameters section: ; $sTitlebarIconFile -> "" (default) = Use the generic AutoIt icon ; File path to the icon file to use 2. Appended the new optional parameter to the Func line: Func _ExtMsgBox($vIcon, $vButton, $sTitle, $sText, $iTimeOut = 0, $hWin = "", $iVPos = 0, $bMain = True, $sTitlebarIconFile = "") 3. Added this after the GUICreate line: If $sTitlebarIconFile <> "" And FileExists($sTitlebarIconFile) = True Then GUISetIcon($sTitlebarIconFile) ; will change icon EndIf Modified function in its entirety: ; #FUNCTION# ========================================================================================================= ; Name...........: _ExtMsgBox ; Description ...: Generates user defined message boxes centred on a GUI, the desktop, or at defined coordinates ; Syntax.........: _ExtMsgBox ($vIcon, $vButton, $sTitle, $sText, [$iTimeout, [$hWin, [$iVPos, [$bMain = True]]]]) ; Parameters ....: $vIcon -> Icon to use: ; 0 - No icon ; 8 - UAC ; 16 - Stop ) ; 32 - Query ) or equivalent $MB/$EMB_ICON constant ; 48 - Exclamation ) ; 64 - Information ) ; 128 - Countdown digits if $iTimeout set ; Any other numeric value returns Error 1 ; If set to the name of an ico or exe file, the main icon within will be displayed ; If another icon from the file is required, add a trailing "|" followed by the icon index ; If set to the name of an image file, that image will be displayed ; $vButton -> Button text separated with "|" character. " " = no buttons. ; Putting a user-defined character (default = "~") before the text indicates button to be focused ; Two focused buttons returns Error 2. A single button is always focused ; Use of standard Windows keyboard shortcut by adding "&" before the button text is still available ; Note UDF focused button character must be placed first, e.g. "~&Yes|&No" ; Can also use $MB_ button numeric constants to define buttons: 0 = "OK", 1 = "~OK|Cancel", ; 2 = "~Abort|Retry|Ignore", 3 = "~Yes|No|Cancel", 4 = "~Yes|No", 5 = "~Retry|Cancel", ; 6 = "~Cancel|Try Again|Continue". Other values return Error 3 ; Default max width of 370 gives 1-4 buttons @ width 80, 5 @ width 60, 6 @ width 50 ; Min button width set at 50, so unless default widths changed 7 buttons will return Error 4 ; $sTitle -> The title of the message box. ; Procrustean truncation if too long to fit ; $sText -> The text to be displayed. Long lines will wrap. The box depth is adjusted to fit. ; If unbroken character strings in $sText too long for set max width, ; EMB expands to set absolute width. Error 6 if still not able to fit ; $iTimeout -> Timeout delay before EMB closes. 0 = no timeout (Default). ; If no buttons and no timeout set, timeout automatically set to 5 ; If timeout value negative, reset to 0 ; $hWin -> Handle of the GUI in which EMB is centred ; If GUI hidden or no handle passed - EMB centred in desktop (Default) ; If not valid window handle, interpreted as horizontal coordinate for EMB location ; $iVPos -> Vertical coordinate for EMB location ; Only valid if $hWin parameter interpreted as horizontal coordinate (Default = 0) ; $bMain -> True (default) = Adjust dialog position to ensure dialog positioned on main screen ; False = Dialog positioned at user-defined coords, which can be on other screens ; $sTitlebarIconFile -> "" (default) = Use the generic AutoIt icon ; File path to the icon file to use ; Requirement(s).: v3.2.12.1 or higher ; Return values .: Success: Returns 1-based index of the button pressed, counting from the LEFT. ; Returns 0 if closed by a "CloseGUI" event (i.e. click [X] or press Escape) ; Returns 9 if timed out ; If "Not again" checkbox is present and checked, return value is negated ; Failure: Returns -1 and sets @error as follows: ; 1 - Icon parameter error ; 2 - Multiple default button error ; 3 - Button constant error ; 4 - Too many buttons to fit in max available EMB width ; 5 - Button text too long for max available button width ; 6 - StringSize error ; 7 - GUI creation error ; Remarks .......; If $bMain set EMB adjusted to appear on main screen closest to required position ; Author ........: Melba23, based on some original code by photonbuddy & YellowLab ; Example........; Yes ;===================================================================================================================== Func _ExtMsgBox($vIcon, $vButton, $sTitle, $sText, $iTimeOut = 0, $hWin = "", $iVPos = 0, $bMain = True, $sTitlebarIconFile = "") ; Set default sizes for message box Local $iMsg_Width_Max = $g_aEMB_Settings[6], $iMsg_Width_Min = 150, $iMsg_Width_Abs = $g_aEMB_Settings[7] Local $iMsg_Height_Min = 100 Local $iButton_Width_Def = 80, $iButton_Width_Min = 50 ; Declare local variables Local $iParent_Win = 0, $fCountdown = False, $cCheckbox, $aLabel_Size, $aRet, $iRet_Value, $iHpos Local $sButton_Text, $iButton_Width, $iButton_Xpos ; Validate timeout value $iTimeOut = Int(Number($iTimeOut)) If $iTimeOut < 0 Then $iTimeOut = 0 EndIf ; Set automatic timeout if no buttons and no timeout set If $vButton == " " And $iTimeOut = 0 Then $iTimeOut = 5 EndIf ; Check for icon Local $iIcon_Style = 0 Local $iIcon_Reduction = 36 Local $sDLL = "user32.dll" Local $sImg = "" ; Cancel numeric countdown if no timeout If $iTimeOut = 0 And $vIcon = 128 Then $vIcon = 0 EndIf If StringIsDigit($vIcon) Then Switch $vIcon Case 0 $iIcon_Reduction = 0 Case 8 $sDLL = "imageres.dll" $iIcon_Style = 78 Case 16 ; Stop $iIcon_Style = -4 Case 32 ; Query $iIcon_Style = -3 Case 48 ; Exclam $iIcon_Style = -2 Case 64 ; Info $iIcon_Style = -5 Case 128 ; Countdown If $iTimeOut > 0 Then $fCountdown = True EndIf Case Else Return SetError(1, 0, -1) EndSwitch Else If StringInStr($vIcon, "|") Then $iIcon_Style = StringRegExpReplace($vIcon, "(.*)\|", "") $sDLL = StringRegExpReplace($vIcon, "\|.*$", "") Else Switch StringLower(StringRight($vIcon, 3)) Case "exe", "ico" $sDLL = $vIcon Case "bmp", "jpg", "gif", "png" $sImg = $vIcon EndSwitch EndIf EndIf ; Check if two buttons are seeking focus Local $sFocus_Char = $g_aEMB_Settings[13] StringReplace($vButton, $sFocus_Char, "") If @extended > 1 Then Return SetError(2, 0, -1) EndIf ; Check if using constants or text If IsNumber($vButton) Then Switch $vButton Case 0 $vButton = "OK" Case 1 $vButton = $sFocus_Char & "OK|Cancel" Case 2 $vButton = $sFocus_Char & "Abort|Retry|Ignore" Case 3 $vButton = $sFocus_Char & "Yes|No|Cancel" Case 4 $vButton = $sFocus_Char & "Yes|No" Case 5 $vButton = $sFocus_Char & "Retry|Cancel" Case 6 $vButton = $sFocus_Char & "Cancel|Try Again|Continue" Case Else Return SetError(3, 0, -1) EndSwitch EndIf ; Set default values Local $aButton_Text[1] = [0] Local $iButton_Width_Req = 0 ; Get required button size If $vButton <> " " Then ; Split button text into individual strings $aButton_Text = StringSplit($vButton, "|") ; Get absolute available width for each button Local $iButton_Width_Abs = Floor((($iMsg_Width_Max - 10) / $aButton_Text[0]) - 10) ; Error if below min button size If $iButton_Width_Abs < $iButton_Width_Min Then Return SetError(4, 0, -1) EndIf ; Determine required size of buttons to fit text Local $iButton_Width_Text = 0 ; Loop through button text For $i = 1 To $aButton_Text[0] ; Remove a possible leading focus character $sButton_Text = StringRegExpReplace($aButton_Text[$i], "^" & $sFocus_Char & "?(.*)$", "$1") ; Check on font to use If BitAND($g_aEMB_Settings[0], 4) Then $aRet = _StringSize($sButton_Text, $g_aEMB_Settings[10], Default, Default, $g_aEMB_Settings[11]) Else $aRet = _StringSize($sButton_Text, $g_aEMB_Settings[4], Default, Default, $g_aEMB_Settings[5]) EndIf If IsArray($aRet) And $aRet[2] + 10 > $iButton_Width_Text Then ; Find max button width required for text $iButton_Width_Text = $aRet[2] + 10 EndIf Next ; Error if text would make required button width > absolute available If $iButton_Width_Text > $iButton_Width_Abs Then Return SetError(5, 0, -1) EndIf ; Determine button size to use - assume default $iButton_Width = $iButton_Width_Def ; If text requires wider then default If $iButton_Width_Text > $iButton_Width_Def Then ; Increase - cannot be > absolute $iButton_Width = $iButton_Width_Text EndIf ; If absolute < default If $iButton_Width_Abs < $iButton_Width_Def Then ; If text > min (text must be < abs) If $iButton_Width_Text > $iButton_Width_Min Then ; Set text width $iButton_Width = $iButton_Width_Text Else ; Set min width $iButton_Width = $iButton_Width_Min EndIf EndIf ; Determine GUI width required for all buttons at this width $iButton_Width_Req = (($iButton_Width + 10) * $aButton_Text[0]) + 10 EndIf ; Set tab expansion flag if required Local $iExpTab = Default If BitAND($g_aEMB_Settings[0], 8) Then $iExpTab = 1 EndIf ; Get message label size While 1 Local $aLabel_Pos = _StringSize($sText, $g_aEMB_Settings[4], Default, $iExpTab, $g_aEMB_Settings[5], $iMsg_Width_Max - 20 - $iIcon_Reduction) If @error Then If $iMsg_Width_Max >= $iMsg_Width_Abs Then Return SetError(6, 0, -1) Else $iMsg_Width_Max += 10 EndIf Else ExitLoop EndIf WEnd ; Reset text to wrapped version $sText = $aLabel_Pos[0] ; Set label size Local $iLabel_Width = $aLabel_Pos[2] Local $iLabel_Height = $aLabel_Pos[3] ; Set GUI size Local $iMsg_Width = $iLabel_Width + 20 + $iIcon_Reduction ; Increase width to fit buttons if needed If $iButton_Width_Req > $iMsg_Width Then $iMsg_Width = $iButton_Width_Req If $iMsg_Width < $iMsg_Width_Min Then $iMsg_Width = $iMsg_Width_Min $iLabel_Width = $iMsg_Width_Min - 20 EndIf ; Check if title sets width Local $iDialog_Width = $iMsg_Width ; Size title Local $aTitleSize = _StringSize($sTitle, $g_aEMB_Settings[10], Default, Default, $g_aEMB_Settings[11]) ; Check if title wider than text If $aTitleSize[2] > ($iMsg_Width - 70) Then ; Assume icon reduction of 50 regardless of icon setting ; Adjust dialog width up to absolute dialog width value $iDialog_Width = ( ($aTitleSize[2] < ($g_aEMB_Settings[7] - $g_aEMB_Settings[12])) ? ($aTitleSize[2] + $g_aEMB_Settings[12]) : ($g_aEMB_Settings[7]) ) EndIf Local $iMsg_Height = $iLabel_Height + 35 ; Increase height if buttons present If $vButton <> " " Then $iMsg_Height += 30 EndIf ; Increase height if checkbox required If BitAND($g_aEMB_Settings[0], 16) Then $iMsg_Height += 40 EndIf If $iMsg_Height < $iMsg_Height_Min Then $iMsg_Height = $iMsg_Height_Min ; If only single line, lower label to to centre text on icon Local $iLabel_Vert = 20 If StringInStr($sText, @CRLF) = 0 Then $iLabel_Vert = 27 ; Check for taskbar button style required If Mod($g_aEMB_Settings[0], 2) = 1 Then ; Hide taskbar button so create as child If IsHWnd($hWin) Then $iParent_Win = $hWin ; Make child of that window Else $iParent_Win = WinGetHandle(AutoItWinGetTitle()) ; Make child of AutoIt window EndIf EndIf ; Determine EMB location If $hWin = "" Then ; No handle or position passed so centre on screen $iHpos = (@DesktopWidth - $iDialog_Width) / 2 $iVPos = (@DesktopHeight - $iMsg_Height) / 2 Else If IsHWnd($hWin) Then ; Get parent GUI pos if visible If BitAND(WinGetState($hWin), 2) Then ; Set EMB to centre on parent Local $aPos = WinGetPos($hWin) $iHpos = ($aPos[2] - $iDialog_Width) / 2 + $aPos[0] - 3 $iVPos = ($aPos[3] - $iMsg_Height) / 2 + $aPos[1] - 20 Else ; Set EMB to centre om screen $iHpos = (@DesktopWidth - $iDialog_Width) / 2 $iVPos = (@DesktopHeight - $iMsg_Height) / 2 EndIf Else ; Assume parameter is horizontal coord $iHpos = $hWin ; $iVpos already set EndIf EndIf ; If dialog is to appear on main display If $bMain Then ; Dialog is visible horizontally If $iHpos < 10 Then $iHpos = 10 If $iHpos + $iDialog_Width > @DesktopWidth - 20 Then $iHpos = @DesktopWidth - 20 - $iDialog_Width ; Then vertically If $iVPos < 10 Then $iVPos = 10 If $iVPos + $iMsg_Height > @DesktopHeight - 60 Then $iVPos = @DesktopHeight - 60 - $iMsg_Height EndIf ; Remove TOPMOST extended style if required Local $iExtStyle = 0x00000008 ; $WS_TOPMOST If BitAND($g_aEMB_Settings[0], 2) Then $iExtStyle = -1 ; Create GUI with $WS_POPUPWINDOW, $WS_CAPTION style and required extended style Local $hMsgGUI = GUICreate($sTitle, $iDialog_Width, $iMsg_Height, $iHpos, $iVPos, BitOR(0x80880000, 0x00C00000), $iExtStyle, $iParent_Win) If @error Then Return SetError(7, 0, -1) EndIf If $sTitlebarIconFile <> "" And FileExists($sTitlebarIconFile) = True Then GUISetIcon($sTitlebarIconFile) ; will change icon EndIf ; Check if titlebar icon hidden - actually uses transparent icon from AutoIt executable If BitAND($g_aEMB_Settings[0], 32) Then If @Compiled Then GUISetIcon(@ScriptName, -2, $hMsgGUI) Else GUISetIcon(@AutoItExe, -2, $hMsgGUI) EndIf EndIf If $g_aEMB_Settings[2] <> Default Then GUISetBkColor($g_aEMB_Settings[2]) ; Check if user closure permitted If BitAND($g_aEMB_Settings[0], 64) Then $aRet = DllCall("User32.dll", "hwnd", "GetSystemMenu", "hwnd", $hMsgGUI, "int", 0) Local $hSysMenu = $aRet[0] DllCall("User32.dll", "int", "RemoveMenu", "hwnd", $hSysMenu, "int", 0xF060, "int", 0) ; $SC_CLOSE DllCall("User32.dll", "int", "DrawMenuBar", "hwnd", $hMsgGUI) EndIf ; Set centring parameter Local $iLabel_Style = 0 ; $SS_LEFT If BitAND($g_aEMB_Settings[1], 1) = 1 Then $iLabel_Style = 1 ; $SS_CENTER ElseIf BitAND($g_aEMB_Settings[1], 2) = 2 Then $iLabel_Style = 2 ; $SS_RIGHT EndIf ; Create label GUICtrlCreateLabel($sText, 10 + $iIcon_Reduction, $iLabel_Vert, $iLabel_Width, $iLabel_Height, $iLabel_Style) GUICtrlSetFont(-1, $g_aEMB_Settings[4], Default, Default, $g_aEMB_Settings[5]) If $g_aEMB_Settings[3] <> Default Then GUICtrlSetColor(-1, $g_aEMB_Settings[3]) ; Create checkbox if required If BitAND($g_aEMB_Settings[0], 16) Then Local $sAgain = " Do not show again" Local $iY = $iLabel_Vert + $iLabel_Height + 10 ; Create checkbox $cCheckbox = GUICtrlCreateCheckbox("", 10 + $iIcon_Reduction, $iY, 20, 20) ; Write text in separate checkbox label Local $cCheckLabel = GUICtrlCreateLabel($sAgain, 20, 20, 20, 20) GUICtrlSetColor($cCheckLabel, $g_aEMB_Settings[3]) GUICtrlSetBkColor($cCheckLabel, $g_aEMB_Settings[2]) ; Set font if required and size checkbox label text If BitAND($g_aEMB_Settings[0], 4) Then $aLabel_Size = _StringSize($sAgain) Else $aLabel_Size = _StringSize($sAgain, $g_aEMB_Settings[4], 400, 0, $g_aEMB_Settings[5]) GUICtrlSetFont($cCheckLabel, $g_aEMB_Settings[4], 400, 0, $g_aEMB_Settings[5]) EndIf ; Move and resize checkbox label to fit $iY = ($iY + 10) - ($aLabel_Size[3] - 4) / 2 ControlMove($hMsgGUI, "", $cCheckLabel, 30 + $iIcon_Reduction, $iY, $iMsg_Width - (30 + $iIcon_Reduction), $aLabel_Size[3]) EndIf ; Create icon, image or countdown timer If $fCountdown = True Then Local $cCountdown_Label = GUICtrlCreateLabel(StringFormat("%2s", $iTimeOut), 10, 20, 32, 32) GUICtrlSetFont(-1, 18, Default, Default, $g_aEMB_Settings[5]) GUICtrlSetColor(-1, $g_aEMB_Settings[3]) Else If $iIcon_Reduction Then Switch StringLower(StringRight($sImg, 3)) Case "bmp", "jpg", "gif" GUICtrlCreatePic($sImg, 4, 4, 32, 32) Case "png" __EMB_ShowPNG($sImg) Case Else GUICtrlCreateIcon($sDLL, $iIcon_Style, 4, 4) EndSwitch EndIf EndIf ; Create buttons Local $aButtonCID[$aButton_Text[0] + 1] = [9999] ; Placeholder prevent problems if no buttons If $vButton <> " " Then ; Calculate button horizontal start If $aButton_Text[0] = 1 Then If BitAND($g_aEMB_Settings[1], 4) = 4 Then ; Single centred button $iButton_Xpos = ($iMsg_Width - $iButton_Width) / 2 Else ; Single offset button $iButton_Xpos = $iMsg_Width - $iButton_Width - 10 EndIf Else ; Multiple centred buttons $iButton_Xpos = ($iMsg_Width - ($iButton_Width_Req - 20)) / 2 EndIf ; Set default button style Local $iDef_Button_Style = 0 ; Work through button list For $i = 0 To $aButton_Text[0] - 1 Local $iButton_Text = $aButton_Text[$i + 1] ; Set default button If $aButton_Text[0] = 1 Then ; Only 1 button $iDef_Button_Style = 0x0001 ElseIf StringLeft($iButton_Text, 1) = $sFocus_Char Then ; Look for focus character $iDef_Button_Style = 0x0001 $aButton_Text[$i + 1] = StringTrimLeft($iButton_Text, 1) EndIf ; Draw button $aButtonCID[$i + 1] = GUICtrlCreateButton($aButton_Text[$i + 1], $iButton_Xpos + ($i * ($iButton_Width + 10)), $iMsg_Height - 35, $iButton_Width, 25, $iDef_Button_Style) ; Set focus if default If $iDef_Button_Style Then GUICtrlSetState($aButtonCID[$i + 1], 256) ; $GUI_FOCUS EndIf ; Set font if required If Not BitAND($g_aEMB_Settings[0], 4) Then GUICtrlSetFont(-1, $g_aEMB_Settings[4], 400, 0, $g_aEMB_Settings[5]) ; Reset default style parameter $iDef_Button_Style = 0 Next EndIf ; Show GUI GUISetState(@SW_SHOW, $hMsgGUI) ; Begin timeout counter Local $iTimeout_Begin = TimerInit() Local $iCounter = 0 ; Declare GUIGetMsg return array here and not in loop Local $aMsg ; Set MessageLoop mode Local $iOrgMode = Opt('GUIOnEventMode', 0) While 1 $aMsg = GUIGetMsg(1) If $aMsg[1] = $hMsgGUI Then Select Case $aMsg[0] = -3 ; $GUI_EVENT_CLOSE $iRet_Value = 0 ExitLoop Case Else ; Check for other buttons For $i = 1 To UBound($aButtonCID) - 1 If $aMsg[0] = $aButtonCID[$i] Then $iRet_Value = $i ; No point in looking further ExitLoop 2 EndIf Next EndSelect EndIf ; Timeout if required If TimerDiff($iTimeout_Begin) / 1000 >= $iTimeOut And $iTimeOut > 0 Then $iRet_Value = 9 ExitLoop EndIf ; Show countdown if required If $fCountdown = True Then Local $iTimeRun = Int(TimerDiff($iTimeout_Begin) / 1000) If $iTimeRun <> $iCounter Then $iCounter = $iTimeRun GUICtrlSetData($cCountdown_Label, StringFormat("%2s", $iTimeOut - $iCounter)) EndIf EndIf WEnd ; Reset original mode Opt('GUIOnEventMode', $iOrgMode) If GUICtrlRead($cCheckbox) = 1 Then ; Negate the return value $iRet_Value *= -1 EndIf GUIDelete($hMsgGUI) Return $iRet_Value EndFunc ;==>_ExtMsgBox Example Usage: Local $hwnd = WinActivate("My Test App") _ExtMsgBoxSet( _ 1, _ ;No Taskbar Button, and makes it modal to the parent window $SS_LEFT, _ ;text justification -1, _ ;colour for the message box background. Default = system colour -1, _ ;colour for the message box text. Default = system colour -1, _ ;font size in points to use for the message box. Default = system font size -1, _ ;font to use for the message box. Default = system font Default, _ ;Normal max width for EMB. Default/min = 370 pixels - max = @DesktopWidth - 20 Default, _ ;Absolute max width for EMB. Default/min = 370 pixels - max = @DesktopWidth - 20 "~") ;Character to define focused button. Default = "~" Local $sMsg = "Auto closing in 10 seconds." & @CRLF & "Do you want to leave it open?" $iMsgboxResult = _ExtMsgBox( _ 128, _ ;makes it have a countdown timer label instead of an icon "~Yes|No", _ ;buttons do display, with Yes as default focus WinGetTitle($hwnd), _ ;title for msgbox $sMsg, _ ;text to put on msgbox 10, _ ;timeout that will be counted down $hwnd, _ ;window to center over Default, _ ;has to be Default or 0 since we are passing in a hwnd above False, _ ;center on hwnd regardless of which monitor it is on "MyTest.ico") ;title bar icon path If $iMsgboxResult = 2 Or $iMsgboxResult = 9 Then ;2 = 2nd button "No", 9 = timed out Exit EndIf -
PeTFreitas reacted to a post in a topic: Dual-Monitor Resolution Detection
-
BigDaddyO reacted to a post in a topic: A Non-Strict JSON UDF (JSMN)
-
Ah, I see. There are are so many examples going back so many versions in this thread. It appears that in my digging, I went with the wrong/obsolete ones.
-
Doing my part to update us on how the changes in Chrome have caused us to have to change the example script "Chrome - Clicking an extension" which was actually how to open a new tab in Chrome. That answer uses MouseClick because the Invoke method didn't work at that time. I'm going to guess that was a Chrome issue for that older version because it works now. Being able to use the UIA Invoke means that Chrome windows does not have to be the active window, but it will become the active window to the New Tab. This example also uses the approach of setting the client application's UIA object by its hWnd rather than a FindAll from the Desktop object. #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y ; If target application is running as 64 bit code #include ".\Includes\UIA_Constants.au3" ;<--More recent approach (February 9, 2020 by LarsJ) https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/ Opt( "MustDeclareVars", 1 ) Opt("WinTitleMatchMode", 2);Match any substring in the title (case-sensitive) Example() Func Example() ; Create UI Automation object Local $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtag_IUIAutomation ) If Not IsObj( $oUIAutomation ) Then Return ConsoleWrite( "$oUIAutomation ERR" & @CRLF ) ConsoleWrite( "$oUIAutomation OK" & @CRLF ) ;*** Get element by handle, without having to first get the Desktop Local $hWindow = WinGetHandle("[TITLE:Google Chrome; CLASS:Chrome_WidgetWin_1]") ConsoleWrite( "$hWindow: " & $hWindow & ", " & WinGetTitle($hWindow) & @CRLF ) Local $pElement, $oChrome $oUIAutomation.ElementFromHandle($hWindow, $pElement) $oChrome = ObjCreateInterface($pElement, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement9) If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ConsoleWrite( "$oChrome OK" & @CRLF ) ; --- Find New Tab button --- ;*** Set up the 2 property condition for the tree search Local $pCondition0, $pCondition1, $pAndCondition1 $oUIAutomation.CreatePropertyCondition( $UIA_ControlTypePropertyId, $UIA_ButtonControlTypeId, $pCondition0 ) $oUIAutomation.CreatePropertyCondition( $UIA_NamePropertyId, "New Tab", $pCondition1 ) $oUIAutomation.CreateAndCondition( $pCondition0, $pCondition1, $pAndCondition1 ) If Not $pAndCondition1 Then Return ConsoleWrite( "$pAndCondition1 ERR" & @CRLF ) ConsoleWrite( "$pAndCondition1 OK" & @CRLF ) ; Search for and set the object Local $pButton1, $oButton1 $oChrome.FindFirst( $TreeScope_Descendants, $pAndCondition1, $pButton1 ) $oButton1 = ObjCreateInterface( $pButton1, $sIID_IUIAutomationElement9, $dtag_IUIAutomationElement9 ) If Not IsObj( $oButton1 ) Then Return ConsoleWrite( "$oButton1 ERR" & @CRLF ) ConsoleWrite( "$oButton1 OK" & @CRLF ) ; Invoke pattern will "click" the button without MouseClick Local $pInvokePattern1, $oInvokePattern1 $oButton1.GetCurrentPattern( $UIA_InvokePatternId, $pInvokePattern1 ) $oInvokePattern1 = ObjCreateInterface( $pInvokePattern1, $sIID_IUIAutomationInvokePattern, $dtag_IUIAutomationInvokePattern ) If Not IsObj( $oInvokePattern1 ) Then Return ConsoleWrite( "$oInvokePattern1 ERR" & @CRLF ) ConsoleWrite( "$oInvokePattern1 OK" & @CRLF ) $oInvokePattern1.Invoke() ;this is listed in the object's "Control Pattern Methods" list EndFunc Environment: Windows 10 Home 64-bit 19042.804, Chrome 64-bit Version 88.0.4324.150, AutoIt 3.3.14.5.
-
When you're working against a client application, not OS objects directly like the System Tray or etc., you can skip the step of getting the Desktop object then using its FindAll method, and go straight to your client application by hWnd which can be retrieved by the good old Windows Management functions like WinGetHandle(). This example comments out the lines that connect to the Desktop object, then use that to connect to the Chrome window. It also shows that you don't need to make Chrome the active window and it will still work fine. We're familiar with that concept from our days of working with Window Management and Controls. By the way, this is also faster than the the other way. #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #AutoIt3Wrapper_UseX64=y ;~ #include "CUIAutomation2.au3" #include ".\Includes\UIA_Constants.au3" ;<--More recent approach (February 9, 2020 by LarsJ) https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/ Opt( "MustDeclareVars", 1 ) Opt("WinTitleMatchMode", 2);<--Match any substring in the title (case-sensitive) Example() Func Example() ; Window handle ;~ Local $hWindow = WinGetHandle( "[CLASS:Chrome_WidgetWin_1]" ) ;<-- This grabs the base chrome.exe process, not one with the GUI, so it doesn't work for this example Local $hWindow = WinGetHandle("[TITLE:Google Chrome; CLASS:Chrome_WidgetWin_1]") ;<-- This can be for any application, not just Chrome that this example is based around If Not IsHWnd( $hWindow ) Then Return ConsoleWrite( "$hWindow ERR" & @CRLF ) ConsoleWrite( "$hWindow OK" & @CRLF ) ;~ ; Activate window ;~ WinActivate( $hWindow ) ;~ Sleep( 100 ) ; UI Automation object Local $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtag_IUIAutomation ) ;<--Find & Replace "$dtagIUIAutomation" with "$dtag_IUIAutomation" (underscore difference) If Not IsObj( $oUIAutomation ) Then Return ConsoleWrite( "$oUIAutomation ERR" & @CRLF ) ConsoleWrite( "$oUIAutomation OK" & @CRLF ) ;~ ; Desktop element ;~ Local $pDesktop, $oDesktop ;~ $oUIAutomation.GetRootElement( $pDesktop ) ;~ $oDesktop = ObjCreateInterface( $pDesktop, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) ;~ If Not IsObj( $oDesktop ) Then Return ConsoleWrite( "$oDesktop ERR" & @CRLF ) ;~ ConsoleWrite( "$oDesktop OK" & @CRLF ) ;~ ;~ ; Chrome window ;~ Local $pCondition ;~ $oUIAutomation.CreatePropertyCondition( $UIA_ClassNamePropertyId, "Chrome_WidgetWin_1", $pCondition ) ;~ If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ;~ ConsoleWrite( "$pCondition OK" & @CRLF ) ;~ ;~ Local $pChrome, $oChrome ;~ $oDesktop.FindFirst( $TreeScope_Descendants, $pCondition, $pChrome ) ;~ $oChrome = ObjCreateInterface( $pChrome, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) ;~ If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ;~ ConsoleWrite( "$oChrome OK" & @CRLF ) ; Get element by handle, without having to first get the UIA Desktop Local $oChrome ;<-- repeating this here because it was commented out in the block above Local $pElement $oUIAutomation.ElementFromHandle($hWindow, $pElement) $oChrome = ObjCreateInterface($pElement, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement9) If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ConsoleWrite( "$oChrome OK" & @CRLF ) ; --- Read a property to assert the object --- Local $vValue $oChrome.GetCurrentPropertyValue( $UIA_NamePropertyId, $vValue) ConsoleWrite( "$UIA_NamePropertyId: " & $vValue & @CRLF ) EndFunc Environment: Windows 10 Home 64-bit 19042.804, Chrome 64-bit Version 88.0.4324.150, AutoIt 3.3.14.5.
-
Here is a performance tip on finding the top level window from the usual Desktop object. The gain will vary depending on how much stuff is open in your tree (UISpy's left pane). My assumption on how the tree walker works could be wrong, but this is my observation. The difference is letting the FindAll method drill down through every...single...subelement, or tell it to just go one level down. I wrapped a timer around the two approaches to show the speed gain. Sure, it's milliseconds, but it accumulates the more your script runs through objects. Low number of windows open: Timer $TreeScope_Descendants: 124.508 Timer $TreeScope_Children: 9.635 15 extra File Explorer windows open: Timer $TreeScope_Descendants: 155.358 Timer $TreeScope_Children: 10.055 So again, you have to know for certain that the element that you are looking for is only one level down from the parent, or your element will not be found. #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #AutoIt3Wrapper_UseX64=y ;~ #include "CUIAutomation2.au3" #include ".\Includes\UIA_Constants.au3" ;<--More recent approach (February 9, 2020 by LarsJ) https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/ Opt( "MustDeclareVars", 1 ) Opt("WinTitleMatchMode", 2);<--Match any substring in the title (case-sensitive) Example() Func Example() ; Window handle Local $hWindow = WinGetHandle( "[CLASS:Chrome_WidgetWin_1]" ) ;<-- This grabs the base chrome.exe process, not one with the GUI, so it doesn't work for this example If Not IsHWnd( $hWindow ) Then Return ConsoleWrite( "$hWindow ERR" & @CRLF ) ConsoleWrite( "$hWindow OK" & @CRLF ) ; Activate window WinActivate( $hWindow ) Sleep( 100 ) ; UI Automation object Local $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtag_IUIAutomation ) ;<--Find & Replace "$dtagIUIAutomation" with "$dtag_IUIAutomation" (underscore difference) If Not IsObj( $oUIAutomation ) Then Return ConsoleWrite( "$oUIAutomation ERR" & @CRLF ) ConsoleWrite( "$oUIAutomation OK" & @CRLF ) ; Desktop element Local $pDesktop, $oDesktop $oUIAutomation.GetRootElement( $pDesktop ) $oDesktop = ObjCreateInterface( $pDesktop, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) If Not IsObj( $oDesktop ) Then Return ConsoleWrite( "$oDesktop ERR" & @CRLF ) ConsoleWrite( "$oDesktop OK" & @CRLF ) ; Chrome window Local $pCondition $oUIAutomation.CreatePropertyCondition( $UIA_ClassNamePropertyId, "Chrome_WidgetWin_1", $pCondition ) If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ConsoleWrite( "$pCondition OK" & @CRLF ) ;~ Local $pChrome, $oChrome ;~ $oDesktop.FindFirst( $TreeScope_Descendants, $pCondition, $pChrome ) ;~ $oChrome = ObjCreateInterface( $pChrome, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) ;~ If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ;~ ConsoleWrite( "$oChrome OK" & @CRLF ) Local $pChrome, $oChrome $oDesktop.FindFirst( $TreeScope_Children, $pCondition, $pChrome ) ;<-- Using $TreeScope_Children so that it only goes 1 branch deep from $oDesktop $oChrome = ObjCreateInterface( $pChrome, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ConsoleWrite( "$oChrome OK" & @CRLF ) ; --- Read a property to assert the object --- Local $vValue $oChrome.GetCurrentPropertyValue( $UIA_NamePropertyId, $vValue) ConsoleWrite( "$UIA_NamePropertyId: " & $vValue & @CRLF ) EndFunc TreeScope_Children - The scope includes children of the element. TreeScope_Descendants - The scope includes children and more distant descendants of the element. Reference: https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/ne-uiautomationclient-treescope Environment: Windows 10 Home 64-bit 19042.804, Chrome 64-bit Version 88.0.4324.150, AutoIt 3.3.14.5.
-
How to activate specific tabs in Google Chrome?
Decibel replied to xuzo's topic in AutoIt General Help and Support
@LarsJ and @junkew, amazing work on providing the numerous write ups on using UI Automation to get us over the hurdles of not being able to work with certain app technologies! I've spent the weekend soaking up as much of your examples and info as I can understand and want to chip in some stuff I figured out that helps me do things more natively. I'll sprinkle in the others nearer to where they are the topic of discussion. LarsJ's answer above uses MouseClick in order to change to a targeted tab. That works just fine and taught me another helpful concept about UIA. Then I found a StackOverflow answer for a different language that had the magic sauce to be able to do it without a MouseClick. I've ported it to AutoIt here showing what to replace: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 #AutoIt3Wrapper_UseX64=y ;~ #include "CUIAutomation2.au3" #include ".\Includes\UIA_Constants.au3" ;<--More recent approach (February 9, 2020 by LarsJ) https://www.autoitscript.com/forum/topic/201683-ui-automation-udfs/ Opt( "MustDeclareVars", 1 ) Example() Func Example() ; Window handle Local $hWindow = WinGetHandle( "[CLASS:Chrome_WidgetWin_1]" ) If Not IsHWnd( $hWindow ) Then Return ConsoleWrite( "$hWindow ERR" & @CRLF ) ConsoleWrite( "$hWindow OK" & @CRLF ) ; Activate window WinActivate( $hWindow ) Sleep( 100 ) ; UI Automation object Local $oUIAutomation = ObjCreateInterface( $sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtag_IUIAutomation ) ;<--Find & Replace All "$dtagIUIAutomation" with "$dtag_IUIAutomation" (underscore difference) If Not IsObj( $oUIAutomation ) Then Return ConsoleWrite( "$oUIAutomation ERR" & @CRLF ) ConsoleWrite( "$oUIAutomation OK" & @CRLF ) ; Desktop element Local $pDesktop, $oDesktop $oUIAutomation.GetRootElement( $pDesktop ) $oDesktop = ObjCreateInterface( $pDesktop, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) If Not IsObj( $oDesktop ) Then Return ConsoleWrite( "$oDesktop ERR" & @CRLF ) ConsoleWrite( "$oDesktop OK" & @CRLF ) ; Chrome window Local $pCondition $oUIAutomation.CreatePropertyCondition( $UIA_ClassNamePropertyId, "Chrome_WidgetWin_1", $pCondition ) If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ConsoleWrite( "$pCondition OK" & @CRLF ) Local $pChrome, $oChrome $oDesktop.FindFirst( $TreeScope_Descendants, $pCondition, $pChrome ) $oChrome = ObjCreateInterface( $pChrome, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) If Not IsObj( $oChrome ) Then Return ConsoleWrite( "$oChrome ERR" & @CRLF ) ConsoleWrite( "$oChrome OK" & @CRLF ) ; --- Forums - AutoIt Forums --- ; Tab item Local $pCondition1 $oUIAutomation.CreatePropertyCondition( $UIA_ControlTypePropertyId, $UIA_TabItemControlTypeId, $pCondition1 ) If Not $pCondition1 Then Return ConsoleWrite( "$pCondition1 ERR" & @CRLF ) ConsoleWrite( "$pCondition1 OK" & @CRLF ) ; Tab name Local $pCondition2 ; Note that $UIA_NamePropertyId ia a CASE SENSITIVE condition $oUIAutomation.CreatePropertyCondition( $UIA_NamePropertyId, "Forums - AutoIt Forums", $pCondition2 ) If Not $pCondition2 Then Return ConsoleWrite( "$pCondition2 ERR" & @CRLF ) ConsoleWrite( "$pCondition2 OK" & @CRLF ) ; And condition $oUIAutomation.CreateAndCondition( $pCondition1, $pCondition2, $pCondition ) If Not $pCondition Then Return ConsoleWrite( "$pCondition ERR" & @CRLF ) ConsoleWrite( "$pCondition OK" & @CRLF ) ; Find tab item Local $pTab, $oTab $oChrome.FindFirst( $TreeScope_Descendants, $pCondition, $pTab ) $oTab = ObjCreateInterface( $pTab, $sIID_IUIAutomationElement, $dtag_IUIAutomationElement ) If Not IsObj( $oTab ) Then Return ConsoleWrite( "$oTab ERR" & @CRLF ) ConsoleWrite( "$oTab OK" & @CRLF ) ;~ ; Rectangle ;~ Local $aRect ; l, t, w, h ;~ $oTab.GetCurrentPropertyValue( $UIA_BoundingRectanglePropertyId, $aRect ) ;~ If Not IsArray( $aRect ) Then Return ConsoleWrite( "$aRect ERR" & @CRLF ) ;~ ConsoleWrite( "$aRect OK" & @CRLF ) ;~ ;~ ; Activate tab ;~ MouseClick( "primary", $aRect[0]+$aRect[2]/2, $aRect[1]+$aRect[3]/2, 1, 0 ) ; Set the interface to use the methods under LegacyIAccessible Pattern Methods seen in UIASpy Local $pLegacyIAccessiblePattern1, $oLegacyIAccessiblePattern1 $oTab.GetCurrentPattern($UIA_LegacyIAccessiblePatternId, $pLegacyIAccessiblePattern1) $oLegacyIAccessiblePattern1 = ObjCreateInterface($pLegacyIAccessiblePattern1, $sIID_IUIAutomationLegacyIAccessiblePattern, $dtag_IUIAutomationLegacyIAccessiblePattern) If Not IsObj( $oLegacyIAccessiblePattern1 ) Then Return ConsoleWrite( "$oLegacyIAccessiblePattern1 ERR" & @CRLF ) ConsoleWrite( "$oLegacyIAccessiblePattern1 OK" & @CRLF ) $oLegacyIAccessiblePattern1.DoDefaultAction() ;magic sauce to activate a Chrome tab without MouseClick gleaned from https://stackoverflow.com/a/58472735 EndFunc Environment: Windows 10 Home 64-bit 19042.804, Chrome 64-bit Version 88.0.4324.150, AutoIt 3.3.14.5. -
mLipok reacted to a post in a topic: Dual-Monitor Resolution Detection
-
Dual-Monitor Resolution Detection
Decibel replied to Overkill's topic in AutoIt General Help and Support
I had a problem with @xrxca's fantastic MultiMon.au3, commented above, with my Windows 10 64-bit configuration. I have four displays, of which only two are the same size. My PC's BIOS displays boot messages on the left monitor, but Windows thinks that it's monitor #2, so I have my Display Settings like the attachment shows ( [2] [1] [3] [4] ). I had to add a few lines to MultiMon.au3 to show the monitors in the correct physical representation, because it was showing Display 2 (primary display) as the 4th hMonitor instead of the 1st. I put an _ArraySort in _GetMonitors() to fix this (at least on my system). I also added a line to the example _ShowMonitorInfo() to provide the hMonitor value(s). See attached "before after" screenshot for the result. #include-Once #include<Array.au3> ;added to fix the display order Global $__MonitorList[1][5] $__MonitorList[0][0] = 0 ; Just for testing ;~ _ArrayDisplay(_GetMonitors()) ;added as another way to see the info _ShowMonitorInfo() ;================================================================================================== ; Function Name: _ShowMonitorInfo() ; Description:: Show the info in $__MonitorList in a msgbox (line 0 is count of monitors and entire Desktop size) ; Parameter(s): n/a ; Return Value(s): n/a ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _ShowMonitorInfo() If $__MonitorList[0][0] == 0 Then _GetMonitors() EndIf Local $Msg = "" Local $i = 0 For $i = 0 To $__MonitorList[0][0] $Msg &= $i & " - hnd:" & $__MonitorList[$i][0] ;added for information $Msg &= ", L:" & $__MonitorList[$i][1] & ", T:" & $__MonitorList[$i][2] $Msg &= ", R:" & $__MonitorList[$i][3] & ", B:" & $__MonitorList[$i][4] If $i < $__MonitorList[0][0] Then $Msg &= @CRLF Next MsgBox(0, $__MonitorList[0][0] & " Monitors: ", $Msg) EndFunc ;==>_ShowMonitorInfo ;================================================================================================== ; Function Name: _MaxOnMonitor($Title[, $Text = ''[, $Monitor = -1]]) ; Description:: Maximize a window on a specific monitor (or the monitor the mouse is on) ; Parameter(s): $Title The title of the window to Move/Maximize ; optional: $Text The text of the window to Move/Maximize ; optional: $Monitor The monitor to move to (1..NumMonitors) defaults to monitor mouse is on ; Note: Should probably have specified return/error codes but haven't put them in yet ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _MaxOnMonitor($Title, $Text = '', $Monitor = -1) _CenterOnMonitor($Title, $Text, $Monitor) WinSetState($Title, $Text, @SW_MAXIMIZE) EndFunc ;==>_MaxOnMonitor ;================================================================================================== ; Function Name: _CenterOnMonitor($Title[, $Text = ''[, $Monitor = -1]]) ; Description:: Center a window on a specific monitor (or the monitor the mouse is on) ; Parameter(s): $Title The title of the window to Move/Maximize ; optional: $Text The text of the window to Move/Maximize ; optional: $Monitor The monitor to move to (1..NumMonitors) defaults to monitor mouse is on ; Note: Should probably have specified return/error codes but haven't put them in yet ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _CenterOnMonitor($Title, $Text = '', $Monitor = -1) $hWindow = WinGetHandle($Title, $Text) If Not @error Then If $Monitor == -1 Then $Monitor = _GetMonitorFromPoint() ElseIf $__MonitorList[0][0] == 0 Then _GetMonitors() EndIf If ($Monitor > 0) And ($Monitor <= $__MonitorList[0][0]) Then ; Restore the window if necessary Local $WinState = WinGetState($hWindow) If BitAND($WinState, 16) Or BitAND($WinState, 32) Then WinSetState($hWindow, '', @SW_RESTORE) EndIf Local $WinSize = WinGetPos($hWindow) Local $x = Int(($__MonitorList[$Monitor][3] - $__MonitorList[$Monitor][1] - $WinSize[2]) / 2) + $__MonitorList[$Monitor][1] Local $y = Int(($__MonitorList[$Monitor][4] - $__MonitorList[$Monitor][2] - $WinSize[3]) / 2) + $__MonitorList[$Monitor][2] WinMove($hWindow, '', $x, $y) EndIf EndIf EndFunc ;==>_CenterOnMonitor ;================================================================================================== ; Function Name: _GetMonitorFromPoint([$XorPoint = -654321[, $Y = 0]]) ; Description:: Get a monitor number from an x/y pos or the current mouse position ; Parameter(s): ; optional: $XorPoint X Position or Array with X/Y as items 0,1 (ie from MouseGetPos()) ; optional: $Y Y Position ; Note: Should probably have specified return/error codes but haven't put them in yet, ; and better checking should be done on passed variables. ; Used to use MonitorFromPoint DLL call, but it didn't seem to always work. ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _GetMonitorFromPoint($XorPoint = 0, $y = 0) If @NumParams = 0 then local $MousePos = MouseGetPos() Local $myX = $MousePos[0] Local $myY = $MousePos[1] Elseif ( @NumParams = 1 ) and IsArray($XorPoint) Then Local $myX = $XorPoint[0] Local $myY = $XorPoint[1] Else Local $myX = $XorPoint Local $myY = $y EndIf If $__MonitorList[0][0] == 0 Then _GetMonitors() EndIf Local $i = 0 Local $Monitor = 0 For $i = 1 To $__MonitorList[0][0] If ($myX >= $__MonitorList[$i][1]) _ And ($myX < $__MonitorList[$i][3]) _ And ($myY >= $__MonitorList[$i][2]) _ And ($myY < $__MonitorList[$i][4]) Then $Monitor = $i Next Return $Monitor EndFunc ;==>_GetMonitorFromPoint ;================================================================================================== ; Function Name: _GetMonitors() ; Description:: Load monitor positions ; Parameter(s): n/a ; Return Value(s): 2D Array of Monitors ; [0][0] = Number of Monitors ; [i][0] = HMONITOR handle of this monitor. ; [i][1] = Left Position of Monitor ; [i][2] = Top Position of Monitor ; [i][3] = Right Position of Monitor ; [i][4] = Bottom Position of Monitor ; Note: [0][1..4] are set to Left,Top,Right,Bottom of entire screen ; hMonitor is returned in [i][0], but no longer used by these routines. ; Also sets $__MonitorList global variable (for other subs to use) ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _GetMonitors() $__MonitorList[0][0] = 0 ; Added so that the global array is reset if this is called multiple times Local $handle = DllCallbackRegister("_MonitorEnumProc", "int", "hwnd;hwnd;ptr;lparam") DllCall("user32.dll", "int", "EnumDisplayMonitors", "hwnd", 0, "ptr", 0, "ptr", DllCallbackGetPtr($handle), "lparam", 0) DllCallbackFree($handle) Local $i = 0 For $i = 1 To $__MonitorList[0][0] If $__MonitorList[$i][1] < $__MonitorList[0][1] Then $__MonitorList[0][1] = $__MonitorList[$i][1] If $__MonitorList[$i][2] < $__MonitorList[0][2] Then $__MonitorList[0][2] = $__MonitorList[$i][2] If $__MonitorList[$i][3] > $__MonitorList[0][3] Then $__MonitorList[0][3] = $__MonitorList[$i][3] If $__MonitorList[$i][4] > $__MonitorList[0][4] Then $__MonitorList[0][4] = $__MonitorList[$i][4] Next _ArraySort($__MonitorList, 0, 1, 0, 0, 0) ;added to sort it by the first column (hMonitor) so that they line up in physical order like Display Settings-->Rearrange Displays Return $__MonitorList EndFunc ;==>_GetMonitors ;================================================================================================== ; Function Name: _MonitorEnumProc($hMonitor, $hDC, $lRect, $lParam) ; Description:: Enum Callback Function for EnumDisplayMonitors in _GetMonitors ; Author(s): xrxca (autoit@forums.xrx.ca) ;================================================================================================== Func _MonitorEnumProc($hMonitor, $hDC, $lRect, $lParam) Local $Rect = DllStructCreate("int left;int top;int right;int bottom", $lRect) $__MonitorList[0][0] += 1 ReDim $__MonitorList[$__MonitorList[0][0] + 1][5] $__MonitorList[$__MonitorList[0][0]][0] = $hMonitor $__MonitorList[$__MonitorList[0][0]][1] = DllStructGetData($Rect, "left") $__MonitorList[$__MonitorList[0][0]][2] = DllStructGetData($Rect, "top") $__MonitorList[$__MonitorList[0][0]][3] = DllStructGetData($Rect, "right") $__MonitorList[$__MonitorList[0][0]][4] = DllStructGetData($Rect, "bottom") Return 1 ; Return 1 to continue enumeration EndFunc ;==>_MonitorEnumProc Now when I use _CenterOnMonitor, it correctly moves the specified WindowTitle to the specified Monitor number. _CenterOnMonitor("Notepad", "", 1) ;leftmost Sleep(2000) _CenterOnMonitor("Notepad", "", 2) ;middle left Sleep(2000) _CenterOnMonitor("Notepad", "", 3) ;middle right Sleep(2000) _CenterOnMonitor("Notepad", "", 4) ;rightmost Edit: I didn't find MultiMon.au3 anywhere in the AutoIt Examples pages to follow up with my 2 cents, so I stuck it here. -
@Jos Yeah, but just found this post and saw that some people were asking for the script to be updated for newer ("AutoIt 3.2.1.0") versions. You can delete my reply if needed.
-
To make this work with AutoIt 3.3.14.5, I renamed both occurrences of $WM_DROPFILES to $WM_DROPFILESb.