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
Related
I used simplespy.au3 to target a slider control in the Windows settings window using _UIA_action(). Asking the user to input a value I send left and right keys for the slider to move.
But I don't know how to get the current value of my slider. I tried GUICtrlRead() but it doesn't work. How do I get the current value of a slider control?
My code:
#RequireAdmin
#include <IE.au3>
#include <MsgBoxConstants.au3>
#include <GuiSlider.au3>
#include <GUIConstants.au3>
#include "UISpy\UIAWrappers\UIAWrappers.au3"
Slider()
Func Slider()
;User Input
$Default = ""
$input = ""
While 1
$input = InputBox("Brightness", "Set Brightness to:", "", " M", -1, -1)
If #error Then ExitLoop
If $input < 0 Or $input > 100 Then
MsgBox(48, "Error!", "Minimum value for brightness is 0 and the Maximum brightness is 100")
$Default = $input
ContinueLoop
ElseIf StringLen($input) > 0 Or $input < 100 Then
ExitLoop
EndIf
If #error = 1 Then
Exit
EndIf
WEnd
;Start automation
Local $iTimeout = 1
Local $hWnd = WinWait("[Class:Shell_TrayWnd]", "", "[CLASS:Button; INSTANCE:1]")
ControlClick($hWnd, "", "[CLASS:Button; INSTANCE:1]") ;open the start menu
Send("Display Settings", 10) ;Type the Display Settings in the start menu
Sleep(1000)
Send("{ENTER}")
AutoItSetOption("MustDeclareVars", 1)
Local $oP2 = _UIA_getObjectByFindAll($UIA_oDesktop, "Title:=Settings;controltype:=UIA_WindowControlTypeId;class:=ApplicationFrameWindow", $treescope_children)
_UIA_Action($oP2, "setfocus")
Local $oP1 = _UIA_getObjectByFindAll($oP2, "Title:=Settings;controltype:=UIA_WindowControlTypeId;class:=Windows.UI.Core.CoreWindow", $treescope_children)
_UIA_Action($oP1, "setfocus")
Local $oP0 = _UIA_getObjectByFindAll($oP1, "Title:=;controltype:=UIA_PaneControlTypeId;class:=ScrollViewer", $treescope_children)
;First find the object in the parent before you can do something
; $oUIElement=_UIA_getObjectByFindAll("Changebrightness.mainwindow", "title:=Change brightness;ControlType:=UIA_SliderControlTypeId", $treescope_subtree)
Local $oUIElement = _UIA_getObjectByFindAll($oP0, "title:=Change brightness;ControlType:=UIA_SliderControlTypeId", $treescope_subtree)
_UIA_action($oUIElement, "setfocus")
Send("{LEFT $input}"`enter code here`)
Sleep(1000)
Local $value = GUICtrlRead($oUIElement)
MsgBox($MB_SYSTEMMODAL, "", "Brightness is at: " & $value, $iTimeout)
Local $setValue = GUICtrlSetData($oUIElement, 50)
;UI for verification
MsgBox(0, "Change Brightness", "Brightness Changed.", $iTimeout)
Sleep(1000)
WinClose("Settings") ;Close the active window
EndFunc ;==>Slider
Don't manipulate the slider. Use the WinAPI instead: _WinAPI_SetDeviceGammaRamp.
I get a list of open windows and check if it contains a certain title. It is working but takes more than 10 seconds. Why does it take so long, what is wrong with my code?
Looks like WinList() doesn't list only visible windows.
$title = 0
$begintime = TimerInit()
MsgBox($MB_OK, "Timer", "Timer inicialized")
While $title = 0
$aList = WinList()
For $x = 1 To $aList[0][0]
;Check if a window with this title exists.
if $aList[$x][0] = "WindowTitle" Then
If $lastruntitle = "WindowTitle" Then
$title = 1
ExitLoop(2)
Else
SendMail4()
$lastruntitle = "WindowTitle"
$title = 1
ExitLoop(2)
EndIf
EndIf
Next
WEnd
Simple solution for your task is:
#include <Array.au3>
While 1
$aList = WinList()
_ArraySearch($aList, "WindowTitle", 0, 0, 0, 0, 1, 0)
If Not #error Then
MsgBox(0,"","Window found!")
Exit
EndIf
Sleep(100)
WEnd
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
I was trying to create an AutoIt script to create a new folder and then highlight it for renaming like if we right click and create a new folder.
Here is my script. What I wanted to achieve is create the new folder, highlight it, then press F2.
#include <WinAPI.au3>
HotKeySet("#y", "NewFolder")
While 1
Sleep(200)
WEnd
Func NewFolder()
Local $hWnd = WinGetHandle("[ACTIVE]")
Local $class = _WinAPI_GetClassName($hWnd)
If StringCompare($class, "CabinetWClass") = 0 Then
Local $sSelected_Path = _GetWindowsExplorerPath($hWnd) & "\NewFolder" & $count
Local $iFileExists = FileExists($sSelected_Path)
If $iFileExists Then
$count += 1
Else
Local $success = DirCreate($sSelected_Path)
Sleep(500)
If $success = 1 Then
Local $Finditem = ControlListView($hWnd, "", "[CLASS:SysListView32; INSTANCE:1]", "Finditem", "NewFolder")
MsgBox(0, "", $Finditem)
Local $Select = ControlListView($hWnd, "", "[CLASS:SysListView32; INSTANCE:1]", "Select", $Finditem)
$count += 1
EndIf
EndIf
EndIf
EndFunc
Func _GetWindowsExplorerPath($hWnd)
Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className
Local $bPIDL = False
Local Const $CWM_GETPATH = 0x400 + 12;
; Check the classname of the window first
$className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)
If #error Then Return SetError(2, 0, "")
If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")
; Retrieve the process ID for our process
$pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")
If #error Then Return SetError(2, 0, "")
; Send the CWM_GETPATH message to the window
$hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0)
If #error Then Return SetError(2, 0, "")
If $hMem[0] = 0 Then Return SetError(1, 0, "")
; Lock the shared memory
$pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])
If #error Then Return SetError(2, 0, "")
If $pv[0] Then
$pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL
If #error Then Return SetError(2, 0, "")
$bPIDL = True
DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory
EndIf
DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory
If $bPIDL Then
; Retrieve the path from the PIDL
$ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))
If (#error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value
DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned
Return SetError(0, 0, $return) ; Success
EndIf
Return SetError(2, 0, "") ; Failed a WinAPI call
EndFunc
This works for me in Win7 - should work in xp as long as address bar is turned on. MUCH simpler than using the DLL calls. I left you a little bit of work to do :)
HotKeySet("#y","_NewFolder")
HotKeySet("#n","_EXIT")
While 1
Sleep(250)
WEnd
FUNC _NewFolder() ; make all vars local
$TEXT = WinGetText("[active]")
; handle error here
$SPLIT = StringSplit($TEXT,#CR & #LF & #CRLF) ;split on new lines (idk which one of the three it uses)
IF IsArray($SPLIT) Then
; trigger = true
FOR $I = 1 to $SPLIT[0]
IF StringInStr($SPLIT[$i],"Address: ") Then
; trigger = false
$STRING = StringReplace($SPLIT[$i],"Address: ","")
$INPUT = InputBox("New Folder","Name your new folder")
; add some enforcement to input box, i like do until loops
$PATH = $STRING & "\" & $INPUT
$CREATE = DirCreate($PATH)
; handle error here
Return SetError(0,0,$PATH)
EndIf
Next
; if trigger then error
Else
Return SetError(1,0,0) ;if split is not an array - could add some more here in case address is the only line returned
EndIf
EndFunc
Func _Exit()
Exit
EndFunc
"create a new folder and then highlight it for renaming like its supposed to"
As per Documentation - Function Reference - DirCreate() :
Creates a directory/folder.
Example:
Global Const $g_sPathFolder = #DesktopDir & '\'
Global Const $g_sPromptText = 'Enter folder name :'
Global Const $g_sPromptExmp = 'NewFolder'
Global $g_sNameFolder = InputBox(#ScriptName, $g_sPromptText, $g_sPromptExmp)
DirCreate($g_sPathFolder & $g_sNameFolder)
ShellExecute($g_sPathFolder & $g_sNameFolder)
I use rsync to synchronize files to Windows clients in a server agnostic way. What methods are available to send the progress of rsync to the parent process for display in a gui progress bar?
I imagine two or three choices exist. (1) Watch STDOUT (2) Watch rsync.exe log file, similar to unix tail (3) Watch rsync console output in memory.
Which one is best/preferred?
For this type of tasks, I use my own AutoIt script (freeware, Windows only). The script redirects the standard output into a graphical window, displaying it with the ability to scroll back, etc (very useful in long processes like XCOPYs / PKZIPs to check if any error did happen).
I use AutoIt because it's free, very easy to use, and can compile quickly into an .EXE. I think it's an excellent alternative to a complete programming language for this type of tasks. The downside is that it's for Windows only.
$sCmd = "DIR E:\*.AU3 /S" ; Test command
$nAutoTimeout = 10 ; Time in seconds to close window after finish
$nDeskPct = 60 ; % of desktop size (if percent)
; $nHeight = 480 ; height/width of the main window (if fixed)
; $nWidth = 480
$sTitRun = "Executing process. Wait...." ;
$sTitDone = "Process done" ;
$sSound = #WindowsDir & "\Media\Ding.wav" ; End Sound
$sButRun = "Cancel" ; Caption of "Exec" button
$sButDone = "Close" ; Caption of "Close" button
#include <GUIConstants.au3>
#include <Constants.au3>
#Include <GuiList.au3>
Opt("GUIOnEventMode", 1)
if $nDeskPct > 0 Then
$nHeight = #DesktopHeight * ($nDeskPct / 100)
$nWidth = #DesktopWidth * ($nDeskPct / 100)
EndIf
If $CmdLine[0] > 0 Then
$sCmd = ""
For $nCmd = 1 To $CmdLine[0]
$sCmd = $sCmd & " " & $CmdLine[$nCmd]
Next
; MsgBox (1,"",$sCmd)
EndIf
; AutoItSetOption("GUIDataSeparatorChar", Chr(13)+Chr(10))
$nForm = GUICreate($sTitRun, $nWidth, $nHeight)
GUISetOnEvent($GUI_EVENT_CLOSE, "CloseForm")
$nList = GUICtrlCreateList ("", 10, 10, $nWidth - 20, $nHeight - 50, $WS_BORDER + $WS_VSCROLL)
GUICtrlSetFont (-1, 9, 0, 0, "Courier New")
$nClose = GUICtrlCreateButton ($sButRun, $nWidth - 100, $nHeight - 40, 80, 30)
GUICtrlSetOnEvent (-1, "CloseForm")
GUISetState(#SW_SHOW) ;, $nForm)
$nPID = Run(#ComSpec & " /C " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD)
; $nPID = Run(#ComSpec & " /C _RunErrl.bat " & $sCmd, ".", #SW_HIDE, $STDOUT_CHILD) ; # Con ésto devuelve el errorlevel en _ERRL.TMP
While 1
$sLine = StdoutRead($nPID)
If #error Then ExitLoop
If StringLen ($sLine) > 0 then
$sLine = StringReplace ($sLine, Chr(13), "|")
$sLine = StringReplace ($sLine, Chr(10), "")
if StringLeft($sLine, 1)="|" Then
$sLine = " " & $sLine
endif
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
EndIf
Wend
$sLine = " ||"
GUICtrlSetData ($nList, $sLine)
_GUICtrlListSelectIndex ($nList, _GUICtrlListCount ($nList) - 1)
GUICtrlSetData ($nClose, $sButDone)
WinSetTitle ($sTitRun, "", $sTitDone)
If $sSound <> "" Then
SoundPlay ($sSound)
EndIf
$rInfo = DllStructCreate("uint;dword") ; # LASTINPUTINFO
DllStructSetData($rInfo, 1, DllStructGetSize($rInfo));
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
$nLastInput = DllStructGetData($rInfo, 2)
$nTime = TimerInit()
While 1
If $nAutoTimeout > 0 Then
DllCall("user32.dll", "int", "GetLastInputInfo", "ptr", DllStructGetPtr($rInfo))
If DllStructGetData($rInfo, 2) <> $nLastInput Then
; Tocó una tecla
$nAutoTimeout = 0
EndIf
EndIf
If $nAutoTimeout > 0 And TimerDiff ($nTime) > $nAutoTimeOut * 1000 Then
ExitLoop
EndIf
Sleep (100)
Wend
Func CloseForm()
Exit
EndFunc
.NET has a pretty straight forward way to read and watch STDOUT.
I guess this would be the cleanest way, since it is not dependent on any external files, just the path to rsync. I would not be too surprised if there is a wrapper library out there either. If not, write and open source it :)
I've built my own simple object for this, I get a lot of reuse out of it, I can wrap it with a cmdline, web page, webservice, write output to a file, etc---
The commented items contain some rsync examples--
what I'd like to do sometime is embed rsync (and cygwin) into a resource & make a single .net executable out of it--
Here you go:
Imports System.IO
Namespace cds
Public Class proc
Public _cmdString As String
Public _workingDir As String
Public _arg As String
Public Function basic() As String
Dim sOut As String = ""
Try
'Set start information.
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 192.168.42.6::cdsERP /cygdrive/s/cdsERP_rsync/gwy")
'Dim startinfo As New ProcessStartInfo("C:\Program Files\cwRsync\bin\rsync", "-avzrbP 10.1.1.6::user /cygdrive/s/cdsERP_rsync/gws/user")
'Dim startinfo As New ProcessStartInfo("C:\windows\system32\cscript", "//NoLogo c:\windows\system32\prnmngr.vbs -l")
Dim si As New ProcessStartInfo(_cmdString, _arg)
si.UseShellExecute = False
si.CreateNoWindow = True
si.RedirectStandardOutput = True
si.RedirectStandardError = True
si.WorkingDirectory = _workingDir
' Make the process and set its start information.
Dim p As New Process()
p.StartInfo = si
' Start the process.
p.Start()
' Attach to stdout and stderr.
Dim stdout As StreamReader = p.StandardOutput()
Dim stderr As StreamReader = p.StandardError()
sOut = stdout.ReadToEnd() & ControlChars.NewLine & stderr.ReadToEnd()
'Dim writer As New StreamWriter("out.txt", FileMode.CreateNew)
'writer.Write(sOut)
'writer.Close()
stdout.Close()
stderr.Close()
p.Close()
Catch ex As Exception
sOut = ex.Message
End Try
Return sOut
End Function
End Class
End Namespace
Check out DeltaCopy. It is a Windows GUI for rsync.
Check NAsBackup Its open source software that give Windows user Rsync GUI using Watch STDOUT.