进程间的通信以及发送消息
2017-12-19 22:05
579 查看
背景:公司一个程序(C++程序)启动另一个程序(C# 程序),启动时会有两三秒的空白时间,所以就需要先预先启动子程序渲染窗体(启动时隐藏窗体窗体),还有部分数据不确定所以要在正真启动的时候再向子程序发消息。
C#隐式启动并渲染窗体
C#进程间发消息
普通方法无法获取到无窗体的程序的窗体句柄
GetCurrentWindowHandle()是获取隐藏窗体句柄的方法(程序无窗体,普通方法获取主线程句柄为空)
C#窗体接收消息
虽然最后发现其实Mutex就能解决实际问题,但是这也算是一次完整的学习经验
C#隐式启动并渲染窗体
//Application.Run(new Form1());此方法窗体不能直接隐藏 Application.Run(new HideOnStartupApplicationContext(new Form1()));
internal class HideOnStartupApplicationContext : ApplicationContext { private Form mainFormInternal; public HideOnStartupApplicationContext(Form mainForm) { this.mainFormInternal = mainForm; this.mainFormInternal.FormClosed += new FormClosedEventHandler(mainFormInternal_FormClosed); } void mainFormInternal_FormClosed(object sender, FormClosedEventArgs e) { Application.Exit(); } }
C#进程间发消息
普通方法无法获取到无窗体的程序的窗体句柄
private void button1_Click(object sender, EventArgs e) { IntPtr ippp = GetCurrentWindowHandle(); SendMess(ippp.ToInt32(), "111"); } [DllImport("user32.dll")] public static extern IntPtr PostMessage(int hWnd, int Msg, IntPtr wParam, int lParam); [DllImport("user32.dll")] public static extern int SendMessage(int hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam); public const int WM_USER = 0x0400;//用户自定义消息 public const int WM_POSTMESSAGE = WM_USER + 1000;//发送信息 public const int defaultlParam = 0; public const int WM_COPYDATA = 0x004A; public Int64 m_Handle;//发送消息的句柄 /// <summary> /// 重载函数,只传递字符串 /// </summary> /// <param name="Handle">目标句柄</param> /// <param name="lParam">字符串</param> public void SendMess(int Handle, string lParam) { byte[] chrs = Encoding.Default.GetBytes(lParam); int size = chrs.Length; COPYDATASTRUCT cds; cds.dwData = (IntPtr)100; cds.cbData = size + 1; cds.lpData = lParam; if (Handle > 0) SendMessage(Handle, WM_COPYDATA, 0, ref cds); } /// <summary> /// PostMessage方法发送消息 /// </summary> /// <param name="Handle">目标句柄</param> /// <param name="wParam">发送的消息</param> public void PostMess(int Handle, string wParam) { IntPtr p = Marshal.StringToHGlobalAnsi(wParam); if (Handle > 0) PostMessage(Handle, WM_POSTMESSAGE, p, 0); } public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; } private static Hashtable processWnd = null; public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam); [DllImport("user32.dll", EntryPoint = "EnumWindows", SetLastError = true)] public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam); [DllImport("user32.dll", EntryPoint = "GetParent", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId); [DllImport("user32.dll", EntryPoint = "IsWindow")] public static extern bool IsWindow(IntPtr hWnd); [DllImport("kernel32.dll", EntryPoint = "SetLastError")] public static extern void SetLastError(uint dwErrCode); public static IntPtr GetCurrentWindowHandle() { IntPtr ptrWnd = IntPtr.Zero; if (processWnd == null) { processWnd = new Hashtable(); } System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("FutureReport.Mars.Viewer.vshost"); System.Diagnostics.Process p = procs[0]; uint uiPid = (uint)p.Id; // 当前进程 ID object objWnd = processWnd[uiPid]; if (objWnd != null) { ptrWnd = (IntPtr)objWnd; if (ptrWnd != IntPtr.Zero && IsWindow(ptrWnd)) // 从缓存中获取句柄 { return ptrWnd; } else { ptrWnd = IntPtr.Zero; } } bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid); // 枚举窗口返回 false 并且没有错误号时表明获取成功 if (!bResult && Marshal.GetLastWin32Error() == 0) { objWnd = processWnd[uiPid]; if (objWnd != null) { ptrWnd = (IntPtr)objWnd; } } return ptrWnd; } private static bool EnumWindowsProc(IntPtr hwnd, uint lParam) { uint uiPid = 0; if (GetParent(hwnd) == IntPtr.Zero) { GetWindowThreadProcessId(hwnd, ref uiPid); if (uiPid == lParam) // 找到进程对应的主窗口句柄 { processWnd[uiPid] = hwnd; // 把句柄缓存起来 SetLastError(0); // 设置无错误 return false; // 返回 false 以终止枚举窗口 } } return true; }
GetCurrentWindowHandle()是获取隐藏窗体句柄的方法(程序无窗体,普通方法获取主线程句柄为空)
C#窗体接收消息
protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_POSTMESSAGE: string str = Marshal.PtrToStringAnsi(m.WParam); MessageBox.Show(str); break; case WM_COPYDATA: COPYDATASTRUCT myStr = new COPYDATASTRUCT(); Type myType = myStr.GetType(); myStr = (COPYDATASTRUCT)m.GetLParam(myType); MessageBox.show(myStr.lpData); this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.Show(); break; default: base.WndProc(ref m); break; } } public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; }
虽然最后发现其实Mutex就能解决实际问题,但是这也算是一次完整的学习经验
相关文章推荐
- MFC 不同进程间的消息通信与数据(字符串)发送
- 跨进程消息以及数据发送
- 发送WM_COPYDATA消息实现进程间的通信
- VC/MFC 不同进程间的消息通信与数据(字符串)发送
- msgrcv,msgsnd进程通信,消息的发送和接收
- msgrcv,msgsnd进程通信,消息的发送和接收
- VC/MFC 不同进程间的消息通信与数据(字符串)发送
- VC/MFC 不同进程间的消息通信与数据(字符串)发送
- linux C++ 网络通信 -- Broken pipe,接收端突然断开,发送没收到,仍然发送消息,会导致进程崩溃
- 写的进程通信子进程类,向子进程发送消息
- VC/MFC 不同进程间的消息通信与数据(字符串)发送
- Java Smack SDK 结合 Openfire服务器,建立IM通信,发送聊天消息
- 简单的,父子进程间通过消息队列通信。
- Smack 结合 Openfire服务器,建立IM通信,发送聊天消息
- [VC]SendMessage和PostMessage发送消息(不同进程传递字符串)
- linux进程通信---几个发送信号的函数(kill,raise,alarm,pause)
- Linux进程间的通信方式----消息队列
- Linux进程通信之POSIX消息队列
- 用任务管理器关闭进程所发送的消息
- 父子进程通信的两种方式--消息队列和共享内存