勇哥注:
大家都知道在window里,进程之间通讯可以用消息通讯。
但是有个较冷门的知识就是RegisterWindowMessage。一般的sendmessage和postmessage是需要在窗体程序间进行通讯,你得知道对方窗口的句柄。
这个句柄每次启动程序时是系统分配的,每次不一样。
有了这个RegisterWindowMessage,两个进程可以共同持有一个相同的“句柄”,然后两者的顶层窗体间可以持这个“句柄”进行通讯。你不需要知道对方的窗体句柄是什么!
下面是引用自网络的文章,作者用C++讲述。
进程间通信的方法有很多,比如使用注册消息,内存映射,WM_COPYDATA等,下面先讲使用注册消息实现的方法。 使用注册消息比较简单,核心是消息的接收端和消息的发送端(接收端和发送端在两个不同的进程)必须注册相同的消息,这样发送消息才能识别。 下面看看具体实现: 一,发送消息进程 1, 在发送消息程序A注册消息: const UINT WM_UPDATE_ALARMFILTER = ::RegisterWindowMessage(_T("UpdateAlarmFilter")); 2,在程序需要发送消息时调用: ::PostMessage(HWND_BROADCAST, WM_UPDATE_ALARMFILTER, 0, 0); 参数HWND_BROADCAST表示将该消息发送到所有top-level的窗口,including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows. 如果不想发给所有顶层窗口,只想发给指定窗口,就不使用HWND_BROADCAST参数,获得要发送窗口的句柄即可: CWnd *pWnd = CWnd::FindWindow(NULL,_T("NMS Server")); // 查找A进程 if(pWnd != NULL) { pWnd->PostMessage(WM_UPDATE_ALARMFILTER, 0, 0); } 二,接收消息进程 1,在接收消息程序B,同样注册消息: const UINT WM_UPDATE_ALARMFILTER = ::RegisterWindowMessage(_T("UpdateAlarmFilter")); 2,定义消息映射: ON_REGISTERED_MESSAGE(WM_UPDATE_ALARMFILTER, OnUpdateAlarmFilter) 3, 在头文件声明: afx_msg LRESULT OnUpdateAlarmFilter(WPARAM wParam, LPARAM lParam); 4,在cpp文件定义函数: LRESULT CMainFrame::OnUpdateAlarmFilter(WPARAM wParam, LPARAM lParam) { // 消息处理 return 1; } 注意:要在消息的发送进程和接收进程注册同样的消息ID。 在接收端,如果不用消息宏定义,可以重载PreTranslateMessage,截取消息,然后处理: BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_UPDATE_ALARMFILTER) { // 消息处理 } return CDialog::PreTranslateMessage(pMsg); }
下面是勇哥编写的C#版演示程序。
首先是接收端:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); uint h = 0; public IntPtr hwndTest; public Form1() { InitializeComponent(); h=RegisterWindowMessage("lxy123456"); } private void button1_Click(object sender, EventArgs e) { hwndTest = this.Handle; } protected override void DefWndProc(ref Message msg) { if (msg.Msg == h) { MessageBox.Show("kkkkk"); } base.DefWndProc(ref msg); } public override bool PreProcessMessage(ref Message msg) { if(msg.Msg== h) { MessageBox.Show("kkkkk"); } return base.PreProcessMessage(ref msg); } } }
下面是发送端:
发送端注释了一部分代码,是想试试用sendmessage,postmessage发送不同的数据类型。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication2 { public partial class Form1 : Form { public class Win32API { [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern uint RegisterWindowMessage(string lpString); [DllImport("User32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("User32.dll", EntryPoint = "FindWindowEx")] public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName); /// <summary> /// 自定义的结构 /// </summary> public struct My_lParam { public int i; public string s; } /// <summary> /// 使用COPYDATASTRUCT来传递字符串 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; } //消息发送API [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 int lParam //参数2 ); //消息发送API [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 ref My_lParam lParam //参数2 ); //消息发送API [DllImport("User32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 ref COPYDATASTRUCT lParam //参数2 ); //消息发送API [DllImport("User32.dll", EntryPoint = "PostMessage")] public static extern int PostMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 int lParam // 参数2 ); //消息发送API [DllImport("User32.dll", EntryPoint = "PostMessage")] public static extern int PostMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 ref My_lParam lParam //参数2 ); //异步消息发送API [DllImport("User32.dll", EntryPoint = "PostMessage")] public static extern int PostMessage( IntPtr hWnd, // 信息发往的窗口的句柄 int Msg, // 消息ID int wParam, // 参数1 ref COPYDATASTRUCT lParam // 参数2 ); } uint handle = 0; public IntPtr hwndTest=(IntPtr)0xffff; public Form1() { InitializeComponent(); handle =Win32API.RegisterWindowMessage("lxy123456"); //hwndTest=Win32API.FindWindow(null, "lxy1"); } private void button1_Click(object sender, EventArgs e) { string strTest = "25425"; Win32API.COPYDATASTRUCT cds; cds.dwData = (IntPtr)100; cds.lpData = strTest; byte[] sarr = System.Text.Encoding.UTF8.GetBytes(strTest); int len = sarr.Length; cds.cbData = len + 1; Win32API.My_lParam lp = new Win32API.My_lParam(); lp.i = 3; lp.s = "test"; if (hwndTest != (IntPtr)0) { //if (DateTime.Now.Second % 2 == 0) //{ // Win32API.SendMessage(hwndTest, /*0x60*/(int)handle, 1, 3);//传递2个整型参数成功 //} //if (DateTime.Now.Second % 3 == 0) //{ // Win32API.SendMessage(hwndTest, /*0x61 */ (int)handle, 5, ref lp);//传递整型参数和结构类型成功,这个方法加以改变后可以传递对象 //} //if (DateTime.Now.Second % 5 == 0) //{ // Win32API.SendMessage(hwndTest, /*0x62 */ (int)handle, 5, ref cds);//传递整型参数和不定长的字符串成功 //} //if (DateTime.Now.Second % 7 == 0) //{ // Win32API.PostMessage(hwndTest, /*0x63 */ (int)handle, 5, 6);//传递2个整型参数成功 //} //if (DateTime.Now.Second % 9 == 0) //{ // Win32API.PostMessage(hwndTest, /*0x64 */ (int)handle, 3, ref lp);//传递整型参数成功,但是传递参数lp失败,3可以传递成功。 //} //if (DateTime.Now.Second % 11 == 0) //{ // Win32API.PostMessage(hwndTest, /*0x65 */ (int)handle, 3, ref cds);//传递整型参数成功,传递参数cds失败,3可以传递成功。 //} Win32API.PostMessage(hwndTest, /*0x65 */ (int)handle, 3,ref lp);//传递整型参数成功,传递参数cds失败,3可以传递成功。 } } } }
不过,由于postmessage在C#中没办法传送对象和字符串,所以也是一点小遗憾。(C++中是有办法的)
另外,HWND_BROADCAST枚举值是0xffff,万能的度娘没办法告诉我这个。
如果不使用RegisterWindowMessage的话,你得在sendmessage的时候由某个ini获取对方程序启动后写入的自己的窗口句柄,还是比较麻烦的。
当然,你也可以findwindow自己来找,还是比较麻烦。
你可以付费下载源码:
2元收费下载源码:
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

