TimRude Posted January 19, 2023 Posted January 19, 2023 (edited) Trying to open the Windows Calculator and get its PID using this very basic script. Local $iCalcPID = Run("calc.exe") ConsoleWrite("PID = " & $iCalcPID & @CRLF) Exit After running this simple script, the console window shows: >"C:\Program Files (x86)\AutoIt3\SciTE\..\AutoIt3.exe" "C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.au3" /run /prod /ErrorStdOut /in "C:\AutoIt-Projects\Test\CalcPID.au3" /UserParams +>22:33:15 Starting AutoIt3Wrapper (22.611.2153.14) from:SciTE.exe (4.4.6.0) Keyboard:00000409 OS:WIN_10/2009 CPU:X64 OS:X64 Environment(Language:0409) CodePage:0 utf8.auto.check:4 +> SciTEDir => C:\Program Files (x86)\AutoIt3\SciTE UserDir => C:\Users\TRR\AppData\Local\AutoIt v3\SciTE\AutoIt3Wrapper SCITE_USERHOME => C:\Users\TRR\AppData\Local\AutoIt v3\SciTE >Running AU3Check (3.3.16.1) from:C:\Program Files (x86)\AutoIt3 input:C:\AutoIt-Projects\Test\CalcPID.au3 +>22:33:16 AU3Check ended. rc:0 >Running:(3.3.16.1):C:\Program Files (x86)\AutoIt3\autoit3.exe "C:\AutoIt-Projects\Test\CalcPID.au3" +>Setting Hotkeys...--> Press Ctrl+Alt+Break to Restart. --> Press Ctrl+BREAK to Stop. PID = 13104 +>22:33:16 AutoIt3 ended. rc:0 +>22:33:16 AutoIt3Wrapper Finished. >Exit code: 0 Time: 1.027 So the PID returned by the Run function is 13104. After running the script, the Calculator app has started successfully. However, in Task Manager, 13104 is not the PID shown for Calculator. In fact there is no 13104 PID at all in the list shown by Task Manager. The version number of the Windows Calculator app (if it matters) is: What gives? (And to be clear, I'm not just using calc.exe as an example app. I really do want to open an instance of calc.exe specifically and get its PID.) Edited January 19, 2023 by TimRude
abberration Posted January 19, 2023 Posted January 19, 2023 I am not familiar with Runtime Process, but I suspect it may have something to do with your issue. How about starting calc, waiting for the window to appear, then use WinGetProcess to retrieve the PID? Easy MP3 | Software Installer | Password Manager
ioa747 Posted January 19, 2023 Posted January 19, 2023 (edited) Me too When i run: #include <Process.au3> Run("calc.exe") ;~ Local $hCalc = WinWait("[TITLE:Calculator; CLASS:ApplicationFrameWindow]", "") Local $hCalc = WinWait("Calculator") Local $iPid = WinGetProcess($hCalc) Local $sName = _ProcessGetName($iPid) ConsoleWrite("$hCalc = " & $hCalc & @CRLF) ConsoleWrite("$iPid = " & $iPid & @CRLF) ConsoleWrite("$sName = " & $sName & @CRLF) Exit ;~ Console out: ;~ $hCalc = 0x001A002C ;~ $iPid = 8924 ;~ $sName = ApplicationFrameHost.exe $iPid is from ApplicationFrameHost.exe Edited January 19, 2023 by ioa747 I know that I know nothing
bdr529 Posted January 19, 2023 Posted January 19, 2023 I apologise in advance for my poor/bad English run name = calc.exe but taskmanager name is calculatorapp.exe WinWait("Calculator") = only if English language test solution To community goes all my regards and thanks
Nine Posted January 19, 2023 Posted January 19, 2023 Solved that problem sometime ago : “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
ioa747 Posted January 19, 2023 Posted January 19, 2023 (edited) I owe you a beer for this @Nine You're amazing! <image> well done! I would look for other calculator. Thank you very much !! Edited April 3, 2023 by ioa747 del image I know that I know nothing
TimRude Posted January 20, 2023 Author Posted January 20, 2023 Hmm. Very interesting. My original intention was to make an app that registers a hotkey to open an instance of the Calculator app. My app would remember the PID returned by running the Calculator app and then if the hotkey was pressed again and that PID was still in existence, it would just make that existing instance of the Calculator window active instead of opening another Calculator window or switching to a different instance of Calculator window. If that PID wasn't still in existence then it would open a new Calculator window and remember its PID. This was based on my mistaken assumption that each instance of the Calculator window would run in a separate process and have its own PID. I see now (thanks to @Nine's nifty code) that my assumption was incorrect. All instances of the Calculator app evidently operate in the same process under the same PID, even if you have a dozen Calculator windows open at the same time. So I'll have to come up with another way of identifying the handle of the specific Calculator window I just created using the Run command (differentiating it from any pre-existing Calculator windows) to be able to switch back to that specific window again later, without relying on the PID returned by the Run command.
AutoBert Posted January 20, 2023 Posted January 20, 2023 Maybe this: #include <Array.au3> $aOldcalcHWND = WinList("Rechner") ;change rechner to wintitle in your language _ArrayDisplay($aOldcalcHWND) Run("calc.exe") Sleep(2000) $aNewcalcHWND = WinList("Rechner") ;_ArrayDisplay($aNewcalcHWND) for $i = UBound($aNewcalcHWND)-1 To 1 Step -1 For $j = 1 To UBound($aOldcalcHWND)-1 If $aNewcalcHWND[$i][1] = $aOldcalcHWND[$j][1] Then _ArrayDelete($aNewcalcHWND, $i) ExitLoop EndIf Next Next ;_ArrayDisplay($aNewcalcHWND) $calcHWND = $aNewcalcHWND[1][1] ConsoleWrite($calcHWND & @CRLF) will give you a idea
ioa747 Posted January 20, 2023 Posted January 20, 2023 @AutoBert it doesn't work for me, and I changed the name to a calculator, from Rechner it has to do with ApplicationFrameHost.exe the solution was given by @Nine thanks any way I know that I know nothing
TimRude Posted January 20, 2023 Author Posted January 20, 2023 @AutoBert I did something similar to that last night (reading the list of windows before opening a new instance of Calculator) and comparing it to the list of windows afterwards, but also incorporating Nine's method of getting past the ApplicationFrameHost.exe issue. Funny thing is, when you load a new instance of the Calculator app it actually creates 2 new windows in the list (and even though you only actually see one new one on the screen they're both 'stated' as being visible). After a little while, the handle for one of the 2 new windows goes away. It got late while I was playing with it so I went to bed. I'll have to do some more tinkering this evening to see how long I have to wait for the second phantom window to drop off the list.
jugador Posted January 20, 2023 Posted January 20, 2023 (edited) 14 hours ago, TimRude said: My original intention was to make an app that registers a hotkey to open an instance of the Calculator app. My app would remember the PID returned by running the Calculator app and then if the hotkey was pressed again and that PID was still in existence, it would just make that existing instance of the Calculator window active instead of opening another Calculator window or switching to a different instance of Calculator window. If that PID wasn't still in existence then it would open a new Calculator window and remember its PID. HotKeySet("a", "__StartCalc") HotKeySet("{ESC}", "__Terminate") While 1 Sleep(100) WEnd Func __StartCalc() Local Static $Pid_Static = -1 If Not ProcessExists($Pid_Static) Then $Pid_Static = Run("calc.exe") Else WinActivate(_WinGetByPID($Pid_Static)) EndIf EndFunc Func __Terminate() Exit EndFunc Func _WinGetByPID($iPID) ; https://www.autoitscript.com/forum/topic/136271-solved-wingethandle-from-wingetprocess/?do=findComment&comment=952135 Local $aWinList = WinList() For $A = 1 To $aWinList[0][0] If WinGetProcess($aWinList[$A][1]) = $iPID And BitAND(WinGetState($aWinList[$A][1]), 2) Then Return $aWinList[$A][1] EndIf Next EndFunc Edited January 20, 2023 by jugador
TimRude Posted January 20, 2023 Author Posted January 20, 2023 @jugador That works with something like notepad.exe, but doesn't work with an ApplicationFrameHost app like calc.exe. The post of mine that you quoted mentions that trying to use the PID from Run won't work with the Calculator app. Also, the PID returned by the Run("calc.exe") command doesn't even correspond to the Calculator app. The process that goes with that PID is only there for a second or less and then it terminates, leaving the PID that was saved pointing to a now non-existent process.
jugador Posted January 20, 2023 Posted January 20, 2023 Tested on win7 and it worked but after reading 15 hours ago, TimRude said: All instances of the Calculator app evidently operate in the same process under the same PID, even if you have a dozen Calculator windows open at the same time. then it will not work on win10.
TimRude Posted January 21, 2023 Author Posted January 21, 2023 (edited) I believe this gets the job done. The first time the hotkey (C) is pressed, it opens a new Calculator window (even if there is already one or more existing Calculator windows open). and remembers its handle. Then as long as that specific Calculator window still exists, pressing the hotkey activates it. If that Calculator window is closed, pressing the hotkey opens a new one and remembers the new handle. Since it turns out that the PID of the actual calculator process isn't helpful in this case, just working with the window titles and handles is sufficient. expandcollapse popup#include <Array.au3> Opt("MustDeclareVars", 1) HotKeySet("c", "ShowCalc") ; press C to show the calculator window HotKeySet("{ESC}", "Stop") ; press ESC to exit this app Do Sleep(100) Until 0 Func ShowCalc() Static $hCalcWin = 0 If WinExists($hCalcWin) Then WinActivate($hCalcWin) ConsoleWrite("-> Activate Existing Calculator Window Handle " & $hCalcWin & @CRLF) Else $hCalcWin = RunCalcAndGetHandle() ConsoleWrite("-> New Calculator Window Handle = " & $hCalcWin & @CRLF) EndIf EndFunc Func Stop() Exit EndFunc Func RunCalcAndGetHandle() Local $aBefore = WinList("Calculator") Local $iPID = Run("calc.exe") ; PID returned is a temporary process that chains the Calculator App ProcessWait($iPID, 2) ; wait for the temporary process to exist ProcessWaitClose($iPID, 2) ; then wait for the temporary process to close - at this point Calculator App should be loaded Sleep(500) ; when new Calculator instance is created, a temporary phantom window is generated ; allow time for this phantom window to go away before getting the window list again Local $aAfter = WinList("Calculator") For $i = 1 To $aAfter[0][0] ; it seems that the newly created Calculator window is always the first one in the list, ; but check to be sure we find the window that wasn't already there before If _ArraySearch($aBefore, $aAfter[$i][1], 0, 0, 0, 0, 1, 1) = -1 Then Return $aAfter[$i][1] ; found it Next Return 0 ; if we get here, there was no new window found EndFunc Edited January 21, 2023 by TimRude
jugador Posted January 21, 2023 Posted January 21, 2023 (edited) @TimRude can you check if this work on win10 HotKeySet("c", "__StartCalc") HotKeySet("{ESC}", "__Terminate") While 1 Sleep(100) WEnd Func __StartCalc() Local Static $Pid_Static = -1 If Not WinActivate($Pid_Static) Then Run("calc.exe") #cs Sleep(250) $Pid_Static = WinGetHandle("[ACTIVE]") #ce ;#cs Do Sleep(250) $Pid_Static = WinGetHandle("[ACTIVE]") Until WinGetTitle($Pid_Static) = 'Calculator' ;#ce Else WinActivate($Pid_Static) EndIf EndFunc Func __Terminate() Exit EndFunc Edited January 21, 2023 by jugador
TimRude Posted January 21, 2023 Author Posted January 21, 2023 (edited) 5 hours ago, jugador said: can you check if this work on win10 Yep, that works too, but with one exception. If you happen to have a Calculator window already open and it's the active window when you press the hotkey, it opens a new Calculator window but it remembers the handle of the first Calculator window you were already sitting on. So pressing the hotkey again activates that first window instead of the new Calculator window that was opened. Edited January 21, 2023 by TimRude
TimRude Posted January 22, 2023 Author Posted January 22, 2023 Better version - removes the PID stuff altogether and just watches the windows. expandcollapse popup#include <Array.au3> #include <WinAPISysWin.au3> Opt("MustDeclareVars", 1) HotKeySet("c", "ShowCalc") ; Press C to show the calculator window HotKeySet("{ESC}", "Stop") ; Press ESC to exit this app Do Sleep(100) Until 0 Func ShowCalc() Static $hCalcWin = 0 If WinExists($hCalcWin) Then WinActivate($hCalcWin) ConsoleWrite("-> Activate Existing Calculator Window Handle " & $hCalcWin & @CRLF) Else $hCalcWin = RunCalcAndGetHandle() ConsoleWrite("-> New Calculator Window Handle = " & $hCalcWin & @CRLF) EndIf EndFunc Func Stop() Exit EndFunc Func RunCalcAndGetHandle() If WinGetTitle("[ACTIVE]") = "Calculator" Then WinActivate(_WinAPI_GetDesktopWindow()) ; avoid detecting the wrong Calculator window with WinWaitActive Local $aBefore = WinList("Calculator") Run("calc.exe") WinWaitActive("Calculator", "", 5) Local $aAfter = WinList("Calculator") For $i = 1 To $aAfter[0][0] ; it seems that the newly created Calculator window is always the first one in the list, ; but check to be sure we find the window that wasn't already there before If _ArraySearch($aBefore, $aAfter[$i][1], 0, 0, 0, 0, 1, 1) = -1 Then Return $aAfter[$i][1] ; found it Next Return 0 ; if we get here, there was no new window found EndFunc @jugador Can you check if this version works properly for Win 7?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now