获取桌面/ shell窗口的句柄

本文关键字:句柄 窗口 shell 桌面 获取 | 更新日期: 2023-09-27 18:16:39

在我的一个程序中,我需要测试用户当前是否正在关注桌面/shell窗口。目前我正在使用user32.dll中的GetShellWindow(),并将结果与GetForegroundWindow()进行比较。

这种方法是有效的,直到有人改变桌面壁纸,但一旦壁纸被改变的句柄从GetShellWindow()不匹配从GetForegroundWindow()不再,我不太明白为什么会这样。(操作系统: Windows 7 32bit)

有没有更好的方法来检查桌面是否集中?最好是一个不会因为用户更换壁纸而损坏的壁纸?

编辑:我设计了一个解决方案:我正在测试句柄有一个子类"SHELLDLL_DefView"。如果有,那么桌面就是焦点。虽然它在我的电脑上工作,但并不意味着它会一直工作…

获取桌面/ shell窗口的句柄

自从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);来获取顶层窗口,以检查它是否为前景窗口。

这是一个使用GetClassName()来检测桌面是否处于活动状态的解决方案:

  • 当Windows第一次启动时,桌面的类是"program"
  • 更换墙纸后,桌面的类为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
        }
    }
}