Windows 8/10中用于活动窗口的进程名称

23

以下示例可可靠地返回与活动窗口关联的进程名称,但无法与较新的现代/通用应用程序一起使用,因为它返回Windows 8上的助手进程WWAHost.exe和Windows 10上的ApplicationFrameHost.exe的名称,而不是应用程序的名称。

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

在Windows 10中,ApplicationFrameHost.exe是创建窗口句柄并由GetWindowThreadProcessId()返回的进程,是否有其他Win32 API可用于获取活动的通用应用程序的进程?

还尝试了使用GetApplicationUserModelId()和GetPackageFullName(),但均未成功,因为active_process句柄只是辅助进程而不是活动应用程序的进程。

是否有其他API可用于根据窗口的hwnd获取现代/通用应用程序的进程名称,或以其他方式找出通用应用程序的进程名称处于活动状态。

提前感谢!


你尝试过使用 QueryFullProcessImageName 吗? - theB
是的,它仍然返回ApplicationFrameHost.exe的路径,因为返回的process_handle是创建窗口的辅助进程。 - Tim Beaudet
4个回答

19

要反向工程类似这样的东西,请务必使用Spy++实用程序。它是Visual Studio附带的,您需要64位版本的Common7\Tools\spyxx_amd64.exe。使用“搜索”>“查找窗口”,并将准星拖到UWP应用程序(如天气)上。

您将看到使用GetForegroundWindow()找到的窗口,它至少有3个子窗口:

  • ApplicationFrameTitleBarWindow
  • ApplicationFrameInputSinkWindow
  • Windows.Core.UI.CoreWindow,这是UWP应用程序的主机窗口,也是您感兴趣的窗口。右键单击它并选择“属性”,在“进程”选项卡中单击进程ID。这将带您进入您想要了解的真正所有者进程。

因此,您只需从已有代码中进行额外的步骤,只需枚举子窗口并查找具有不同所有者进程的窗口即可。以下是一些C代码,试图使其尽可能通用而不会做出太多假设并且错误检查不足:

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

天气程序的输出结果:

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


1
一个晚期的观察 - 这个在窗口模式下可以工作,但无法在Win10上的全屏UWP应用程序中工作(返回ApplicationFrameHost.exe的pid,同时在枚举路径中作为父进程和子进程)。 - Prabindh
只有在UW应用程序已经处于活动状态并正在运行时,此方法才有效。如果您正在使用“SetWinEventHook”实时监控应用程序,并尝试上述代码,则仍将返回ApplicationFrameHost.exe,但是在我们切换到另一个应用程序然后再切换回来后,它将起作用。 - Asesh

13

这是一个小型的控制台应用程序,它连续地(因此您可以轻松测试选择桌面上的不同窗口)显示有关当前前景窗口进程和存储进程(如果有的话)的信息。

应用程序可以具有跨多个进程的窗口层次结构。我在这里做的是搜索第一个具有“Windows.UI.Core.CoreWindow”类名的子窗口。

该应用程序使用UIAutomation API(还使用由#import指令提供的智能指针、智能BSTR和智能VARIANT)。我想使用标准的Windows SDK也可以实现相同的功能,但我觉得以这种方式使用UIAutomation非常优雅。

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

2

将进程ID与什么进行比较?现代(Windows Store风格)应用程序不拥有顶级USER32窗口,因此获取正确的HWND以传递给GetWindowThreadProcessId()是非常复杂的。 - Ben Voigt
快照不需要 hwnd。它可以用来获取系统中所有进程的列表。然后,您可以根据您已知的有关进程的信息从该列表中过滤出一个条目。大概您知道一些有关进程的信息(比如其父进程 id)。 - Dmitry Rubanovich
@Ben Voigt,我会删除关于GetWindowThreadProcessId()的部分,因为正如你所提到的,没有hwnd。 - Dmitry Rubanovich

-2

从Win10周年更新开始,ApplicationFrameHost子窗口返回除UWP应用程序之外的任何内容。只有在重新登录后才能在平板电脑模式下工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接