首先还是定义非托管调用,如下:
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);
private Semaphore m_Write; //可写的信号
private Semaphore m_Read; //可读的信号
private IntPtr handle; //文件句柄
private IntPtr addr; //共享内存地址
uint mapLength; //共享内存长
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_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();
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 ++;
}
}
}
{
fixed (byte* pSrc = byteSrc)
{
byte* pDst = (byte*)dst;
byte* psrc = pSrc;
for(int i=0;i<byteSrc.Length;i++)
{
*pDst = *psrc;
pDst++;
psrc ++;
}
}
}
最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。
UnmapViewOfFile(addr);
CloseHandle(handle);
CloseHandle(handle);
要在B进程中读取共享内存中的数据,首先要打开共享内存对象:
m_Write = Semaphore.OpenExisting("WriteMap");
m_Read = Semaphore.OpenExisting("ReadMap");
handle = OpenFileMapping(0x0002,0,"shareMemory");
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();
string str = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);
txtMsg.Text = str;
m_Write.Release();