【无标题】wpf最小化至托盘和只允许一个实例(第二次运行激活上个实例)

最小化至托盘使用ShowWindow实现。

ShowWindow nCmdShow参数参考https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-showwindow

如果使用Hide(),Show()来实现,它内部会改变Visibility的值,当我们第二次运行激活上个实例的时候无法直接通过ShowWindow直接激活窗口。

//在MainWindow中的代码 实现最小化至托盘
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "ShowWindow")]
public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

//设置右下角图标
private void SetIcon()
{
    string path = AppDomain.CurrentDomain.BaseDirectory + "Resources\\home.ico";
    if (File.Exists(path))
    {
        this.notifyIcon = new System.Windows.Forms.NotifyIcon();
        this.notifyIcon.Text = "XXX";//最小化到托盘时,鼠标点击时显示的文本
        System.Drawing.Icon icon = new System.Drawing.Icon(path);//程序图标
        this.notifyIcon.Icon = icon;
        this.notifyIcon.Visible = true;
        notifyIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(notifyIcon_MouseClick);
    }
}
//窗体关闭事件,最小化至托盘
private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    ShowWindow(Process.GetCurrentProcess().MainWindowHandle, 0);//隐藏窗口
    e.Cancel=true; 
    return;
}
//图标上面的鼠标事件 激活窗体
private void notifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
    if (e.Button == form.MouseButtons.Left)
    {
        if (WindowState == WindowState.Minimized)//防止窗体被最小化
        {
            WindowState = WindowState.Normal;
        }
        this.Activate();
        ShowWindow(new System.Windows.Interop.WindowInteropHelper(this).Handle, 5);//显示窗口
    }
}

只允许一个实例第二次运行激活上个实例使用Mutex锁和n个win32api

当最小化至托盘时使用EnumDesktopWindows函数枚举所有窗口来获取主窗口(参考https://stackoverflow.com/questions/21154693/activate-a-hidden-wpf-application-when-trying-to-run-a-second-instance)

public partial class App : Application
{
    [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
    public static extern int SetForegroundWindow(IntPtr hwnd);
    [DllImport("user32.dll", EntryPoint = "ShowWindow")]
    public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
    [DllImport("user32.dll")]
    private static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc ewp, int lParam);

    [DllImport("user32.dll")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

    [DllImport("user32.dll")]
    private static extern uint GetWindowTextLength(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern uint GetWindowText(IntPtr hWnd, StringBuilder lpString, uint nMaxCount);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern bool GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);

    const int GWL_EXSTYLE = (-20);
    const uint WS_EX_APPWINDOW = 0x40000;
    public const int WM_SYSCOMMAND = 0x112;
    public const int SC_RESTORE = 0xF120;
    System.Threading.Mutex mutex;
    protected override void OnStartup(StartupEventArgs e)
    {
        try
        {
           //运行时根据XXX来获取这个锁,当第二个运行时就拿不到,就激活上个实例
            mutex = new System.Threading.Mutex(true, "XXX", out bool createNew);
            if (!createNew)
            {
                var currProcess = Process.GetCurrentProcess();
                var sameNameProcess = Process.GetProcesses().FirstOrDefault(m => m.Id != currProcess.Id && m.ProcessName == currProcess.ProcessName && m.MainModule.FileName == currProcess.MainModule.FileName);
                if (sameNameProcess != null)
                {
                    var handle = sameNameProcess.MainWindowHandle;
                    if (handle == IntPtr.Zero)//当最小化至托盘时MainWindowHandle句柄是0
                    {
                        handle = GetWindowHandle(sameNameProcess.Id);
                    }
                    if (handle == IntPtr.Zero)
                    {
                        MessageBox.Show("未找到句柄,激活窗口失败,协同已启动请手动打开窗体"); return;
                    }
                    ShowWindow(handle,3);
                }
                Application.Current.Shutdown();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex);
        }
        base.OnStartup(e);
        
    }
    static bool IsApplicationWindow(IntPtr hWnd)
    {
        return (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_APPWINDOW) != 0;
    }
    static IntPtr GetWindowHandle(int pid)
    {
        var result = IntPtr.Zero;
        EnumWindowsProc enumerateHandle = delegate (IntPtr hWnd, int lParam)
        {
            int id;
            GetWindowThreadProcessId(hWnd, out id);

            if (pid == id)
            {
                var clsName = new StringBuilder(256);
                var hasClass = GetClassName(hWnd, clsName, 256);
                if (hasClass)
                {
                    var maxLength = (int)GetWindowTextLength(hWnd);
                    var builder = new StringBuilder(maxLength + 1);
                    GetWindowText(hWnd, builder, (uint)builder.Capacity);
                    var text = builder.ToString();
                    var className = clsName.ToString();
                    if (className.StartsWith("HwndWrapper") && IsApplicationWindow(hWnd))
                    {
                        result = hWnd;
                        return false;
                    }
                }
            }
            return true;
        };
        EnumDesktopWindows(IntPtr.Zero, enumerateHandle, 0);
        return result;
    }
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值