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

Posted lpq21314

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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() , 那么任务栏托盘图标就会自动消失了。

 

以上是关于WinForm 关于任务栏图标进程结束后图标无法自动清除的问题!的主要内容,如果未能解决你的问题,请参考以下文章

C# winform 托盘图标问题?

windows任务栏和桌面图标不见啦!!!解决重赏

为啥任务栏没有图标

如何修改C#winform程序图标

电脑桌面图标右键用不了怎么办

电脑图标点击没有效果解决方法