3

I am trying to get the Process ID of a program (PID) but for some odd reason, the PID changes. When the target program (Alarms & Clock) is visible, it gives me the wrong PID while having the program minimized gives me the right PID.

I am guessing that minimizing the target program suspends it's process, thus allowing it to be read. However, simply reading the PID should not be a restriction even when a process is running.

Does anyone have an idea on what am I doing wrong?

Currently Tried Methods:

  • Ran in Administrative Mode
  • Compiled for 64 bit
  • Compiled for 32 bit

ere is a working, concise piece of code that portrays the problem:

#include <iostream>
#include <Windows.h>
#include <string>

int main()
{
    std::string window_name = "Alarms & Clock"; //Feel free to replace this with another program
    HWND hwnd = FindWindowA(NULL, window_name.c_str());
    if (!hwnd)
    {
        std::cerr << "Error: Could not find window" << std::endl;
        return -1;
    }

    DWORD processID = 0;
    GetWindowThreadProcessId(hwnd, &processID);
    std::cout << "Process ID: " << processID << std::endl;
    std::cin.get();

    return 0;
}
Kevin Duarte
  • 424
  • 1
  • 4
  • 13
  • How do you know which is the "right" process id? – Some programmer dude Jun 02 '17 at 06:00
  • More importantly, what process does the "wrong" pid belong to? – Harry Johnston Jun 02 '17 at 06:02
  • Using `Task Manager`, I can see what process ID belongs to `Alarms & Clock`. Having `Alarms & Clock` opened gives me a non-existent process ID. – Kevin Duarte Jun 02 '17 at 06:02
  • "minimizing the target program suspends it's process" - you do not minimize program, you minimize window. That does not suspend the process at all. – iehrlich Jun 02 '17 at 06:02
  • @iehrlich Yes, minimizing a window suspends its process. Go on task manager and minimize a window and it will show it is suspended. Most applications should `suspend` – Kevin Duarte Jun 02 '17 at 06:03
  • @iehrlich, I think it does, for "modern" applications? – Harry Johnston Jun 02 '17 at 06:03
  • Oh sorry, I'm still stuck in Win7 :-/ – iehrlich Jun 02 '17 at 06:04
  • You're not checking whether the call to GetWindowThreadProcessId succeeds. – Harry Johnston Jun 02 '17 at 06:04
  • 2
    Process ID is fixed for life of process. – David Heffernan Jun 02 '17 at 06:04
  • @HarryJohnston I re-written the code and it succeeds every time – Kevin Duarte Jun 02 '17 at 06:06
  • @HarryJohnston you think failed call might still write something to lpdwProcessId? – iehrlich Jun 02 '17 at 06:06
  • @DavidHeffernan Exactly! That is why this is confusing me. – Kevin Duarte Jun 02 '17 at 06:06
  • Also, MSDN is surprisingly awful regarding this particular function :-/ – iehrlich Jun 02 '17 at 06:07
  • I have a vague feeling that the window of a "modern" application actually belongs to some sort of helper process. You might need to run Task Manager "as administrator" in order to see it? – Harry Johnston Jun 02 '17 at 06:13
  • @HarryJohnston I am running `Task Manager` in Administrator mode but the PID it gives is still non existent – Kevin Duarte Jun 02 '17 at 06:20
  • 1
    If you check e.g. [this `GetWindowThreadProcessId` reference](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633522(v=vs.85).aspx), in the minimum supported section, it say "desktop apps only". `Alarms & Clock` is *not* a desktop app. Maybe this could have something to do with your problem? – Some programmer dude Jun 02 '17 at 06:23
  • @Someprogrammerdude, no, that's the calling application, not the target application. – Harry Johnston Jun 02 '17 at 06:30
  • @HarryJohnston Yes that's what I think too, but it's still something that might need investigation I think. – Some programmer dude Jun 02 '17 at 06:37
  • 1
    @Someprogrammerdude Yep, I believe you are right. Desktop-specific apps seem to keep their PID even when the window is minimized, unlike tablet apps. Most window apps are starting to become tablet apps which may cause some problems. Can you post your answer on the answer section? I have not seen this documented anywhere so it may help someone out. – Kevin Duarte Jun 02 '17 at 06:37
  • 1
    window can belong to another process. say for app container apps. for example "Calculator" window - belong not to `Calculator.exe` but to `ApplicationFrameHost.exe` - are hwnd the same - not changed ? and it not belong to `ApplicationFrameHost.exe` ? – RbMm Jun 02 '17 at 06:40
  • @Kevin Duarte: I was able to regenerat the problem on my Win/10 with GCC 5.3. I tested it with the "Calculator" app. When its window is not minimized I get PID = 14440 which belongs to **ApplicationFrameHost.exe**, However PID = 1936 is shown correctly when its window is minimized. [_This SO post_](https://stackoverflow.com/questions/32360149/name-of-process-for-active-window-in-windows-8-10) may be useful for you. – Shadi Jun 02 '17 at 06:41
  • `Desktop-specific apps seem to keep their PID` - all windows processes keep it own pid - window assign pid to process when it start and never change it. as and noted DavidHeffernan – RbMm Jun 02 '17 at 06:42
  • @RbMm Yes they may belong to another process, but the PID given, when the window is open, gives a non-existent PID. – Kevin Duarte Jun 02 '17 at 06:42
  • @RbMm Yes, all programs keep their PID, I was referring to what `GetWindowThreadProcessId()` gives. – Kevin Duarte Jun 02 '17 at 06:43
  • @Shadi Does this give the PID when the `Calculator` app is running or suspended? The "real" PID seems to only be retrieved when the app is suspended (minimized) – Kevin Duarte Jun 02 '17 at 06:45
  • What could be remotely confusing. Different PID means different process. – David Heffernan Jun 02 '17 at 06:47
  • yes, I was right - you not check hwnd - you got **different** hwnd in 2 query. one *hwnd* belong to **ApplicationFrameHost.exe** when app is minimized and another hwnd belong to **time.exe** when app is shown – RbMm Jun 02 '17 at 06:51
  • @KevinDuarte - When calculator is minimized (suspended per task manager) it shows the PID of "Calculator.exe". When calculator's window is shown on the desktop it shows PID of **ApplicationFrameHost.exe** – Shadi Jun 02 '17 at 06:55
  • @RbMm Yep you are right, strangely enough, `Task Manager` seemed to not show ApplicationFrameHost.exe (PID 1500 now) – Kevin Duarte Jun 02 '17 at 06:55
  • @Shadi I am going to try your linked example to see if solves the problem – Kevin Duarte Jun 02 '17 at 06:57
  • are you set option - show process from all users ? for me taskmgr show ApplicationFrameHost.exe as well – RbMm Jun 02 '17 at 06:58
  • @Shadi Yes the code works! It seems to get `ApplicationFrameHost.exe` and ask for the every child PID it holds. If the child PID matches `Calculator.exe`, it will return that child PID. Lengthy but brilliant! Can you post your answer on the "Answer section"? – Kevin Duarte Jun 02 '17 at 07:14

2 Answers2

3

I was able to regenerate the problem on my Win/10 with GCC 5.3. I tested it with the "Calculator" app. When the app's window was not minimized I got PID = 14440 which belonged to ApplicationFrameHost.exe, However, I got PID = 1936 correctly when calc's window is minimized.

This is due to the fact that "Calculator" is a tablet app and not a desktop app. Desktop apps give the right PID no matter if the window is minimized or not.

I think this SO post would be useful for you.

It seems that ApplicationFrameHost.exe is an app container that handle many child apps. An extra code is needed to retrieve the exact child app pid you are looking for.

base on that page, I wrote this piece of code and it worked for me, however, you might need to refine it.

typedef struct {
    DWORD ownerpid;
    DWORD childpid;
} windowinfo;

BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lp) {
    windowinfo* info = (windowinfo*)lp;
    DWORD pid = 0;
    GetWindowThreadProcessId(hWnd, &pid);
    if (pid != info->ownerpid) info->childpid = pid;
    return TRUE;
}

