How to use PixelSearch() on inactive windows? - windows

Because of the $hwnd parameter I assume PixelSearch() should work on an inactive window but I can't make it do so. When another window is put in front of the one to search, it fails.
My script :
$hwnd = WinGetHandle("[CLASS:MSPaintApp]")
$Cor = PixelSearch(0, 0, #DesktopWidth, #DesktopHeight, 0x39B6EF, 0, 1, $hwnd)
If Not #error Then
MouseMove($Cor[0], $Cor[1])
Else
MsgBox(0, "", #error)
EndIf
How can I make this work on an inactive window?

Simple fix of making sure that the window you want to search on is active (If I read the question correctly). The WinActive checks to see if the window is active, and if it is 0 (not active). Then, we active the window using WinActivate.
Local $hwnd, $Cor
$hwnd = WinGetHandle("[CLASS:MSPaintApp]")
If WinActive($hwnd) = 0 Then
WinActivate($hwnd)
EndIf
$Cor = PixelSearch(0, 0, #DesktopWidth, #DesktopHeight, 0x39B6EF, 0, 1, $hwnd)
If Not #error Then
MouseMove($Cor[0], $Cor[1])
Else
MsgBox(0, "", #error)
EndIf

Related

Running multiple identical applications

Tell me why it does not work? I searched, but did not find how to run several identical applications, so that you can then work with each separately.
The script works, starts the first window, moves it, then the second window starts and the first moves along the second coordinate, and the second one does not move. What is the problem?
Run('c:\Program Files\CPUID\CPU-Z\cpuz.exe')
$hWnd = WinWait("[TITLE:CPU-Z; INSTANCE:1]", "", 0)
If Not $hWnd Then
MsgBox(4096, 'Сообщение', 'Окно не найдено, завершаем работу скрипта')
Exit
EndIf
Sleep(400)
WinMove($hWnd, "", 0, 645)
Run('c:\Program Files\CPUID\CPU-Z\cpuz.exe')
$hWnd2 = WinWaitActive("[TITLE:CPU-Z; INSTANCE:2]", "", 0)
If Not $hWnd2 Then
MsgBox(4096, 'Сообщение', 'Окно не найдено, завершаем работу скрипта')
Exit
EndIf
Sleep(400)
WinMove($hWnd2, "", 405, 645)
How to correctly write such a script?
...and the second one does not move. What is the problem?
Script generates identical $hWnd and $hWnd2 tied to the initial window, which you can check by outputting variables with MsgBox() or _DebugOut() or whatever you like. Looks like INSTANCE property doesn't work well in current scenario, so WinWait() searches window using title only and the second call finds the same window as the first one.
How to correctly write such a script?
Well, I have less than one week of AutoIt experience, so don't hit me hard, but here is my version:
Run('c:\Program Files\CPUID\CPU-Z\cpuz.exe')
Global $hWnd = WinWait("CPU-Z", "", 0)
If Not $hWnd Then
MsgBox(4096, 'Сообщение', 'Окно не найдено, завершаем работу скрипта')
Exit
EndIf
Sleep(400)
WinMove($hWnd, "", 0, 645)
Run('c:\Program Files\CPUID\CPU-Z\cpuz.exe')
Global $hWnd2 = Null
;wait until there are two windows with the same title
Do
Sleep(10)
Global $aList = WinList("CPU-Z")
Until $aList[0][0] > 1
For $i = 1 To $aList[0][0]
If $aList[$i][1] <> $hWnd Then
$hWnd2 = $aList[$i][1]
EndIf
Next
If Not $hWnd2 Then
MsgBox(4096, 'Сообщение', 'Окно не найдено, завершаем работу скрипта')
Exit
EndIf
Sleep(400)
WinMove($hWnd2, "", 405, 645)
EDIT
Bonus: packed repetitive part of the script into function for easy use with multiple windows:
Global $aKnownHandles[1] ;array storing all known win handles
Global $iCounter = 0 ;keeps track of array size
AddInstance(0, 645)
AddInstance(405, 645)
AddInstance(810, 645)
AddInstance(1215, 645)
AddInstance(0, 345)
AddInstance(405, 345)
AddInstance(810, 345)
AddInstance(1215, 345)
AddInstance(0, 50)
AddInstance(405, 50)
AddInstance(810, 50)
AddInstance(1215, 50)
Func AddInstance($x, $y)
Run('c:\Program Files\CPUID\CPU-Z\cpuz.exe')
Do
Sleep(1)
Local $aWinList = WinList("CPU-Z")
Until $aWinList[0][0] > $iCounter
Local $hNewHandle = Null
;for each handle in list of windows ($aWinList)
;check if it matches any item in list of known handles ($aKnownHandles)
;If not, put handle into $hNewHandle variable
For $i = 1 To $aWinList[0][0]
Local $bHandleKnown = false
For $j = 0 To $iCounter-1
If $aWinList[$i][1] == $aKnownHandles[$j] Then
$bHandleKnown = true
ExitLoop
EndIf
Next
If NOT $bHandleKnown Then
$hNewHandle = $aWinList[$i][1]
ExitLoop
EndIf
Next
If Not $hNewHandle Then
MsgBox(4096, 'Сообщение', 'Окно не найдено, завершаем работу скрипта')
Exit
EndIf
Sleep(400)
WinMove($hNewHandle, "", $x, $y)
ReDim $aKnownHandles[$iCounter+1] ;resize array
$aKnownHandles[$iCounter] = $hNewHandle ;add new handle to list of known
$iCounter += 1 ;update counter
EndFunc

Auto it how to check if window appears and close

How do I check if a specific windoww appears in Autoit.
At the moment I am running with Auto it Adobe After Effect,
so far so good.
The problem is that a warning message pops up if the user does not have quick time installed.
Now I want to check if that window appears and is active and then close it.
So far I have this but did not work:
Local $iPID = Run("C:\Program Files\Adobe\Adobe After Effects CC 2015\Support Files\AfterFX.exe", "", #SW_SHOWMAXIMIZED)
WinWait("[CLASS:AfterEffects]", "", 1000)
Sleep(200000)
; if qicktime warning eror appears
If WinExists ("DroverLord - Window Class", "") Then
Send ("{ENTER}")
EndIf
Does this help?
Opt("WinDetectHiddenText", 1) ;0=don't detect, 1=do detect
Opt("WinSearchChildren", 1) ;0=no, 1=search children also
Opt("WinTextMatchMode", 1) ;1=complete, 2=quick
Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase
#include<Date.au3>
Local $iPID = Run("C:\Program Files\Adobe\Adobe After Effects CC 2015\Support Files\AfterFX.exe", "", #SW_SHOWMAXIMIZED)
If #error Then
ConsoleWrite('ERROR' & #CRLF)
Exit(0)
EndIf
Global $end = False
Do
; if qicktime warning eror appears
If WinExists("DroverLord - Window Class", "") Then
ConsoleWrite('!FOUND ' & _NowTime() & #CRLF)
Send("{ENTER}") ;close?
WinClose("DroverLord - Window Class", "") ; this
WinKill("DroverLord - Window Class", "") ; or this
$end = True
EndIf
Until $end
Here is an some example code of what you are trying to do:
Local $fDiff
Local $sAfterFXPath = "C:\Program Files\Adobe\Adobe After Effects CC 2015\Support Files\AfterFX.exe"
If FileExists($sAfterFXPath) Then
Local $iPID = Run($sAfterFXPath, "", #SW_SHOWMAXIMIZED)
;no need to call WinExists becuase you are waiting for it to exist and be active with WinActivate
Local $hTimer = TimerInit() ; Begin the timer and store the handle in a variable.
Do
$fDiff = TimerDiff($hTimer)
Until WinActive("Title you are looking for") Or $fDiff >= 30000 ;<<<will exit loop when the window is active or after 30 seconds
If WinActive("Title you are looking for") Then
;Closes the window now that it is active
WinClose("Title you are looking for")
Else
MsgBox(0, "", "The window was never active.")
EndIf
Else
MsgBox(0, "", "File path not found. Do something else...")
EndIf

How to handle optional windows in Autoit?

I am automating a software installation in Windows7 using AutoIt.
During the installation, in between if a error window appears. I want to click ENTER.
If the error window not appears then I should NOT do anything. Simply its should go to the next section.
I have tried "WinActive and WinWaitActive" But its waiting for the window to appear. If window not appears its not going to the next screen.
Any idea how to handle this situation?
Do a while loop:
$w = 0
While($w = 0)
If(WinActive("ERROR WINDOW"))Then
Send("{ENTER}")
$w = 1
ElseIf(ControlGetText("YOUR WINDOW", "", "[CLASS:Static; INSTANCE:2]") <> "SOME TEXT") Then
$w = 1
;and something else
EndIf
Sleep(1000)
WEnd
AdlibRegister() is the right choice. From the help file:
"... typically to check for unforeseen errors. For example, you could use adlib in a script which causes an error window to pop up unpredictably."
Each 100 ms (may be adjusted) the function is called to check the appearing of your error dialog:
Global $sErrorWindow = 'ErrorDialogName'
Global $iDelayHowOftenDoTheFunctionCall = 100
AdlibRegister('_isErrorWindowDisplayed', $iDelayHowOftenDoTheFunctionCall)
Func _isErrorWindowDisplayed()
If WinActive($sErrorWindow) <> 0 Then
WinActivate($sErrorWindow) ; just to be sure that the ENTER command is on the correct window/dialog
; either do
Send('{ENTER}')
; or
ControlClick('title', 'text', 'controlID')
EndIf
EndFunc
; do your software installation processing here
; ...
; ...
; don't forget to unregister the function at the end
AdlibUnRegister('_isErrorWindowDisplayed')

How to send keys to GUICtrl in remote desktop?

I want to send Windows + R to my GUICtrl using AutoIt. When I do Send("#r") it works on my computer but not in remote desktop. I want to do it in the RDP session.
Code :
$host = "" ;<<<<<<< enter here the host name or ip address
$hGUI = GUICreate("Terminal server", 900, 700, -1, -1, $WS_OVERLAPPEDWINDOW + $WS_CLIPSIBLINGS + $WS_CLIPCHILDREN)
$oRDP = ObjCreate("MsTscAx.MsTscAx.2")
$oRDP_Ctrl = GUICtrlCreateObj($oRDP, 0, 0, 900, 700)
GUICtrlSetResizing(-1, $GUI_DOCKALL)
GUICtrlSetStyle($oRDP_Ctrl, $WS_VISIBLE)
$oRDP.DesktopWidth = 900
$oRDP.DesktopHeight = 700
$oRDP.Fullscreen = False
$oRDP.ColorDepth = 16
$oRDP.AdvancedSettings3.SmartSizing = True
$oRDP.Server = $host
$oRDP.UserName = "" ;<<<<<<< enter here the user name
$oRDP.Domain = ""
$oRDP.AdvancedSettings2.ClearTextPassword = ""
$oRDP.ConnectingText = "Connecting to " & $host
$oRDP.DisconnectedText = "Disconnected from " & $host
$oRDP.StartConnected = True
$oRDP.Connect()
GUISetState(#SW_SHOW, $hGUI)
$oShel = ObjCreate("shell.application")
$oShel_Ctrl = GUICtrlCreateObj($oShel, 0, 0, 900, 700)
GUICtrlSetStyle($oShel_Ctrl, $WS_VISIBLE)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
$oRDP.Disconnect()
Exit
EndSwitch
You will want to use the special shortcut key for use when connected via RDP. You can find a list here: Remove Desktop Services Shortcut Keys
Try sending ALT+HOME:
Send("{ALT}{HOME}")
I found the solution. I use PsExec.exe, it's easier !
PS : Don't forget the session's ID after options. Without it, PsExec will works but only in processes and will not make a window

Save snapshots of minimized windows with Xlib

In short, I want to write a Gnome-Shell-style window switcher. So I need to fetch snapshots of all the windows. My current program looks like this:
char filename[101];
sprintf(filename, "%d.png", (int)win_list[i]);
GdkWindow *win_gdk = gdk_x11_window_foreign_new_for_display
(gdk_display_get_default(), win_list[i]);
gint _w, _h;
gdk_drawable_get_size(GDK_DRAWABLE(win_gdk), &_w, &_h);
XEvent _xevent;
_xevent.xexpose =
(XExposeEvent)
{
.type = Expose,
.send_event = True,
.display = xsu_vars.dpy,
.window = win_list[i],
.x = 0, .y = 0, .width = _w, .height = _h,
.count = 0
};
XSendEvent(xsu_vars.dpy, win_list[i], False, 0, &_xevent);
GdkPixbuf *_pb = gdk_pixbuf_get_from_drawable(
NULL, GDK_DRAWABLE(win_gdk), NULL, 0, 0, 0, 0, _w, _h);
if(_pb != NULL) {
cairo_surface_t *_surf_cairo = cairo_image_surface_create(
CAIRO_FORMAT_RGB24, _w, _h);
cairo_t *_cr = cairo_create(_surf_cairo);
gdk_cairo_set_source_pixbuf(_cr, _pb, 0, 0);
cairo_paint(_cr);
cairo_surface_write_to_png(_surf_cairo, filename);
printf("%s saved successfully!\n", filename);
} else {
printf("failed...\n");
}
The program works well well, but it will not generate correct images for those windows which are on a different desktop of minimized -- they would look like this:
Note that I send a expose event to all windows before generating pixbufs of them.
UPDATE:
It seems that xlib doesn't support that. So the only way may be creating cache manually.
This is possible with Composite extension - see "Preventing the backing pixmap from being freed when the window is hidden/destroyed" section in tutorial.
Yes, your update is correct. When a window is unmapped (or covered up), X just discards its contents; they don't exist anywhere in order to be snapshotted.
I believe libwnck contains code to do this and other parts of writing a switcher, btw. It's basically a library for writing things like window switchers.

Resources