目录
一、问题描述
二、解决方案
三、测试代码
参考文献
本文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139574981]。
一、问题描述
当 GUI 线程的窗口属于 Windows/UWP 应用程序时,它们始终由进程 ApplicationFrameHost 托管。如果依然使用 Win32 的那套方法我们最终将获取到根进程 ApplicationFrameHost.exe 而不是实际的 AppContainer 进程或者 RuntimeBroker 进程。
例如下面的情况:
这里的 0xB1568 窗口作为根父窗口,由 ApplicationFrameHost.exe 进程创建,而它的子窗口中有一个窗口不是由 ApplicationFrameHost.exe 进程创建的,而是指向了它的实际的 App 包进程。
查阅:关于 ApplicationWindow、FrameWindow 和 CoreWindow 的信息。
二、解决方案
我们进行一个测试可以找到它。当将 Spy++ 的窗口查找光标拖动到系统设置界面的标题栏区域时,我们将成功捕获到 CoreWindow。
查看进程信息:
所以,优化 FrameWindow 溯源的方法也出来了,就是遍历子窗口,找到实际进程,然后再获取你想要的信息,比如获取它是否是 UWP 应用:GetApplicationUserModelId 或者 GetPackageFamilyName 函数。
GetApplicationUserModelId 示例:
#define _UNICODE 1
#define UNICODE 1
#include <Windows.h>
#include <appmodel.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
int ShowUsage();
void ShowProcessApplicationUserModelId(__in const UINT32 pid, __in HANDLE process);
int ShowUsage()
{
wprintf(L"Usage: GetApplicationUserModelId <pid> [<pid>...]\n");
return 1;
}
int __cdecl wmain(__in int argc, __in_ecount(argc) WCHAR * argv[])
{
if (argc <= 1)
return ShowUsage();
for (int i=1; i<argc; ++i)
{
UINT32 pid = wcstoul(argv[i], NULL, 10);
if (pid > 0)
{
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (process == NULL)
wprintf(L"Error %d in OpenProcess (pid=%u)\n", GetLastError(), pid);
else
{
ShowProcessApplicationUserModelId(pid, process);
CloseHandle(process);
}
}
}
return 0;
}
void ShowProcessApplicationUserModelId(__in const UINT32 pid, __in HANDLE process)
{
wprintf(L"Process %u (handle=%p)\n", pid, process);
UINT32 length = 0;
LONG rc = GetApplicationUserModelId(process, &length, NULL);
if (rc != ERROR_INSUFFICIENT_BUFFER)
{
if (rc == APPMODEL_ERROR_NO_APPLICATION)
wprintf(L"Desktop application\n");
else
wprintf(L"Error %d in GetApplicationUserModelId\n", rc);
return;
}
PWSTR fullName = (PWSTR) malloc(length * sizeof(*fullName));
if (fullName == NULL)
{
wprintf(L"Error allocating memory\n");
return;
}
rc = GetApplicationUserModelId(process, &length, fullName);
if (rc != ERROR_SUCCESS)
wprintf(L"Error %d retrieving ApplicationUserModelId\n", rc);
else
wprintf(L"%s\n", fullName);
free(fullName);
}
GetPackageFamilyName 示例:
#define _UNICODE 1
#define UNICODE 1
#include <Windows.h>
#include <appmodel.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
int ShowUsage();
void ShowProcessPackageFamilyName(__in const UINT32 pid, __in HANDLE process);
int ShowUsage()
{
wprintf(L"Usage: GetPackageFamilyName <pid> [<pid>...]\n");
return 1;
}
int __cdecl wmain(__in int argc, __in_ecount(argc) WCHAR * argv[])
{
if (argc <= 1)
return ShowUsage();
for (int i=1; i<argc; ++i)
{
UINT32 pid = wcstoul(argv[i], NULL, 10);
if (pid > 0)
{
HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (process == NULL)
wprintf(L"Error %d in OpenProcess (pid=%u)\n", GetLastError(), pid);
else
{
ShowProcessPackageFamilyName(pid, process);
CloseHandle(process);
}
}
}
return 0;
}
void ShowProcessPackageFamilyName(__in const UINT32 pid, __in HANDLE process)
{
wprintf(L"Process %u (handle=%p)\n", pid, process);
UINT32 length = 0;
LONG rc = GetPackageFamilyName(process, &length, NULL);
if (rc != ERROR_INSUFFICIENT_BUFFER)
{
if (rc == APPMODEL_ERROR_NO_PACKAGE)
wprintf(L"Process has no package identity\n");
else
wprintf(L"Error %d in GetPackageFamilyName\n", rc);
return;
}
PWSTR familyName = (PWSTR) malloc(length * sizeof(*familyName));
if (familyName == NULL)
{
wprintf(L"Error allocating memory\n");
return;
}
rc = GetPackageFamilyName(process, &length, familyName);
if (rc != ERROR_SUCCESS)
wprintf(L"Error %d retrieving PackageFamilyName\n", rc);
else
wprintf(L"%s\n", familyName);
free(familyName);
}
三、测试代码
下面给出根据上文理论编写的,获取窗口进程的二进制文件路径的代码(C++):
#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <string>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
struct SPYWINDOWINFO
{
uint32_t ownerpid;
uint32_t childpid;
};
class UwpUtils
{
public:
static std::wstring GetProcessName(HWND hWnd)
{
std::wstring processName;
if (hWnd == nullptr)
return L"";
uint32_t pID = 0;
GetWindowThreadProcessId(hWnd, reinterpret_cast<LPDWORD>(&pID));
HANDLE proc = nullptr;
proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID);
if (proc == nullptr)
return L"";
DWORD capacity = 2000;
TCHAR exeName[2000];
if (QueryFullProcessImageNameW(proc, 0, exeName, &capacity) == FALSE)
{
CloseHandle(proc);
return L"";
}
processName = std::wstring(exeName, capacity);
if (!wcscmp(PathFindFileNameW(processName.c_str()), L"ApplicationFrameHost.exe"))
{
std::cout << "ExtendedWindowMode: " << std::endl;
processName = UWP_AppName(hWnd, pID);
}
else {
std::cout << "LegacyWindowMode: " << std::endl;
}
return processName;
}
private:
static std::wstring UWP_AppName(HWND hWnd, uint32_t pID)
{
SPYWINDOWINFO windowinfo = { 0 };
windowinfo.ownerpid = pID;
windowinfo.childpid = windowinfo.ownerpid;
LPVOID pWindowinfo = malloc(sizeof(windowinfo));
if (pWindowinfo == nullptr) {
return L"";
}
memcpy(pWindowinfo, &windowinfo, sizeof(windowinfo));
WNDENUMPROC lpEnumFunc = EnumChildWindowsCallback;
EnumChildWindows(hWnd, lpEnumFunc, reinterpret_cast<LPARAM>(pWindowinfo));
memcpy(&windowinfo, pWindowinfo, sizeof(windowinfo));
free(pWindowinfo);
if (windowinfo.childpid <= 4) {
return L"";
}
HANDLE proc = nullptr;
proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, windowinfo.childpid);
if (proc == nullptr)
return L"";
std::cout << "AppContainer Real Process ID: " << windowinfo.childpid << std::endl;
DWORD capacity = 2000;
TCHAR exeName[2000];
if (QueryFullProcessImageNameW(proc, 0, exeName, &capacity) == FALSE)
{
CloseHandle(proc);
return L"";
}
return std::wstring(exeName, capacity);
}
static BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lParam)
{
SPYWINDOWINFO info;
memcpy(&info, reinterpret_cast<LPCVOID>(lParam), sizeof(info));
uint32_t pID = 0;
GetWindowThreadProcessId(hWnd, reinterpret_cast<LPDWORD>(&pID));
if (pID != info.ownerpid)
info.childpid = pID;
memcpy(reinterpret_cast<LPVOID>(lParam), &info, sizeof(info));
return TRUE;
}
};
int main()
{
// 测试代码:
std::cout << "Please enter the handle to set the child window ";
std::cout << "(hexadecimal input, example 0x12B4): ";
std::string hexInput;
std::cin >> hexInput;
// 将十六进制字符串转换为数字
HWND hwnd = reinterpret_cast<HWND>(std::stoull(hexInput, nullptr, 16));
if (hwnd) {
// 检查句柄是否有效
if (IsWindow(hwnd)) {
std::cout << "(Verified) Valid window handle: " << hwnd << std::endl;
std::wstring processName = UwpUtils::GetProcessName(hwnd);
std::wcout << "Process Name: " << processName << std::endl;
}
else {
std::cerr << "(Verified) InValid window handle! " << std::endl;
}
}
else {
std::cerr << "Unable to convert input to a valid window handle! " << std::endl;
}
system("pause");
return 0;
}
测试效果:
参考文献
- c++ - Name of process for active window in Windows 8/10 - Stack Overflow
- How to get the "Application Name" from hWnd for Windows 10 Store Apps
- stackoverflow-code-samples/src/Q32001621 (github.com)
本文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139574981]。
本文发布于:2024.06.10.