最近在做一个项目,有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() , 那么任务栏托盘图标就会自动消失了。