windows 获取桌面/外壳窗口的句柄

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8364758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:34:51  来源:igfitidea点击:

Get handle to desktop / shell window

c#.netwindowswinapipinvoke

提问by MFH

In one of my programs I need to test if the user is currently focusing the desktop/shell window. Currently I'm using GetShellWindow() from user32.dll and compare the result to GetForegroundWindow().

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

This approach is working until someone changes the desktop wallpaper, but as soon as the wallpaper is changed the handle from GetShellWindow() doesn't match the one from GetForegroundWindow() anymore and I don't quite get why that is. (OS:Windows 7 32bit)

这种方法在有人更改桌面墙纸之前一直有效,但是一旦更改墙纸,GetShellWindow() 中的句柄就不再与 GetForegroundWindow() 中的句柄匹配,我不太明白为什么会这样。(操作系统:Windows 7 32 位)

Is there a better approach to check if the desktop is focused? Preferably one that won't be broken if the user changes the wallpaper?

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

EDIT:I designed a workaround: I'm testing the handle to have a child of class "SHELLDLL_DefView". If it has, the desktop is on focus. Whilst it's working at my PC that doesn't mean it will work all the time…

编辑:我设计了一个解决方法:我正在测试句柄是否有一个“SHELLDLL_DefView”类的孩子。如果有,则桌面是焦点。虽然它在我的电脑上工作,但这并不意味着它会一直工作......

采纳答案by tklepzig

The thing changed a little bit since there are slideshows as wallpaper available in Windows 7. You are right with WorkerW, but this works only with wallpaper is set to slideshow effect.

事情发生了一些变化,因为在 Windows 7 中有幻灯片作为墙纸可用。您对 WorkerW 来说是正确的,但这仅适用于设置为幻灯片效果的墙纸。

When there is set the wallpaper mode to slideshow, you have to search for a window of class WorkerWand check the children, whether there is a SHELLDLL_DefView. If there is no slideshow, you can use the good old GetShellWindow().

当壁纸模式设置为幻灯片时,你必须搜索一个班级窗口WorkerW并检查孩子们是否有SHELLDLL_DefView. 如果没有幻灯片,您可以使用旧的GetShellWindow().

I had the same problem some months ago and I wrote a function for getting the right window. Unfortunately I can't find it. But the following should work. Only the Win32 Imports are missing:

几个月前我遇到了同样的问题,我写了一个函数来获取正确的窗口。不幸的是我找不到它。但以下应该工作。仅缺少 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;
    }
}

In your case you would call GetDesktopWindow(DesktopWindow.SHELLDLL_DefViewParent);to get the top-level window for checking whether it is the foreground window.

在您的情况下,您将调用GetDesktopWindow(DesktopWindow.SHELLDLL_DefViewParent);获取顶级窗口以检查它是否是前台窗口。

回答by AJKenny84

Here is a workaround that uses GetClassName()to detect if the desktop is active:

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

  • When Windows first starts, the desktop's Class is "Progman"
  • After changing the wallpaper, the desktop's Class will be "WorkerW"
  • Windows 首次启动时,桌面的 Class 为“Progman”
  • 更换壁纸后,桌面的Class为“WorkerW”

You can test against these to see if the desktop is focused.

您可以针对这些进行测试以查看桌面是否已聚焦。

[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
        }
    }
}