Имя процесса для активного окна в Windows 8/10

В следующем примере надежно возвращено имя процесса, связанного с активным окном, но оно не работает с более новыми современными / универсальными приложениями, поскольку возвращает имя вспомогательного процесса. 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 является просто вспомогательным процессом, а не процессом активного приложения.

Любые другие API-интерфейсы, используемые для получения имени процесса современного / универсального приложения по заданному окну окна или для определения иного имени процесса универсального приложения, активны.

Заранее спасибо!

20

Решение

Обязательно используйте утилиту Spy ++, если вы хотите перепроектировать что-то подобное. В комплекте с Visual Studio вам нужна 64-битная версия в Common7 \ Tools \ spyxx_amd64.exe. Используйте Search> Find Window и перетащите яблочко в приложение UWP, например, Weather.

Вы увидите окно, которое вы найдете с помощью GetForegroundWindow (), оно имеет как минимум 3 дочерних окна:

  • ApplicationFrameTitleBarWindow
  • ApplicationFrameInputSinkWindow
  • Windows.Core.UI.CoreWindow, это главное окно для приложения UWP и того, которое вас интересует. Щелкните его правой кнопкой мыши и выберите «Свойства», вкладка «Процесс», нажмите «Идентификатор процесса». Это приведет вас к реальному процессу владельца, который вы хотите знать.

Так что вам просто нужно сделать дополнительный шаг из кода, который у вас уже есть, вы просто должны перечислить дочерние окна и найти одно с другим процессом владельца. Некоторый код на 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

17

Другие решения

Это небольшое консольное приложение, которое непрерывно (так что вы можете легко проверить его, выбирая разные окна на рабочем столе) отображает информацию о текущем процессе основного окна и процессе сохранения, если таковые имеются.

Приложения могут иметь иерархию окон, которая может охватывать несколько процессов. То, что я делаю здесь, это поиск в первом подокне с именем класса «Windows.UI.Core.CoreWindow».

Это приложение использует UIAutomation API (а также умные указатели, умные BSTR и умные VARIANT, предоставляемые директивой #import). Я полагаю, вы можете сделать то же самое со стандартным 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;
}
10

Не работает ли моментальный снимок запущенных процессов и извлечение имени из него путем сравнения идентификаторов процессов?
Полная ссылка здесь:

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

Но вы исправляете снимок с помощью CreateToolhelp32Snapshot ().

Или из WTSEnumerateProcesses () и окружающего API?

Уверен, он работал в Win 8. Он сломан в 10?

2

Начиная с Win10 Anniversary Update, дочернее окно ApplicationFrameHost возвращает все, кроме приложения UWP. Работало только в режиме планшета после повторного запуска.

-2