Jump to content

Get PID of calc.exe in Windows 10


TimRude
 Share

Recommended Posts

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.

image.png.6073c854d48af9a6421aafb7853339ec.png 

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.

image.png.668d6311ee083824077a6cd15cf8df0d.png

The version number of the Windows Calculator app (if it matters) is:

image.png.66dacada15963edbcce01756863a6664.png

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 by TimRude
Link to comment
Share on other sites

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 by ioa747

I know that I know nothing

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

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 by jugador
Link to comment
Share on other sites

@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.

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

#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 by TimRude
Link to comment
Share on other sites

@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 by jugador
Link to comment
Share on other sites

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 by TimRude
Link to comment
Share on other sites

Better version - removes the PID stuff altogether and just watches the windows.

#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?

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...