void Show_PID()
{
    Sleep(1000);
    std::string window_name = "Calculator"; 
    HWND hwnd = FindWindowA(NULL, window_name.c_str());
    windowinfo info = { 0 };
    GetWindowThreadProcessId(hwnd, &info.ownerpid);
    info.childpid = info.ownerpid;
    EnumChildWindows(hwnd, EnumChildWindowsCallback, (LPARAM)&info);
    std::cout << "Process ID: " << info.childpid << std::endl;
}

int main()
{
    for (int i = 0; i < 9; ++i)
    {
        Show_PID();
    }

    return 0;
}
Kevin Duarte
  • 424
  • 1
  • 4
  • 13
Shadi
  • 1,701
  • 2
  • 14
  • 27
1

you need check the returned hwnd value - you can view that when appcontainer app is suspended(you minimize it window) and when it active - you got different hwnd. for all app containers in active state - it main frame window belong not to it process but to ApplicationFrameHost.exe and have ApplicationFrameWindow class. but when it minimized - need click exactly on minimize button - process is suspended and.. however let run this code

if (HWND hwnd = FindWindowW(0, L"Alarms & Clock"))
{
    ULONG pid, tid = GetWindowThreadProcessId(hwnd, &pid);

    DbgPrint("%x %x.%x", hwnd, pid, tid);

    WCHAR sz[MAX_PATH];
    if (GetClassName(hwnd, sz, RTL_NUMBER_OF(sz)))
    {
        DbgPrint(" [%S]", sz);
    }

    if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid))
    {
        PROCESS_EXTENDED_BASIC_INFORMATION pebi;
        if (0 <= ZwQueryInformationProcess(hProcess, ProcessBasicInformation, &pebi, sizeof(pebi), 0))
        {
            DbgPrint(" Suspended=%x, flags(%x)", pebi.IsFrozen, pebi.Flags);
        }
        ULONG len = RTL_NUMBER_OF(sz);
        if (QueryFullProcessImageNameW(hProcess, 0, sz, &len))
        {
            DbgPrint(" %S", sz);
        }

        CloseHandle(hProcess);
    }

    DbgPrint("\n");
}

and I got next output for 2 states:

1902e6 510.155c [Windows.UI.Core.CoreWindow] Suspended=1, flags(58) C:\Program Files\WindowsApps\Microsoft.WindowsAlarms_10.1605.1742.0_x64__8wekyb3d8bbwe\Time.exe
740414 574.934 [ApplicationFrameWindow] Suspended=0, flags(8) C:\Windows\System32\ApplicationFrameHost.exe
RbMm
  • 31,280
  • 3
  • 35
  • 56