.NET Framework 中对进程间的通讯支持不多,不过Windows API 已经为我们提供了丰富的进程间通讯的特性。我们可以使用Windows API SendMessage、PostMessage来实现windows 窗体之间的通讯。本文就是将SendMessage封装在一个窗体基类WinMsgData中,把它变成类中的一个方法以方便调用,而接收其他窗体的消息则封装成事件通知的形式提供。其中还对接收到的消息做队列处理,避免对消息发送方造成阻塞。所以只要程序中的WinForm从这个基类继承,就可以很方便的与其他的窗体进行通讯了。
下面看看具体的实现吧。
首先在窗体的构造函数中,我使用RegisterWindowMessage为希望通讯的窗体在系统中注册一个消息值。然后执行一个“Connect”的动作,就是使用PostMessage做广播,看看是否有“志同道合”者。代码如下:
-
publiceventWindowsMessageHandlerOnMessage;
-
publicdelegatevoidWindowsMessageHandler(objectsender,
- WindowsMessageEventArgse);
-
privateconststringDefaultAttachWindowMessage
-
="Peanut.DefaultAttachWinMsgString";
-
privateboolconnected=false;
-
privateintattachMessage;
-
privateintthisHandle;
-
privatestringattachMessageString;
-
privateList<IntPtr>AttachWindows;
-
privateQueue<WindowsMessageEventArgs>incomingMessageQueue
-
=newQueue<WindowsMessageEventArgs>();
-
publicWinMsgData():this(DefaultAttachWindowMessage){}
-
publicWinMsgData(stringattachMessageString)
- {
-
this.thisHandle=this.Handle.ToInt32();
-
AttachWindows=newList<IntPtr>();
-
this.attachMessageString=attachMessageString;
-
this.attachMessage=User32.RegisterWindowMessage(attachMessageString);
-
Connect();
- }
-
privatevoidConnect()
- {
-
if(User32.PostMessage(User32.HWND_BROADCAST,
-
attachMessage,thisHandle,1)==0)
-
thrownewException("PostMessagefailed.");
-
else
-
connected=true;
- }
调用到Windows API代码如下:
具体如何调用Windows的API请看Calling Win32 DLLs in C# with P/Invoke。
-
publicstructCOPYDATASTRUCT
- {
-
publicIntPtrdwData;
-
publicintcbData;
- [MarshalAs(UnmanagedType.LPStr)]
-
publicstringlpData;
- }
-
publicclassUser32
- {
-
publicconstintWM_COPYDATA=0x4A;
-
publicconstintWM_DESTROY=0x0002;
-
publicconstintWM_QUERYENDSESSION=0x0011;
-
publicconstintWM_QUEUE_NOTIFY=0x401;
-
[DllImport("user32")]
-
publicstaticexternintPostMessage(IntPtrhwnd,intwMsg,intwParam,intlParam);
-
[DllImport("user32")]
-
publicstaticexternintRegisterWindowMessage(stringlpString);
-
[DllImport("user32")]
-
publicstaticexternintSendMessage(IntPtrhWnd,intMsg,
-
intwParam,refCOPYDATASTRUCTlParam);
-
publicstaticIntPtrHWND_BROADCAST
- {
-
get{return(IntPtr)0xFFFF;}
- }
- }
然后就要重写WndProc来接收处理窗体消息了:
-
protectedoverridevoidWndProc(refMessagem)
- {
-
if(m.Msg==attachMessage&
- m.WParam.ToInt32()!=0&
- m.WParam.ToInt32()!=thisHandle)
- {
-
if(m.LParam.ToInt32()==1)
-
User32.PostMessage(m.WParam,attachMessage,thisHandle,0);
-
if(m.LParam.ToInt32()==-1)
-
AttachWindows.Remove(m.WParam);
-
else
-
AttachWindows.Add(m.WParam);
- }
-
switch(m.Msg)
- {
-
caseUser32.WM_COPYDATA:
-
COPYDATASTRUCTcopyData=newCOPYDATASTRUCT();
- copyData=(COPYDATASTRUCT)m.GetLParam(copyData.GetType());
- MessageNotify(m.WParam.ToInt32(),copyData.lpData);
-
break;
-
caseUser32.WM_QUEUE_NOTIFY:
-
if(incomingMessageQueue.Count==0)
-
break;
- WindowsMessageEventArgstempArgs=incomingMessageQueue.Dequeue();
-
if(OnMessage!=null)
- OnMessage(thisHandle,tempArgs);
-
if(incomingMessageQueue.Count>0)
-
User32.PostMessage(this.Handle,User32.WM_QUEUE_NOTIFY,0,0);
-
break;
-
caseUser32.WM_QUERYENDSESSION:
-
caseUser32.WM_DESTROY:
- User32.PostMessage(User32.HWND_BROADCAST,
-
attachMessage,thisHandle,-1);
-
break;
- }
-
base.WndProc(refm);
- }
假如已经有窗体进程已经在运行,那么它就会收到新窗体起来时是所发送的“Connect”消息。上面的代码中第一个if就时处理这个消息的。首先会给消息发送者一个响应。然后会将发送者(窗体的句柄)保存到的列表AttachWindows中。
窗体后面部分就是真正处理通讯消息的部分了。MessageNotify方法首先将消息入队,接着给自己发送一个PostMessage通知自己处理,然后就马上返回。大家可能已经注意到WM_QUEUE_NOTIFY了,不错,这个就是通知自己处理消息的。“处理消息”的就是从消息队列中取出一个消息,将消息作为事件参数触发事件。子窗体只要订阅这个事件,并做处理即可。
上面已经把处理消息的过程讲完了,但还没看到发送消息的部分。下面马上给出。
还是先看代码吧,下面的代码是上面提到的MessageNotify方法及发送消息的方法SendMessage();
-
privatevoidMessageNotify(inttarget,stringmessage)
- {
-
incomingMessageQueue.Enqueue(newWindowsMessageEventArgs(target,message));
-
User32.PostMessage(this.Handle,User32.WM_QUEUE_NOTIFY,0,0);
- }
-
publicvoidSendMessage(inttarWin,stringmessage)
- {
-
if(!connected)
-
thrownewException("notconnected!");
-
byte[]bytes=System.Text.Encoding.UTF8.GetBytes(message);
-
intlength=bytes.Length;
-
COPYDATASTRUCTcopyData=newCOPYDATASTRUCT();
- copyData.dwData=(IntPtr)1;
- copyData.lpData=message;
- copyData.cbData=length+1;
- System.Threading.Thread.Sleep(100);
-
try
- {
-
User32.SendMessage((IntPtr)tarWin,User32.WM_COPYDATA,thisHandle,refcopyData);
- }
-
catch(Exceptione)
- {
-
thrownewException("windowssendmessageerror",e);
- }
- }
还有消息的参数类:
-
publicclassWindowsMessageEventArgs:EventArgs
- {
- [====Fields====]#region[====Fields====]
-
privateinttargetWinHandle;
-
privatestringdata;
-
#endregion
-
publicWindowsMessageEventArgs(inttargetWinHandle,stringdata)
- {
-
this.targetWinHandle=targetWinHandle;
-
this.data=data;
- }
- [====Properties====]#region[====Properties====]
-
///<summary>
-
-
-
publicintTargetWinHandle
- {
-
get{returntargetWinHandle;}
- }
-
publicstringData
- {
-
get{returndata;}
-
}
-
#endregion
子窗体只要从WinMsgData继承,并订阅消息事件:
base.OnMessage += new WinMsgData.WindowsMessageHandler(HandleMyMessage);
要发送消息的时候调用base.SendMessage(yourMessageToSend)就可以了。使用方便。
效果图:
分享到:
相关推荐
这个任务可以通过各种技术来实现,而“WPF窗体跨进程消息通讯简单Demo”正是一个这样的示例,它演示了如何在WPF应用中实现跨进程通信。以下将详细解析这个主题。 首先,我们要理解什么是跨进程通信(Inter-Process ...
Winform中实现进程间消息通讯,通常采用Windows消息队列(WM_COPYDATA)或者命名管道(Named Pipe)。WM_COPYDATA消息允许两个进程之间传递数据,通过`SendMessage`或`PostMessage`函数发送,接收方通过处理`WM_...
Socket是网络编程中的基本组件,它提供了进程间通信(IPC)的能力,尤其是跨网络的进程间通信。 首先,我们需要了解Socket的工作原理。Socket是网络通信的两端,可以理解为通信的两个端点。在C#中,我们可以使用...
- **消息队列**:进程间通过发送和接收消息进行通信,适合大量小数据的传递。 - **套接字**:网络通信的基础,也可用于同一机器上的进程间通信。 - **命名对象**:包括事件、信号量、互斥体等,用于进程间的同步...
【标题】"用C#编写的Winform通信程序"是一个基于C#开发的Windows桌面应用程序,主要用于实现点对点通信。...通过深入研究这个程序,你可以了解到如何在C#环境中实现UDP通信,以及如何处理数据的序列化和线程同步问题。
- **WSDL**(Web Services Description Language):一种XML格式的文件,用于描述Web服务的消息格式和通讯协议。 - **作用**: - UDDI提供了一个目录服务,帮助人们发现和集成Web服务。 - WSDL定义了服务的接口,...
在VB源码中实现文件映射,开发者需要深入理解Windows API,特别是关于内存管理和进程间通信的部分。 至于“okbase.net”,这可能是提供的示例代码或文档所在的网站,它可能包含了更多关于如何在VB中实现文件映射的...
Socket是网络通信的接口,它提供了进程间通信(IPC)和网络通信的能力。在TCP/IP协议栈中,Socket用于实现应用层与传输层的交互,提供TCP或UDP两种主要的通信协议。TCP提供面向连接的、可靠的通信,而UDP则是无连接...
命名管道是一种在Windows操作系统中实现进程间通信(IPC,Inter-Process Communication)的技术,它允许不同的进程之间交换数据。在C#中,命名管道提供了一种高效、可靠的通信方式,尤其适用于同一台计算机上的进程...
4. **AIDL(Android Interface Definition Language)**:对于复杂的跨进程通讯,Android提供了AIDL,允许定义进程间通信的接口。C#开发者需要理解和转换这些接口,以便在C#代码中使用。 5. **服务(Services)和...
在QQ机器人源码中,可能使用了如.NET框架提供的System.IO.Pipes或System.Net命名空间下的类来实现进程间的数据传输。通过进程通信,QQ机器人可以与其他应用程序交互,比如接收用户命令或者更新状态。 2. 消息机制:...
标题中的"C#版ErlangOtp跨平台通信框架(Java版的转译)"指的是一个用C#语言实现的框架,...这个框架的关键技术包括进程间通信(IPC)、序列化与反序列化、网络传输以及跨语言互操作性,这些都是实现跨平台通信所必需的。
在IT领域,尤其是在软件开发中,进程间通信(IPC,Inter-Process Communication)是一项至关重要的技术,它使得不同进程能够共享数据和协调工作。在Windows操作系统中,管道是一种常见的IPC方式,C#作为.NET框架的...
在TCP/IP协议栈中,Socket是网络通信的基础,它是进程间的通信端点,允许两个运行在不同机器上的程序通过网络交换数据。在MFC中,你可以使用CSocket类来处理TCP套接字操作。CSocket类提供了创建、连接、发送和接收...
Socket,通常称为套接字,是网络编程中的一个概念,它是进程间通信的一种方式,允许不同计算机上的进程通过网络交换数据。 “在VS2005环境下开发的”表明该软件是在Visual Studio 2005集成开发环境中编写的。Visual...
.NET Remoting是.NET框架中用于应用程序间通信的重要工具,它允许不同进程甚至不同计算机上的对象相互通信。在MiniChat中,Remoting可能被用于实现客户端与服务器之间的实时消息传递,使得用户能够迅速地发送和接收...
这个“winform Socket 聊天程序”是针对初学者的一个理想学习资源,它包含有源代码以及详细的注释,帮助理解Socket的工作原理和如何在Winform应用中实现。 首先,让我们来了解Socket的基本概念。Socket是操作系统...
3. **Socket通讯**:Socket是网络编程的基础,提供了进程间通信的能力,使得程序能够发送和接收数据。在C#中,使用System.Net.Sockets命名空间可以实现TCP或UDP通信,这对于开发网络应用或测试网络连接非常有用。 4...