C#使用SendMessage进行进程间通讯
最近公司有个需求是,拖动文件到桌面图标上,自动打开文件。那么只需在OnStartup事件中通过StartupEventArgs获取文件名然后进行操作即可。操作之后发现当软件已经启动了(单例运行),那么将无法将参数传给业务层。原因是因为跨进程了,那么我们可以通过窗口句柄的方式来进行通讯。
1 public partial classApp : Application2 {3 private staticMutex AppMutex;4 publicApp()5 {6 7 }8 9 protected override voidOnStartup(StartupEventArgs e)10 {11 //获取启动参数 12 var param = string.Empty;13 if (e.Args.Length > 0)14 {15 param = e.Args[0].ToString();16 }17 18 //WpfApp8 = 你的项目名称 19 AppMutex = new Mutex(true, "WpfApp8", out varcreatedNew);20 21 if (!createdNew)22 {23 var current =Process.GetCurrentProcess();24 25 foreach (var process inProcess.GetProcessesByName(current.ProcessName))26 {27 if (process.Id !=current.Id)28 {29 Win32Helper.SetForegroundWindow(process.MainWindowHandle);30 Win32Helper.SendMessageString(process.MainWindowHandle, param);31 break;32 }33 }34 Environment.Exit(0);35 }36 else 37 {38 base.OnStartup(e);39 }40 }41 }
1 public classWin32Helper2 {3 [DllImport("user32.dll", ExactSpelling = true, CharSet =CharSet.Auto)]4 public static extern boolSetForegroundWindow(IntPtr hWnd);5 6 /// <summary> 7 ///发送消息8 /// </summary> 9 /// <param name="hWnd"></param> 10 /// <param name="Msg"></param> 11 /// <param name="wParam"></param> 12 /// <param name="lParam"></param> 13 /// <returns></returns> 14 [DllImport("user32.dll")]15 public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, refCOPYDATASTRUCT lParam);16 17 //声明常量 18 public const int WM_COPYDATA = 0x004A;19 20 //定义 COPYDATASTRUCT 结构 21 [StructLayout(LayoutKind.Sequential)]22 public structCOPYDATASTRUCT23 {24 publicIntPtr dwData;25 public intcbData;26 publicIntPtr lpData;27 }28 29 /// <summary> 30 ///发送字符串消息31 /// </summary> 32 /// <param name="hWnd"></param> 33 /// <param name="message"></param> 34 public static void SendMessageString(IntPtr hWnd, stringmessage)35 {36 if (string.IsNullOrEmpty(message)) return;37 38 byte[] messageBytes = Encoding.Unicode.GetBytes(message + '\0'); //添加终止符 39 40 COPYDATASTRUCT cds = newCOPYDATASTRUCT();41 cds.dwData =IntPtr.Zero;42 cds.cbData =messageBytes.Length;43 cds.lpData =Marshal.AllocHGlobal(cds.cbData);44 Marshal.Copy(messageBytes, 0, cds.lpData, cds.cbData);45 try 46 {47 SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, refcds);48 }49 finally 50 {51 //释放分配的内存,即使发生异常也不会泄漏资源 52 Marshal.FreeHGlobal(cds.lpData);53 }54 }55 }
1 public partial classMainWindow : Window2 {3 publicMainWindow()4 {5 InitializeComponent();6 }7 8 protected override voidOnSourceInitialized(EventArgs e)9 {10 base.OnSourceInitialized(e);11 12 HwndSource hwndSource = PresentationSource.FromVisual(this) asHwndSource;13 hwndSource.AddHook(WndProc);14 }15 16 private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref boolhandled)17 {18 if (msg ==WM_COPYDATA)19 {20 COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));21 string receivedMessage =Marshal.PtrToStringUni(cds.lpData);22 23 Console.WriteLine("收到消息:" +receivedMessage);24 25 //TODO:业务处理 26 MessageBox.Show(receivedMessage);27 28 handled = true;29 }30 31 returnIntPtr.Zero;32 }33 }