.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)就可以了。使用方便。
效果图:
分享到:
相关推荐
ADO.NET自己封装SqlHelper类 1、简单封装 2、传递参数封装 3、参数可变封装
对文件的操作 .net中封装文件操作 把内容封装起来更容易,操作节省代码!
Windows Api 的 .NET 封装,从微软的 .NET 基础类库中提取出来的,方便大家在 C# .NET 中调用 Windows API.
ASP.NET c# 封装常用到的js通用函数ASP.NET c# 封装常用到的js通用函数ASP.NET c# 封装常用到的js通用函数ASP.NET c# 封装常用到的js通用函数ASP.NET c# 封装常用到的js通用函数ASP.NET c# 封装常用到的js通用函数
Linux下提供了多种共享内存的通讯机制,常用...1:使用进程间的互斥锁,实现了共享内存共享数据的互斥访问问题 2:有效数据部分,通过分配器来管理内存的开辟和释放 3:实现了一对多的模型(一端发送,多端接收的模型)
使用.net 程序集 对windows api 的封装,包含 user32,kernel32 等核心api,便于.net开发者使用 windowsAPI
封装Dapper dbContext类,对Dapper 的增删查改进行封装
教学示范代码 ADO.NET分页封装[支持多表连接查询分页]-代码实现
ASP.NET封装功能整理
别个工作几年的程序员封装的数据库访问类,蛮不错的!和BLL层完全分离,可以轻松的修改以访问Oracle和MySql. 保证你下了不得骂我就行咯……
可以来看看,asp.net分页封装源码结合存储过程
对StackExchange.Redis.dll的Redis封装类,抽象一个接口ICacheStorageProvider作为公共缓存接口,具有增,删,改的功能接口
上期技术CTP行情及交易接口.Net封装 本次更新到CTP官方库20120530版本,增加了Multiple AppDomain支持
上期技术CTP行情交易接口.Net封装完整版 CTP.dll 将非托管C++库转换为托管库,供.Net程序调用。包括行情接口和交易接口。 Struct.h头文件修改自海风版C#的Struct.cs文件,非常感谢! CSharpMdTest C#行情接口测试...
百度UEditor控件的asp.net控件封装
.net5 dapper封装操作数据库
直接从数据库中取出字段进行封装成一个类!不用为封装很多的字段而发愁!
此程序基于Visual studio 2005 英文版,主要是为了示例.net中用oledb方式对数据库操作(增删查改)的封装,包括了所有源码,适合入门者,我已调试无误(其中我基本上未进行容错处理,因为此程序的主要目的是对数据库的...
.NET 下最好的 Windows DirectShow 开源封装。 DirectShow.NET LIB 库。 关健字:DirectShow C#.NET 音视频 WINDOWS 视频采集 视频回放
使用.net 程序集 对windows api 的封装,包含 user32,kernel32 等核心api,便于.net开发者使用 windowsAPI