使 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 10 专业版
- 版本:21H2
- 内部版本:19044.1645
- 经验:Windows功能体验包120.2212.4170.0,
有一些Windows操作不能被开发者覆盖,例如:
- 始终在主任务栏上显示托盘图标
- 覆盖 Win+D 以始终在桌面上显示您的window
- 强制通知始终显示
这些是 Windows 操作系统的政策,以确保用户始终处于控制之中,而不是开发人员。
话虽如此,您可以尝试另一种方法来使您的“小部件”可见。我可以提出以下建议:
- 创建 1 秒 System.Threading.Timer
- 在计时器的回调中,check to see if there are any visible desktop windows。当有 none 时(即由于 Win+D 或用户只是 closing/minimizing 每 window),使你的小部件 window 可见。
在我看来,延迟 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 后保留在桌面上。
因此(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 10 专业版
- 版本:21H2
- 内部版本:19044.1645
- 经验:Windows功能体验包120.2212.4170.0,
有一些Windows操作不能被开发者覆盖,例如:
- 始终在主任务栏上显示托盘图标
- 覆盖 Win+D 以始终在桌面上显示您的window
- 强制通知始终显示
这些是 Windows 操作系统的政策,以确保用户始终处于控制之中,而不是开发人员。
话虽如此,您可以尝试另一种方法来使您的“小部件”可见。我可以提出以下建议:
- 创建 1 秒 System.Threading.Timer
- 在计时器的回调中,check to see if there are any visible desktop windows。当有 none 时(即由于 Win+D 或用户只是 closing/minimizing 每 window),使你的小部件 window 可见。
在我看来,延迟 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 后保留在桌面上。