(文章转载请说明出处和作者)
常用进程间共享数据方法:
- 通过共享DLL
- 通过内存映射文件
- 向另一进程发送WM_COPYDATA消息
今天主要介绍“通过共享DLL”来达到进程间共享数据,其他两种方式留在其他章节讲解。在Win32环境下,当进程启动时操作系统会为该进程分配4GB的虚拟内存,然后分析进程模块,为模块所需要的DLL创建虚拟内存,最后将DLL虚拟内存(含有代码页和数据页)中的代码页和数据页映射到进程地址空间。当另一进程也要加载此DLL时,系统不需要为DLL重新创建虚拟内存只需将DLL虚拟内存中的代码页和数据页也映射到该进程,这样也节省了内存。当进程修改DLL中的数据时,操作系统会进行写入时拷贝(该进程得到DLL的数据是拷贝后修改的数据),另一个进程访问时还是DLL中原来的数据,这是win2000系统对DLL中可写入数据的保护。那么我们要在进程间共享数据可以通过命令[#prama data_seg()创建共享节来完成。
关于节创建的格式:
#pragma data_seg(".MySec")//MySec节的名字(不超过8个字符)
char g_pMsg[6] = {0};//节中的数据
#pragma data_seg()
#pragma comment(linker,"/section:.MySec,rws")//设置节的属性
其中最后一句设置节属性:
#pragma comment(linker,"/section:.MySec,rws")
的另一种形式是在模块文件(.DEF)中加入:
SEGMENTS
.MySec READ WRITE SHARED
节中数据注意点:
- 必须初始化
- 节中数据的多少直接影响DLL的大小(节中数据不宜过多)
- 不要存放进程相关信息(Win32种这些数据只在特定环境下有效)
- 不要存放地址(同一地址在不同进程中的情况是不一致的,会有不可预知的错误)
实例代码:
下面我来创建一个带有共享节的DLL来演示一下进程间通信:
- 创建Win32DLL,工程名:DllShare
- DllShare.cpp代码如下
// DllShare.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include <stdlib.h> #pragma data_seg(".MySec") char g_pMsg[6] = {0}; #pragma data_seg() //#pragma comment(linker,"/section:.MySec,rws")//设置节属性放在了模块文件中 BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } BOOL __stdcall SetMsg() { strcpy(g_pMsg, "Hello"); return TRUE; } BOOL __stdcall GetMsg(char **pMsg) { *pMsg = g_pMsg; return TRUE; }
- DllShare.def代码如下:
LIBRARY DllShare EXPORTS SetMsg GetMsg SEGMENTS .MySec READ WRITE SHARED
- 编译生成动态库DllShare.dll
- 创建对话框测试程序:DllShareTest
- 关键代码如下:
__declspec(dllimport) BOOL __stdcall SetMsg(); __declspec(dllimport) BOOL __stdcall GetMsg(char **pMsg); void CDllShareTestDlg::OnSetMsg() { // TODO: Add your control notification handler code here if(SetMsg()) { MessageBox("设置Msg成功!"); } } void CDllShareTestDlg::OnGetMsg() { // TODO: Add your control notification handler code here char *pMsg = NULL; if(GetMsg(&pMsg)) { MessageBox(LPCTSTR(pMsg)); } }
- 运行结果图: