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