显示所有“Alt+Tab 窗口”(甚至全屏 UWP 窗口)的列表并检索用户选择的窗口的句柄

问题描述 投票:0回答:2

我需要检索用户选择的窗口的句柄,然后检索其句柄。该窗口必须是按下 ALT+TAB 时显示的窗口之一。

我尝试使用 EnumWindows 枚举窗口,但它没有枚举全屏 UWP 窗口。例如,如果您使用“照片”应用程序打开一张图片并将其全屏显示,EnumWindows 将不会枚举它。

然后我尝试了EnumChildWindows,因为我认为它可以枚举所有内容,甚至是全屏 UWP 窗口,但可能不会。

GraphicsCapturePicker.PickSingleItemAsync方法显示了一个窗口列表,用户可以选择一个,但它返回一个GraphicsCaptureItem,我猜你无法从中获取窗口句柄。

是否可以重用 ALT+TAB 窗口来执行此操作(或显示窗口列表的任何其他方式)并检索用户选择的窗口的句柄?

注意:我需要按下 ALT+TAB 时显示的所有窗口,甚至是全屏 UWP 窗口,而不需要其他窗口。

c# winapi window-handles
2个回答
1
投票

我已经使用 Spy++ 进行了调查,

EnumWindows
EnumChildWindows
都无法检索全屏 UWP 窗口的根所有者的句柄。但是
EnumChildWindows
检索其子窗口,并且每个 UWP 窗口都有一个类名为 ApplicationFrameInputSinkWindow 的子窗口(以及其他子窗口)。然后,您可以使用 GetAncestor 检索根所有者窗口。

因此,要检索“标准”窗口,您可以调用 EnumWindows

但是要检索全屏 UWP 窗口:

  • 桌面窗口 作为父窗口调用 EnumChildWindows
  • 在回调函数中仅获取 class nameApplicationFrameInputSinkWindow 的窗口。
  • 调用 GetAncestor 获取根所有者窗口。
  • 如果根所有者窗口具有 扩展窗口样式 WS_EX_TOPMOST 而不是 WS_EX_NOACTIVATE 或 WS_EX_TOOLWINDOW,则它是全屏 UWP 窗口。

此示例演示了如何使用

EnumWindows
EnumChildWindows
枚举所有“ALT+TAB 窗口”,甚至是全屏 UWP 窗口。这些列在带有两列 DataGridViewForm 中,并检索与用户单击的行相对应的窗口句柄。

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 窗口”,只要回调函数具有过滤不同窗口所需的所有过滤器即可。


0
投票

这就是 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;
}

© www.soinside.com 2019 - 2024. All rights reserved.