使 WPF Window 忽略显示桌面 (Win+D)

Make WPF Window Ignore Show Desktop (Win+D)

因此(4-5 年前)关于这个主题已经有各种各样的问题,我一直在关注他们提出以下解决方案,以避免我的 window 对 Win+D 做出反应(显示桌面) 命令:

public partial class MainWindow : Window
{

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindowEx(IntPtr hP, IntPtr hC, string sC, string sW);
    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    public MainWindow()
    {
        InitializeComponent();
        Loaded += OnWindowLoaded;
    }

    private void OnWindowLoaded(object sender, RoutedEventArgs e)
    {
        IntPtr nWinHandle = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Progman", null);
        nWinHandle = FindWindowEx(nWinHandle, IntPtr.Zero, "SHELLDLL_DefView", null);
        SetParent(new WindowInteropHelper(this).Handle, nWinHandle);
    }
}

然而这对我来说似乎不起作用(上面的代码是在一个全新的项目中)。

任何人都可以解释一下 WinAPI 是否有任何变化,它仍然有效吗?这是我在这个主题上找到的几乎所有问题的答案。

我是运行:

有一些Windows操作不能被开发者覆盖,例如:

  • 始终在主任务栏上显示托盘图标
  • 覆盖 Win+D 以始终在桌面上显示您的window
  • 强制通知始终显示

这些是 Windows 操作系统的政策,以确保用户始终处于控制之中,而不是开发人员。

话虽如此,您可以尝试另一种方法来使您的“小部件”可见。我可以提出以下建议:

在我看来,延迟 1 秒显示您的小部件对您的用户体验来说是一个很小的代价。

好的,所以我找到了适合我的解决方案,我知道将 window 设置为桌面的子项有它的 problems/risks,但对于仍然需要这样做的人来说,这里是我发现的:

“SHELLDLL_DefView”桌面 window 并不总是“Progman”的子项,有时它是“WorkerW”window 的子项。这就是我原来问题中的代码对我不起作用的原因。

因此,与其找到“Progman”window 并找到“SHELLDLL_DefView”子节点,不如枚举所有 windows 并找到 window小时候有“SHELLDLL_DefView”。

这是通过 EnumWindows 函数完成的 (https://www.pinvoke.net/default.aspx/user32.enumwindows)

下面的代码是上面 pinvoke.net link 中的示例之一和以下 2 个答案的混搭:


    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr FindWindowEx(IntPtr hP, IntPtr hC, string sC, 
    string sW);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumWindows(EnumedWindow lpEnumFunc, ArrayList 
    lParam);

    public delegate bool EnumedWindow(IntPtr handleWindow, ArrayList handles);

    public static bool GetWindowHandle(IntPtr windowHandle, ArrayList 
    windowHandles)
    {
        windowHandles.Add(windowHandle);
        return true;
    }

    private void SetAsDesktopChild() 
    {
        ArrayList windowHandles = new ArrayList();
        EnumedWindow callBackPtr = GetWindowHandle;
        EnumWindows(callBackPtr, windowHandles);

        foreach (IntPtr windowHandle in windowHandles)
        {
            IntPtr hNextWin = FindWindowEx(windowHandle, IntPtr.Zero,     
            "SHELLDLL_DefView", null);
            if (hNextWin != IntPtr.Zero)
            {
                var interop = new WindowInteropHelper(_window);
                interop.EnsureHandle();
                interop.Owner = hNextWin;
            }
        }
    }

现在,我的 WPF 在按预期显示 Desktop/Win+D 后保留在桌面上。