Name of process for active window in Windows 8/10
Asked Answered
A

4

23

The following sample has reliably returned the name of the process that is associated with the active window, but does not work with the newer modern/universal apps because it returns the name of a helper process WWAHost.exe on Windows 8 and ApplicationFrameHost.exe on Windows 10 rather than the name of the app.

HWND active_window = GetForegroundWindow();
GetWindowThreadProcessId(active_window, &active_process_id);
HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, active_process_id);
GetProcessImageFileName(active_process, image_name, 512);

With Windows 10 the ApplicationFrameHost.exe is the process that creates the window handles and is what gets returned by GetWindowThreadProcessId(), is there another Win32 API that can be used to get the active process of universal app that is active?

Also tried using GetApplicationUserModelId() and GetPackageFullName() with no success as they return APPMODEL_ERROR_NO_APPLICATION and APPMODEL_ERROR_NO_PACKAGE respectively because the active_process handle is just the helper process and not the process of the active application.

Any other APIs to use to get the process name of a Modern/Universal application given the hwnd of the window, or otherwise figure out the process name of the universal app is active.

Thanks in advance!

Alejandrinaalejandro answered 2/9, 2015 at 18:2 Comment(2)
Have you tried QueryFullProcessImageName?Ibeam
Yes and it still returns a path to ApplicationFrameHost.exe, since the process_handle returned is the helper process that created the window.Alejandrinaalejandro
S
19

Be sure to use the Spy++ utility when you want to reverse-engineer something like this. Included with Visual Studio, you need the 64-bit version in Common7\Tools\spyxx_amd64.exe. Use Search > Find Window and drag the bullseye to a UWP app, like Weather.

You'll see the window you'll find with GetForegroundWindow(), it has at least 3 child windows:

  • ApplicationFrameTitleBarWindow
  • ApplicationFrameInputSinkWindow
  • Windows.Core.UI.CoreWindow, that's the host window for the UWP app and the one you are interested in. Right-click it and select Properties, Process tab, click the Process ID. That takes you to the real owner process you want to know.

So you just need to make an extra step from the code you already have, you just have to enumerate the child windows and look for one with a different owner process. Some C code, trying to make it as universal as possible without making too many assumptions and not enough error checking:

#include <stdio.h>
#include <Windows.h>

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;
}

int main()
{
    Sleep(2000);
    HWND active_window = GetForegroundWindow();
    windowinfo info = { 0 };
    GetWindowThreadProcessId(active_window, &info.ownerpid);
    info.childpid = info.ownerpid;
    EnumChildWindows(active_window, EnumChildWindowsCallback, (LPARAM)&info);
    HANDLE active_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info.childpid);
    WCHAR image_name[MAX_PATH] = { 0 };
    DWORD bufsize = MAX_PATH;
    QueryFullProcessImageName(active_process, 0, image_name, &bufsize);
    wprintf(L"%s\n", image_name);
    CloseHandle(active_process);
    return 0;
}

Output on the Weather program:

C:\Program Files\WindowsApps\Microsoft.BingWeather_4.5.168.0_x86__8wekyb3d8bbwe\ Microsoft.Msn.Weather.exe

Stilly answered 11/9, 2015 at 0:1 Comment(2)
A late observation - This works on Windowed mode, does not work with fullscreen UWP apps on Win10 (returns the ApplicationFrameHost.exe pid for both parent and child in the enumeration path).Abducent
This only works if UW application is already active and running. If you are doing real-time monitoring of apps using SetWinEventHook and try the above code then it would still return ApplicationFrameHost.exe but however it will work after we switch to another application and then switch back again.Tarragon
D
13

Here is a small console app application that continuously (so you can test it easily selecting different windows on your desktop) display information about the current foreground window process and store process, if any.

Apps can have a window hierarchy that can span multiple processes. What I do here is search the first sub window that has the 'Windows.UI.Core.CoreWindow' class name.

This app uses the UIAutomation API (and also smart pointers, smart BSTRs and smart VARIANTs provided by the #import directive). I suppose you can do the same with standard Windows SDK, but I find the UIAutomation used this way quite elegant.

#include "stdafx.h"
#import "UIAutomationCore.dll"
using namespace UIAutomationClient;

int main()
{
    // initialize COM, needed for UIA
    CoInitialize(NULL);

    // initialize main UIA class
    IUIAutomationPtr pUIA(__uuidof(CUIAutomation));

    do
    {
        // get the Automation element for the foreground window
        IUIAutomationElementPtr foregroundWindow = pUIA->ElementFromHandle(GetForegroundWindow());
        wprintf(L"pid:%i\n", foregroundWindow->CurrentProcessId);

        // prepare a [class name = 'Windows.UI.Core.CoreWindow'] condition
        _variant_t prop = L"Windows.UI.Core.CoreWindow";
        IUIAutomationConditionPtr condition = pUIA->CreatePropertyCondition(UIA_ClassNamePropertyId, prop);

        // get the first element (window hopefully) that satisfies this condition
        IUIAutomationElementPtr coreWindow = foregroundWindow->FindFirst(TreeScope::TreeScope_Children, condition);
        if (coreWindow)
        {
            // get the process id property for that window
            wprintf(L"store pid:%i\n", coreWindow->CurrentProcessId);
        }

        Sleep(1000);
    } while (TRUE);

cleanup:
    CoUninitialize();
    return 0;
}
Davidson answered 10/9, 2015 at 22:29 Comment(0)
E
2

Does taking snapshot of running processes and pulling the name out of it by comparing process id not work? Full reference here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms686837(v=vs.85).aspx

But you fix the snapshot with CreateToolhelp32Snapshot().

Or from WTSEnumerateProcesses() and surrounding API?

Pretty sure it worked in Win 8. Is it broken in 10?

Elsworth answered 10/9, 2015 at 23:41 Comment(3)
Comparing process ID to what? Modern (Windows Store-style) applications don't own top-level USER32 windows, so getting the right HWND to pass to GetWindowThreadProcessId() is non-trivial.Manualmanubrium
The snapshot doesn't require an hwnd. It can be used to get a list of all the processes in the system. Then you can filter out an entry out of that list based on what you do know about the process. Presumably you know something about it (like its parent process id).Elsworth
@Ben Voigt, I'll remove the bit about GetWindowThreadProcessId() since, as you mentioned, there is no hwnd.Elsworth
O
-2

Starting from Win10 Anniversary Update ApplicationFrameHost child window return anything but UWP application. It worked only in Tablet mode after relogon.

Odessa answered 10/5, 2017 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.