上次發了利用發消息實現的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中使用命名管道完成進程間通信