我需要检索用户选择的窗口的句柄,然后检索其句柄。该窗口必须是按下 ALT+TAB 时显示的窗口之一。
我尝试使用 EnumWindows 枚举窗口,但它没有枚举全屏 UWP 窗口。例如,如果您使用“照片”应用程序打开一张图片并将其全屏显示,EnumWindows 将不会枚举它。
然后我尝试了EnumChildWindows,因为我认为它可以枚举所有内容,甚至是全屏 UWP 窗口,但可能不会。
GraphicsCapturePicker.PickSingleItemAsync方法显示了一个窗口列表,用户可以选择一个,但它返回一个GraphicsCaptureItem,我猜你无法从中获取窗口句柄。
是否可以重用 ALT+TAB 窗口来执行此操作(或显示窗口列表的任何其他方式)并检索用户选择的窗口的句柄?
注意:我需要按下 ALT+TAB 时显示的所有窗口,甚至是全屏 UWP 窗口,而不需要其他窗口。
我已经使用 Spy++ 进行了调查,
EnumWindows
和 EnumChildWindows
都无法检索全屏 UWP 窗口的根所有者的句柄。但是 EnumChildWindows
检索其子窗口,并且每个 UWP 窗口都有一个类名为 ApplicationFrameInputSinkWindow 的子窗口(以及其他子窗口)。然后,您可以使用 GetAncestor 检索根所有者窗口。
因此,要检索“标准”窗口,您可以调用 EnumWindows。
但是要检索全屏 UWP 窗口:
此示例演示了如何使用
EnumWindows
和 EnumChildWindows
枚举所有“ALT+TAB 窗口”,甚至是全屏 UWP 窗口。这些列在带有两列 DataGridView 的 Form 中,并检索与用户单击的行相对应的窗口句柄。
const int GWL_EXSTYLE = -20;
const uint DWMWA_CLOAKED = 14;
const uint DWM_CLOAKED_SHELL = 0x00000002;
const uint GA_ROOTOWNER = 3;
const uint WS_EX_TOOLWINDOW = 0x00000080;
const uint WS_EX_TOPMOST = 0x00000008;
const uint WS_EX_NOACTIVATE = 0x08000000;
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
dataGridView1.ReadOnly = true;
dataGridView1.Click += dataGridView1_Click;
EnumWindows(GetAltTabWindows, IntPtr.Zero);
EnumChildWindows(GetDesktopWindow(), GetFullScreenUWPWindows, IntPtr.Zero);
}
private bool GetAltTabWindows(IntPtr hWnd, IntPtr lparam)
{
if (IsAltTabWindow(hWnd))
AddWindowToGrid(hWnd);
return true;
}
private bool GetFullScreenUWPWindows(IntPtr hWnd, IntPtr lparam)
{
// Check only the windows whose class name is ApplicationFrameInputSinkWindow
StringBuilder className = new StringBuilder(1024);
GetClassName(hWnd, className, className.Capacity);
if (className.ToString() != "ApplicationFrameInputSinkWindow")
return true;
// Get the root owner of the window
IntPtr rootOwner = GetAncestor(hWnd, GA_ROOTOWNER);
if (IsFullScreenUWPWindows(rootOwner))
AddWindowToGrid(rootOwner);
return true;
}
private bool IsAltTabWindow(IntPtr hWnd)
{
// The window must be visible
if (!IsWindowVisible(hWnd))
return false;
// The window must be a root owner
if (GetAncestor(hWnd, GA_ROOTOWNER) != hWnd)
return false;
// The window must not be cloaked by the shell
DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, out uint cloaked, sizeof(uint));
if (cloaked == DWM_CLOAKED_SHELL)
return false;
// The window must not have the extended style WS_EX_TOOLWINDOW
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
if ((style & WS_EX_TOOLWINDOW) != 0)
return false;
return true;
}
private bool IsFullScreenUWPWindows(IntPtr hWnd)
{
// Get the extended style of the window
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
// The window must have the extended style WS_EX_TOPMOST
if ((style & WS_EX_TOPMOST) == 0)
return false;
// The window must not have the extended style WS_EX_NOACTIVATE
if ((style & WS_EX_NOACTIVATE) != 0)
return false;
// The window must not have the extended style WS_EX_TOOLWINDOW
if ((style & WS_EX_TOOLWINDOW) != 0)
return false;
return true;
}
private void AddWindowToGrid(IntPtr hWnd)
{
StringBuilder windowText = new StringBuilder(1024);
GetWindowText(hWnd, windowText, windowText.Capacity);
var strTitle = windowText.ToString();
var strHandle = hWnd.ToString("X8");
dataGridView1.Rows.Add(new string[] { strHandle, strTitle });
}
private void dataGridView1_Click(object sender, EventArgs e)
{
var dgv = (DataGridView)sender;
if (dgv.SelectedRows.Count == 0)
return;
// Get the value of the first cell of the selected row
var value = dgv.SelectedRows[0].Cells[0].Value;
if (value == null)
return;
// Convert the value to IntPtr
var strValue = value.ToString();
var intValue = int.Parse(strValue, System.Globalization.NumberStyles.HexNumber);
var windowHandle = new IntPtr(intValue);
// Do what you want with the window handle
}
当然,您也可以只使用
EnumChildWindows
来获取所有“ALT+TAB 窗口”,只要回调函数具有过滤不同窗口所需的所有过滤器即可。
这就是 Microsoft 在其屏幕捕获示例中所做的事情。
#pragma once
#include <dwmapi.h>
struct Window
{
public:
Window(nullptr_t) {}
Window(HWND hwnd, std::wstring const& title, std::wstring& className)
{
m_hwnd = hwnd;
m_title = title;
m_className = className;
}
HWND Hwnd() const noexcept { return m_hwnd; }
std::wstring Title() const noexcept { return m_title; }
std::wstring ClassName() const noexcept { return m_className; }
private:
HWND m_hwnd;
std::wstring m_title;
std::wstring m_className;
};
std::wstring GetClassName(HWND hwnd)
{
std::array<WCHAR, 1024> className;
::GetClassName(hwnd, className.data(), (int)className.size());
std::wstring title(className.data());
return title;
}
std::wstring GetWindowText(HWND hwnd)
{
std::array<WCHAR, 1024> windowText;
::GetWindowText(hwnd, windowText.data(), (int)windowText.size());
std::wstring title(windowText.data());
return title;
}
bool IsAltTabWindow(Window const& window)
{
HWND hwnd = window.Hwnd();
HWND shellWindow = GetShellWindow();
auto title = window.Title();
auto className = window.ClassName();
if (hwnd == shellWindow)
{
return false;
}
if (title.length() == 0)
{
return false;
}
if (!IsWindowVisible(hwnd))
{
return false;
}
if (GetAncestor(hwnd, GA_ROOT) != hwnd)
{
return false;
}
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (!((style & WS_DISABLED) != WS_DISABLED))
{
return false;
}
DWORD cloaked = FALSE;
HRESULT hrTemp = DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked));
if (SUCCEEDED(hrTemp) &&
cloaked == DWM_CLOAKED_SHELL)
{
return false;
}
return true;
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
auto class_name = GetClassName(hwnd);
auto title = GetWindowText(hwnd);
auto window = Window(hwnd, title, class_name);
if (!IsAltTabWindow(window))
{
return TRUE;
}
std::vector<Window>& windows = *reinterpret_cast<std::vector<Window>*>(lParam);
windows.push_back(window);
return TRUE;
}
const std::vector<Window> EnumerateWindows()
{
std::vector<Window> windows;
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&windows));
return windows;
}