WPF - 单例程序和系统托盘

Tim
2024-10-22
点 赞
0
热 度
34
评 论
0

文章摘要

智阅GPT

记录一下工作中遇到的场景。单例运行程序同时还要将程序隐藏到系统托盘,再次启动程序时如果已存在需要调出隐藏的程序

Mutex 互斥锁

程序启动入口添加互斥锁判断:

public  System.Threading.Mutex mutex;
public static bool AppSingletonMark = false;

protected override void OnStartup(StartupEventArgs e)
{
     bool isNew;
     mutex = new Mutex(true, "Singleton Instance Sample", out isNew);
     if (!isNew)//isNew为false代表已经存在,所以需要关闭正在打开的程序
     {
        //这里可以添加唤起已启动的程序
        ... ...

        AppSingletonMark = true;//标识是否需要隐藏程序
        Shutdown();
     }  
 }

NotifyIcon 系统托盘

在主窗体加载的同时创建系统托盘:

private System.Windows.Forms.NotifyIcon notifyIcon;

private void InitialTray()
{
    this.notifyIcon = new System.Windows.Forms.NotifyIcon();
    this.notifyIcon.BalloonTipText = "提示文本";
    this.notifyIcon.ShowBalloonTip(8000);
    this.notifyIcon.Text = "Wits监听中...";
    //this.notifyIcon.Icon = new System.Drawing.Icon("../../activity_monitor.ico");
    //以上一句替换成下面内容,意思就是读取程序图标,来作为托盘图标
    this.notifyIcon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(System.Windows.Forms.Application.ExecutablePath);
    this.notifyIcon.Visible = true;

    //打开菜单项
    System.Windows.Forms.MenuItem show = new System.Windows.Forms.MenuItem("Show");
    show.Click += new EventHandler(Show);
    //退出菜单项
    System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("Exit");
    exit.Click += new EventHandler(Close);
    //将菜单关联到托盘控件
    System.Windows.Forms.MenuItem[] childen = new System.Windows.Forms.MenuItem[] { show, exit };
    this.notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen);

    //单机系统托盘图标,显示程序
    this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler((o, e) =>
    {
        if (e.Button == MouseButtons.Left) this.Show(o, e);
    });
}

 /// <summary>
 /// 显示主窗体
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void Show(object sender, EventArgs e)
 {
     this.Visibility = System.Windows.Visibility.Visible;
     this.ShowInTaskbar = true;
     this.Activate();
     //this.notifyIcon.Visible = false;
 }
private void Close(object sender, EventArgs e)
{
   Environment.Exit(0);
   System.Windows.Application.Current.Shutdown();
}

Win32 唤起隐藏程序

需要注意的是对于隐藏的程序还要使用 SendMessage 否则程序将会黑屏

/// <summary>
/// 正常显示窗口值
/// </summary>
private const int WS_SHOWNORMAL = 1;

/// <summary>
/// 当隐藏或显示窗口是发送此消息给这个窗口 
/// </summary>
private const int WM_SHOWWINDOW =0x18;

/// <summary>
/// 设置由不同线程产生的窗口的显示状态
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">窗口如何显示</param>
/// <returns></returns>
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

/// <summary>
/// 把创建给定窗口的线程放到前台并激活该窗口                                 
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <returns></returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

/// <summary>
/// 查找窗口句柄
/// </summary>
/// <param name="lpClassName">窗口类名</param>
/// <param name="lpWindowName">窗口文本</param>
/// <returns></returns>
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);


[DllImport("User32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public void HandleRunningInstance(string windowsTitle)
{
    //通过窗体的title查找句柄
    var windowHandle = FindWindow(null, windowsTitle); 
  
    //发送显示消息到指定窗体
    SendMessage(windowHandle, WM_SHOWWINDOW, (IntPtr)1,(IntPtr)3);

    //确保窗口没有被最小化或最大化 
    ShowWindowAsync(windowHandle, WS_SHOWNORMAL);
    
    //设置为foreground window 
    SetForegroundWindow(windowHandle);
}


眼睛记得的光影,心记得的温度,它们不会消散,只是藏进岁月的褶皱里。某一天,风一吹,它们又鲜活如初...

Tim

infj 提倡者

站长

具有版权性

请您在转载、复制时注明本文 作者、链接及内容来源信息。 若涉及转载第三方内容,还需一同注明。

具有时效性

目录

欢迎来到Tim的博客,为您导航全站动态

45 文章数
4 分类数
3 评论数
48标签数

热门文章

D&F - Frida

2024-08-04

1716
D&F开服

2024-07-27

760
D&F - DP插件

2024-08-04

355

访问统计