Windows进程间通信之共享内存

之前自己做的一个项目涉及到进程间通信问题,我采用的是SOCKET方式。面试的时候有问过为什么不采用其他方式。好吧,其实发现共享内存更方便一点。于是自己写了一下,并且做了个测试界面。


程序启动会获得自身的窗口句柄,另外可以输入一个窗口句柄,用于进程间Windows消息通信。File Mapping Name实际上就是内核对象名,进程间依据这个来访问共享内存。

Windows下的共享内存实际是用文件映射实现的,可以用CreateFileMapping创建一个内存文件映射对象,用于映射文件到内存。该函数返回的是File Mapping Object句柄

CreateFileMappingA(
    __in     HANDLE hFile,
    __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
    __in     DWORD flProtect,
    __in     DWORD dwMaximumSizeHigh,
    __in     DWORD dwMaximumSizeLow,
    __in_opt LPCSTR lpName
    );

1)因为并不需要创建一个实际的文件,所以把hFile设置成为0xFFFFFFFF(INVALID_HANDLE_VALUE)就行了。

2)Windows支持64位的文件,但一般内存不会超过4G也就是32位文件就够用了,所以上面的参数当中,dwMaximumSizeHigh为0,dwMaximumSizeLow设置为需要开辟的内存大小。

3)lpName用于标示这段内存,进程间通过这个标示访问这段内存。


接着调用MapViewOfFile()映射到当前进程的虚拟地址上。该函数如果调用成功,返回映射文件的开始地址。如果失败为NULL。

MapViewOfFile(
    __in HANDLE hFileMappingObject,
    __in DWORD dwDesiredAccess,
    __in DWORD dwFileOffsetHigh,
    __in DWORD dwFileOffsetLow,
    __in SIZE_T dwNumberOfBytesToMap
    );


1)hFileMappingObject就是刚才调用CreateFileMapping返回的句柄。

2)dwDesiredAccess设置为FILE_MAP_ALL_ACCESS。

3)dwNumberOfBytesToMap,文件中要映射的字节数,也就是这块共享内存的大小。


我的程序是这么调用它的。

int Cp1Dlg::MapFile()
{
	CString str;
	m_edit7.GetWindowTextA(str);
	if(str.GetLength() == 0)
	{
		AfxMessageBox("File Mapping Name can't be NULL");
		return -1;
	}
	m_hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE,
		NULL,
		PAGE_READWRITE,
		0,
		BUF_SIZE,
		str.GetBuffer());
	if(m_hMapFile == NULL)
	{
		AfxMessageBox("CreateFileMapping failed!");
		return 1;
	}
	m_pBuf = static_cast<LPTSTR>(MapViewOfFile(
		m_hMapFile,
		FILE_MAP_ALL_ACCESS,
		0,
		0,
		BUF_SIZE));
	if(m_pBuf == NULL)
	{
		AfxMessageBox("MapViewOfFile failed!");
		CloseHandle(m_hMapFile);
		return 1;
	}
	return 0;
}


接下来就可以对m_pBuf进行写数据或者读数据了。

写数据:

m_edit6.GetWindowTextA(str);
memcpy((void*)m_pBuf, str.GetBuffer(), str.GetLength());

读数据:

LRESULT Cp1Dlg::OnMsg3(WPARAM wParam, LPARAM lParam){
	CString str;
	str.Format("R:\t%s", m_pBuf);
	m_list2.AddString(str);
	memset((void*)m_pBuf, 0, BUF_SIZE);//读完之后对这块内存进行清零
	return 0;
}

读数据我采用的是消息处理函数。因为当一个进程对内存完数据之后,我会发送一个Windows消息通知另一进程,在其收到这条消息后就会调用函数读取数据。

比起SOCKET,的确挺方便的。但是如果两个进程同时对这块内存进行写数据该怎么办呢?这就涉及到进程间同步技术了。不过这个我没有做。

把资源打包上传了。



原文地址:https://www.cnblogs.com/javawebsoa/p/3076915.html