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中使用命名管道完成進程間通信

http://www.hackhome.com/InfoView/Article_121029_2.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM