【问题标题】:Name of process for active window in Windows 8/10Windows 8/10 中活动窗口的进程名称
【发布时间】:2015-11-28 08:59:28
【问题描述】:

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

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() 均未成功,因为它们分别返回 APPMODEL_ERROR_NO_APPLICATION 和 APPMODEL_ERROR_NO_PACKAGE,因为 active_process 句柄只是辅助进程,而不是活动应用程序的进程。

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

提前致谢!

【问题讨论】:

  • 你试过QueryFullProcessImageName吗?
  • 是的,它仍然返回 ApplicationFrameHost.exe 的路径,因为返回的 process_handle 是创建窗口的帮助进程。

标签: c++ windows winapi accessibility win-universal-app


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    对正在运行的进程进行快照并通过比较进程 ID 来提取名称是否不起作用? 完整参考:

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

    但是您使用 CreateToolhelp32Snapshot() 修复快照。

    或者来自 WTSEnumerateProcesses() 和周围的 API?

    很确定它在 Win 8 中工作。它在 10 中坏了吗?

    【讨论】:

    • 比较进程 ID 和什么?现代(Windows Store 风格)应用程序不拥有顶级 USER32 窗口,因此将正确的 HWND 传递给 GetWindowThreadProcessId() 并非易事。
    • 快照不需要 hwnd。它可用于获取系统中所有进程的列表。然后,您可以根据您对该过程的了解从该列表中过滤掉一个条目。大概你知道它的一些东西(比如它的父进程ID)。
    • @Ben Voigt,我将删除有关 GetWindowThreadProcessId() 的部分,因为正如您所提到的,没有 hwnd。
    【解决方案3】:

    当您想对类似的东西进行逆向工程时,请务必使用 Spy++ 实用程序。包含在 Visual Studio 中,您需要 Common7\Tools\spyxx_amd64.exe 中的 64 位版本。使用 Search > Find Window 并将靶心拖动到 UWP 应用,例如 Weather。

    您会看到使用 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

    【讨论】:

    • 后期观察 - 这适用于窗口模式,不适用于 Win10 上的全屏 UWP 应用程序(返回枚举路径中父项和子项的 ApplicationFrameHost.exe pid)。
    • 这仅适用于 UW 应用程序已经处于活动状态并正在运行的情况。如果您正在使用SetWinEventHook 对应用程序进行实时监控并尝试上面的代码,那么它仍然会返回 ApplicationFrameHost.exe 但在我们切换到另一个应用程序然后再次切换回来后它会起作用。
    【解决方案4】:

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

    应用程序可以有一个可以跨越多个进程的窗口层次结构。我在这里所做的是搜索具有“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;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-19
      相关资源
      最近更新 更多