C#进程间通讯--共享内存篇
上次发了利用发消息实现的C#进程间的通讯,这次又使用共享内存了,他们应用范围是不同的,共享内存适用于共享大量数据的情况。
const int INVALID_HANDLE_VALUE = -1; const int PAGE_READWRITE = 0x04; //共享内存 [DllImport("Kernel32.dll",EntryPoint="CreateFileMapping")] private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile, UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes, //0 UInt32 flProtect,//DWORD flProtect UInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh, UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow, string lpName//LPCTSTR lpName ); [DllImport("Kernel32.dll",EntryPoint="OpenFileMapping")] private static extern IntPtr OpenFileMapping( UInt32 dwDesiredAccess,//DWORD dwDesiredAccess, int bInheritHandle,//BOOL bInheritHandle, string lpName//LPCTSTR lpName ); const int FILE_MAP_ALL_ACCESS = 0x0002; const int FILE_MAP_WRITE = 0x0002; [DllImport("Kernel32.dll",EntryPoint="MapViewOfFile")] private static extern IntPtr MapViewOfFile( IntPtr hFileMappingObject,//HANDLE hFileMappingObject, UInt32 dwDesiredAccess,//DWORD dwDesiredAccess UInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh, UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow, UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap ); [DllImport("Kernel32.dll",EntryPoint="UnmapViewOfFile")] private static extern int UnmapViewOfFile(IntPtr lpBaseAddress); [DllImport("Kernel32.dll",EntryPoint="CloseHandle")] private static extern int CloseHandle(IntPtr hObject); 然后分别在AB两个进程中定义如下两个信号量及相关变量; private Semaphore m_Write; //可写的信号 private Semaphore m_Read; //可读的信号 private IntPtr handle; //文件句柄 private IntPtr addr; //共享内存地址 uint mapLength; //共享内存长
定义这两个信号量是为读写互斥用的。 在A进程中创建共享内存: m_Write = new Semaphore(1,1,"WriteMap"); m_Read = new Semaphore(0,1,"ReadMap"); mapLength = 1024; IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE); handle = CreateFileMapping(hFile,0,PAGE_READWRITE,0,mapLength,"shareMemory"); addr = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0); 然后再向共享内存中写入数据: m_Write.WaitOne(); byte[] sendStr = Encoding.Default.GetBytes(txtMsg.Text + '/0'); //如果要是超长的话,应另外处理,最好是分配足够的内存 if(sendStr.Length < mapLength) Copy(sendStr,addr); m_Read.Release(); 这是在一个单独的方法中实现的,可多次调用,但受信号量的控制。其中txtMsg是一个文本框控件,实际中可用任意字符串,加最后的'/0'是为了让在共享内存中的字符串有一个结束符,否则在内存中取出时是以'/0'为准的,就会出现取多的情况。 Copy方法的实现如下: static unsafe void Copy(byte[] byteSrc,IntPtr dst) { fixed (byte* pSrc = byteSrc) { byte* pDst = (byte*)dst; byte* psrc = pSrc; for(int i=0;i<byteSrc.Length;i++) { *pDst = *psrc; pDst++; psrc ++; } } } 注意unsafe 关键字,在编译时一定要打开非安全代码开关。 最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。 UnmapViewOfFile(addr); CloseHandle(handle); 要在B进程中读取共享内存中的数据,首先要打开共享内存对象: m_Write = Semaphore.OpenExisting("WriteMap"); m_Read = Semaphore.OpenExisting("ReadMap"); handle = OpenFileMapping(0x0002,0,"shareMemory"); 读取共享内存中的数据: m_Read.WaitOne(); string str = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0); txtMsg.Text = str; m_Write.Release(); 这里获取了字符串,如果要获取byte数组,请参考上面的Copy函数实现。
使用微软消息队列实现C#进程间通信 http://tech.ddvip.com/2007-11/119554606737754.html
在.NET中使用命名管道完成进程间通信