• WinForm 关于任务栏图标进程结束后图标无法自动清除的问题!


           最近在做一个项目,有2个进程,A进程需要定时把B进程强行kill掉,然后再启动,当时这样会有一个问题,就是强行kill掉的进程在任务栏的托盘图标不会自动消失,必须用鼠标经过那个位置才会消失。这样就导致事件久了,任务栏出现一大堆图标,非常影响形象。

          后来网上看到一个方法,说是通过进程间的通讯,就是由A发送通知给B,告诉B应该要退出程序了,然后由B自己来结束进程,这样任务栏的图标才会正常的消失。废话少说,直接看代码吧:

    对于A进程来说,需要先找到B进程的句柄,然后才能给它发送通知,代码如下:

    /// <summary>
            /// 根据端口号结束某个进程
            /// </summary>
            /// <param name="port">端口号,如:7012  </param>
            /// <returns></returns>
            private void KillPortProcess(int port)
            { 
                int pid = 0;
    
                try
                {
                    IntPtr hwnd = FindWindow(null, port.ToString());
                    int ihWnd = (int)hwnd;
                    GetWindowThreadProcessId(hwnd, out pid);
                    var p = Process.GetProcessById(pid);
                    if (p != null)
                    {
                        if (p.ProcessName == "MySvr")
                        {
                            //强制杀掉进程(这种模式不能自动销毁任务栏图标)
                            //p.Kill();                        
                              
                            //利用发送消息方式,通知进程自杀(这种模式可以自动销毁任务栏图标)
                            byte[] sarr = System.Text.Encoding.Default.GetBytes("SelfKill");
                            int len = sarr.Length;
                            COPYDATASTRUCT cds;
    
                            cds.dwData = (IntPtr)Convert.ToInt16("1");//可以是任意值 
                            cds.cbData = len + 1;//指定lpData内存区域的字节数 
                            cds.lpData = "SelfKill";//发送给目标窗口所在进程的数据
    
                            int iflag = SendMessage(ihWnd, WM_COPYDATA, 0, ref cds); 
                        }
                    }
                }
                catch (Exception e)
                { 
                } 
            }

    我这个函数是根据进程的窗体标题来查找的,因为我的标题都是一个固定的端口号,所以按这种方式来做,当然也可以根据进程名称来做,在这里就不举例了。

    这里用到了Windows的API函数:  SendMessage  , 要引用这个函数,必须事先做以下的声明才能使用:

     消息结构体:

    public struct COPYDATASTRUCT
        {
    
            public IntPtr dwData;
    
            public int cbData;
    
            [MarshalAs(UnmanagedType.LPStr)]
    
            public string lpData;
    
        }

    声明要引用的API函数:

            [DllImport("User32.dll", EntryPoint = "FindWindow")]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32", EntryPoint = "GetWindowThreadProcessId")]
            public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int pid);
    
            [DllImport("User32.dll", EntryPoint = "SendMessage")]
            private static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
     
    
            const int WM_COPYDATA = 0x004A;

    -------------------------------------------------------------------------------------------------------------------------------------------------------

    那么对于B进程来说,需要做的事情就是接收A进程发来的消息,根据消费的内容来做出对应的动作,

    只要重载 DefWndProc 函数即可实现消息的接收处理,代码如下:

    /// <summary>
            /// 消息接受处理函数
            /// </summary>
            /// <param name="m"></param>
            protected override void DefWndProc(ref Message m)
            {
    
                switch (m.Msg)
                {
    
                    case WM_COPYDATA: 
                        COPYDATASTRUCT cds = new COPYDATASTRUCT(); 
                        Type t = cds.GetType(); 
                        cds = (COPYDATASTRUCT)m.GetLParam(t); 
                        string strResult = cds.dwData.ToString() + ":" + cds.lpData;
    
                        AppendText(strResult);
                         
                        //强制退出
                        if (strResult == "1:SelfKill")
                        {
                            Thread.Sleep(1000);
                            this.mainNotifyIcon.Dispose();
                            Application.Exit();
                        }
                        break; 
                    default: 
                        base.DefWndProc(ref m); 
                        break; 
                }
    
            }

    在B进程退出前,只要把 NotifyIcon.Dispose() , 那么任务栏托盘图标就会自动消失了。

  • 相关阅读:
    【知识总结】Burnside 引理和 Polya 定理
    【洛谷1973】[NOI2011]NOI嘉年华(动态规划)
    【洛谷4705】玩游戏(多项式)
    【洛谷5366】[SNOI2017] 遗失的答案(状压DP)
    【Codeforces235D_CF235D】Graph Game(概率_基环树)
    【Codeforces553E_CF553E】Kyoya and Train(概率_CDQ分治_FFT)
    【知识总结】博弈论入门
    Saltstack
    Tomcat 的 catalina.out 日志分割
    eclipse的工程里的*.properties文件默认以unicode的编码形式显示
  • 原文地址:https://www.cnblogs.com/lpq21314/p/9475325.html
Copyright © 2020-2023  润新知