如何防止窗口最小化

本文关键字:最小化 窗口 何防止 | 更新日期: 2023-09-27 18:08:31

当用户点击显示桌面按钮时,如何防止WPF窗口最小化?

如何防止窗口最小化

发出"Show Desktop"时不会最小化Windows。相反,"WorkerW"answers"Desktop"窗口被放在前台。

我最终想出了自己的解决方案。我在网上搜了几个星期,试图找到一个答案,所以我有点自豪的这一个。

所以我们要做的是使用pinvoke为EVENT_SYSTEM_FOREGROUND窗口事件创建一个钩子。当前台窗口发生变化时,此事件将触发。

现在我注意到的是,当"显示桌面"命令发出时,WorkerW窗口类变成了前台。

注意这个WorkerW窗口不是桌面,我确认这个WorkerW窗口的hwnd不是桌面hwnd。

所以我们所做的就是每当WorkerW窗口成为前景时,我们将"WPF Gadget窗口"设置为最顶部!

当WorkerW窗口以外的窗口成为前景时,我们从"WPF Gadget窗口"中删除topmost。

如果你想更进一步,你可以取消注释我检查的部分,如果新的前景窗口也是"programman",这是桌面窗口。

但是,如果用户在不同的显示器上单击桌面,这将导致您的窗口成为最上面的。就我而言,我不想要这种行为,但我想你们中的一些人可能会。

已确认可在Windows 10中工作。应该可以在旧版本的Windows中工作。

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
namespace YourNamespace
{
    internal static class NativeMethods
    {
        [DllImport("user32.dll")]
        internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, ShowDesktop.WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
        [DllImport("user32.dll")]
        internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
        [DllImport("user32.dll")]
        internal static extern int GetClassName(IntPtr hwnd, StringBuilder name, int count);
    }
    public static class ShowDesktop
    {
        private const uint WINEVENT_OUTOFCONTEXT = 0u;
        private const uint EVENT_SYSTEM_FOREGROUND = 3u;
        private const string WORKERW = "WorkerW";
        private const string PROGMAN = "Progman";
        public static void AddHook(Window window)
        {
            if (IsHooked)
            {
                return;
            }
            IsHooked = true;
            _delegate = new WinEventDelegate(WinEventHook);
            _hookIntPtr = NativeMethods.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _delegate, 0, 0, WINEVENT_OUTOFCONTEXT);
            _window = window;
        }
        public static void RemoveHook()
        {
            if (!IsHooked)
            {
                return;
            }
            IsHooked = false;
            NativeMethods.UnhookWinEvent(_hookIntPtr.Value);
            _delegate = null;
            _hookIntPtr = null;
            _window = null;
        }
        private static string GetWindowClass(IntPtr hwnd)
        {
            StringBuilder _sb = new StringBuilder(32);
            NativeMethods.GetClassName(hwnd, _sb, _sb.Capacity);
            return _sb.ToString();
        }
        internal delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
        private static void WinEventHook(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
        {
            if (eventType == EVENT_SYSTEM_FOREGROUND)
            {
                string _class = GetWindowClass(hwnd);
                if (string.Equals(_class, WORKERW, StringComparison.Ordinal) /*|| string.Equals(_class, PROGMAN, StringComparison.Ordinal)*/ )
                {
                    _window.Topmost = true;
                }
                else
                {
                    _window.Topmost = false;
                }
            }
        }
        public static bool IsHooked { get; private set; } = false;
        private static IntPtr? _hookIntPtr { get; set; }
        private static WinEventDelegate _delegate { get; set; }
        private static Window _window { get; set; }
    }
}

此链接将帮助您:获取WPF窗口的最小化框点击

你需要捕获事件并自己处理它。

编辑:这个方法会提醒你一旦状态改变,所以它可能不是"最好"的解决方案,但它可以工作。

您可以更改窗口的父窗口,使其不受显示桌面的影响。(如此处所述:Window "on desktop")

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Loaded += MainWindowLoaded;
    }
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    private void MainWindowLoaded(object sender, RoutedEventArgs e)
    {
        var hwnd = new WindowInteropHelper(this).Handle;
        var ProgmanHwnd = FindWindowEx(FindWindowEx(FindWindow("Progman", "Program Manager"), IntPtr.Zero, "SHELLDLL_DefView",""), IntPtr.Zero,"SysListView32", "FolderView");
        SetParent(hwnd, ProgmanHwnd);
    }
}