前段时间LED项目需要我和同事的两部分合并起来,他的程序是用VC写的,而我的程序是c#写的,由于我们数据需要通讯,苦思冥想终于想出的一个办法:内存共享及消息通讯。
首先我们之间制定了一些协议,规定了我们直接的通讯方式是通过发送不同的消息来执行对应的命令。比如说,我这边发送WM_CHIP的消息过去,然后他接收到这消息之后就执行相关操作,然后再给我反馈一个WM_NEXT的消息。
具体步骤如下:(C#代码)
public const int WM_USER = 0x400;
public const int WM_CHIPS = WM_USER + 101;
public const int WM_NO_CHIPS = WM_USER + 102;
.......
private IntPtr hFileMap;//共享内存句柄
private IntPtr address; //传输数据地址句柄
private IntPtr mesgptr; //对方应用程序的句柄
mesgptr = Win32.FindWindow(null, "程序名");//FindWindow和SendMessage为系统API函数,要DllImport声明
SendMessage(mesgptr, WM_XX, 0, 0);
接收的情况,需要重载DefWndProc函数:
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
switch (m.Msg)
{
case WM_XX://处理消息
break;
case WM_XX2:
break;
.......
default:
base.DefWndProc(ref m);//调用基类函数处理非自定义消息。
break;
}
}
内存共享即开辟一个共享的内存空间,让两个不同的程序可以在里面读写数据,共享的内存空间开辟一次即可,程序关闭时释放其内存。
//CreateFileMapping和MapViewOfFile为系统API函数,要DllImport声明
hFileMap= CreateFileMapping(Win32.InvalidHandleValue,
IntPtr.Zero, Win32.PAGE_READWRITE, 0, 0x100, "MYLEDSHARE");
if(hFileMap!=null)
{
address = WinMapViewOfFile(hFileMap, Win32.FILE_MAP_WRITE, 0, 0, IntPtr.Zero);
if(address==IntPtr.Zero)
{
MessageBox.Show("创建mapviewoffile出错");
return;
}
}
创建成功,address即为共享内存的地址(不知道该称为句柄还是指针,用法和指针差不多),然后调用Marshel的相关函数读写内存地址即可,如:
Marshal.WriteByte(address, i, (byte)(arr[i]));//写第i个字节数据进去共享内存,arr为数据内容,arr为char[]数组。
arr[i]=Marshal.ReadByte(address, i);//从内存里读第i个字节的数据并存到arr里。
测试过两个不同的程序实现消息和内存通讯所耗的时间少于1毫秒。
后记:这个技术已经成为历史,因为为了通讯的实时性,我的同事已经把他的程序改成用c#写了。写这篇东西是为了纪念一下当时学了这个看起来很高级的技术,呵呵。