最小化至托盘使用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;}
}
}