获取桌面/外壳窗口句柄

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

在我的一个程序中,我需要测试用户当前是否将焦点集中在桌面/shell 窗口。目前,我正在使用

user32.dll
中的 GetShellWindow() 并将结果与
GetForegroundWindow()
进行比较。

这种方法一直有效,直到有人更改桌面壁纸,但是一旦更改壁纸,

GetShellWindow()
中的句柄就不再与
GetForegroundWindow()
中的句柄相匹配,我不太明白这是为什么。 (操作系统:Windows 7 32位)

有没有更好的方法来检查桌面是否聚焦?最好是如果用户更换壁纸也不会损坏的?

编辑:我设计了一个解决方法:我正在测试手柄以拥有一个班级

SHELLDLL_DefView
的孩子。如果有,则桌面处于焦点状态。虽然它在我的电脑上运行,但这并不意味着它会一直运行。

c# .net windows winapi pinvoke
2个回答
8
投票

事情发生了一点变化,因为 Windows 7 中提供了幻灯片作为壁纸。 您对 WorkerW 的看法是正确的,但这仅适用于壁纸设置为幻灯片效果的情况。

当设置壁纸模式为幻灯片时,你必须搜索

WorkerW
类的窗口并检查子窗口,是否有
SHELLDLL_DefView
。 如果没有幻灯片,您可以使用旧的
GetShellWindow()

几个月前我遇到了同样的问题,我编写了一个函数来获取正确的窗口。不幸的是我找不到它。但以下应该有效。仅缺少 Win32 导入:

public enum DesktopWindow
{
    ProgMan,
    SHELLDLL_DefViewParent,
    SHELLDLL_DefView,
    SysListView32
}

public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
    IntPtr _ProgMan = GetShellWindow();
    IntPtr _SHELLDLL_DefViewParent = _ProgMan;
    IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
    IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");

    if (_SHELLDLL_DefView == IntPtr.Zero)
    {
        EnumWindows((hwnd, lParam) =>
        {
            if (GetClassName(hwnd) == "WorkerW")
            {
                IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
                if (child != IntPtr.Zero)
                {
                    _SHELLDLL_DefViewParent = hwnd;
                    _SHELLDLL_DefView = child;
                    _SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
                    return false;
                }
            }
            return true;
        }, IntPtr.Zero);
    }

    switch (desktopWindow)
    {
        case DesktopWindow.ProgMan:
            return _ProgMan;
        case DesktopWindow.SHELLDLL_DefViewParent:
            return _SHELLDLL_DefViewParent;
        case DesktopWindow.SHELLDLL_DefView:
            return _SHELLDLL_DefView;
        case DesktopWindow.SysListView32:
            return _SysListView32;
        default:
            return IntPtr.Zero;
    }
}

在您的情况下,您可以调用

GetDesktopWindow(DesktopWindow.SHELLDLL_DefViewParent);
来获取顶级窗口以检查它是否是前台窗口。


6
投票

以下是使用

GetClassName()
检测桌面是否处于活动状态的解决方法:

  • Windows第一次启动时,桌面的Class是“Progman”
  • 更改壁纸后,桌面的Class将是“WorkerW”

您可以针对这些进行测试,看看桌面是否获得焦点。

[DllImport("user32.dll")]
static extern int GetForegroundWindow();

[DllImport("user32.dll")]
static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);

public void GetActiveWindow() {
    const int maxChars = 256;
    int handle = 0;
    StringBuilder className = new StringBuilder(maxChars);

    handle = GetForegroundWindow();

    if (GetClassName(handle, className, maxChars) > 0) {
        string cName = className.ToString();
        if (cName == "Progman" || cName == "WorkerW") {
            // desktop is active
        } else {
            // desktop is not active
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.