进程通讯:如何实现win9X进程间数据通讯技术来源: 发布时间:星期二, 2008年12月30日 浏览:2次 评论:0
1、引言
在Windows中各个进程的间常常需要交换数据进行数据通讯WIN32 API提供了许多使我们能够方便高效地进行进程间通讯通过这些我们可以控制区别进程间数据交换就如同在WIN16中对本地进程进行读写操作样 典型WIN16两进程可以通过共享内存来进行数据交换: (1)进程A将GlobalAlloc(GMEM_SHARE...)API分配定长度内存;(2)进程A将GlobalAlloc返回句柄传递给进程B(通过个登录消息);(3)进程B对这个句柄GlobalLock并利用GlobalLock返回指针访问数据这种思路方法在WIN32中可能失败这是GlobalLock返回指向是进程A内存由于进程使用是虚拟地址而非实际物理地址因此这指针仅和A进程有关而于B进程无关 本文探讨了几种WIN32下进程的间通讯几种实现思路方法读者可以使用区别方 法以达到运行高效可靠目 2、Windows95中进程内存空间管理 WIN32进程间通讯和Windows95内存管理有密切关系理解Windows95内存管理对我们如下设计将会有很大帮助下面我们讨论以下Windows95中进程内存空间管理 在WIN16下所有Windows应用共享单地址任何进程都能够对这空间中属于共享单地址空间和属于其他进程内存进行读写操作甚至可以存取操作系统本身数据这样就可能破坏其他数据段代码 在WIN32下每个进程都有自己地址空间个WIN32进程不能存取另个地 址私有数据两个进程可以用具有相同值指针寻址但所读写只是它们各自 数据这样就减少了进程的间相互干扰另方面每个WIN32进程拥有4GB 地址空间但并不代表它真正拥有4GB实际物理内存而只是操作系统利用CPU 内存分配功能提供虚拟地址空间在般情况下绝大多数虚拟地址并没有物理 内存和它对应在真正可以使用这些地址空间的前还要由操作系统提供实际物 理内存(这个过程叫“提交”commit)在区别情况下系统提交 物理内存是区别可能是RAM也可能是硬盘模拟虚拟内存 3、WIN32中进程间通讯 在Windows 95中为实现进程间平等数据交换用户可以有如下几种选择: * 使用内存映射文件 * 通过共享内存DLL共享内存 * 向另进程发送WM_COPYDATA消息 * ReadProcessMemory以及WriteProcessMemory用户可以发送由 GlobalLock(GMEM_SHARE,...)提取句柄、GlobalLock返回指针以 及VirtualAlloc返回指针 3.1、利用内存映射文件实现WIN32进程间通讯 Windows95中内存映射文件机制为我们高效地操作文件提供了种途径 它允许我们在WIN32进程中保留段内存区域把目标文件映射到这段虚拟内存中 在实现中必须考虑各进程的间同步具体实现步骤如下: 首先我们在发送数据进程中需要通过内存映射APICreateFileMapping 创建个有名共享内存: HANDLE CreateFileMapping( HANDLE hFile, // 映射文件句柄 //设为0xFFFFFFFF以创建个进程间共享对象 LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 安全属性 DWORD flProtect, // 保护方式 DWORD dwMaximumSizeHigh, //对象大小 DWORD dwMaximumSizeLow, LPCTSTR lpName // 必须为映射文件命名 ); 和虚拟内存类似保护方式可以是PAGE_READONLY或是PAGE_READWRITE如果多进程都对同共享内存进行写访问则必须保持相互间同步映射文件还可以指定PAGE_WRITECOPY标志可以保证其原始数据不会遭到破坏同时允许其他进程在必要时自由地操作数据拷贝 在创建文件映射对象后使用可以MapViewOfFile映射到本进程地址空间内 下面介绍说明创建个名为MySharedMem长度为4096字节有名映射文件: HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF) NULLPAGE_READWRITE00x1000“MySharedMem”); 并映射缓存Cache区视图: LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFile FILE_MAP_READ|FILE_MAP_WRITE000); 其他进程访问共享对象需要获得对象名并OpenFileMapping HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITE FALSE“MySharedMem"); 旦其他进程获得映射对象句柄可以像创建进程那样MapViewOfFile来映射对象视图用户可以使用该对象视图来进行数据读写操作以达到数据通讯目 当用户进程结束使用共享内存后UnmapViewOfFile以取消其地址空间内视图: (!UnmapViewOfFile(pszMySharedMap View)) { AfxMessageBox(“could not unmap view of file"); } 3.2、利用共享内存DLL 共享数据DLL允许进程以类似于Windows 3.1 DLL共享数据方式访问读写数据多个进程都可以对该共享数据DLL进行数据操作达到共享数据目在WIN32中为建立共享内存必须执行以下步骤: 首先创建个有名数据区这在Visual C++中是使用data_seg pragma宏 使用data_seg pragma宏必须注意数据化: #pragma data_seg(“MYSEC") char MySharedData[4096]={0}; #pragma data_seg 然后在用户DEF文件中为有名数据区设定共享属性 LIBRARY TEST DATA READ WRITE SECTIONS .MYSEC READ WRITE SHARED 这样每个附属于DLL进程都将接受到属于自己数据拷贝个进程数据 变化并不会反映到其他进程数据中 在DEF文件中适当地输出数据以下DEF文件项介绍说明了如何以常数变量形式 输出MySharedData EXPORTS MySharedData CONSTANT 最后在应用(进程)按外部变量引用共享数据 extern _export"C"{char * MySharedData} 进程中使用该变量应注意间接引用 m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED); m_pStatic->GetLine(0,*MySharedData,80); 3.3、用于传输只读数据WM_COPYDATA 传输只读数据可以使用Win32中WM_COPYDATA消息该消息主要目是允许在进程间传递只读数据Windows95在通过WM_COPYDATA消息传递期间不提供继承同步方式SDK文档推荐用户使用SendMessage接受方在数据拷贝完成前不返回这样发送方就不可能删除和修改数据: SendMessage(hwnd,WM_COPYDATA,wPara m,lParam); 其中wParam设置为包含数据窗口句柄lParam指向个COPYDATASTRUCT结构: typedef struct tagCOPYDATASTRUCT{ DWORD dwData;//用户定义数据 DWORD cbData;//数据大小 PVOID lpData;//指向数据指针 }COPYDATASTRUCT; 该结构用来定义用户数据 3.4、直接ReadProcessMemory和WriteProcessMemory实现进程间通讯 通过ReadProcessMemory以及WriteProcessMemory用户可以按类似和Windows3.1思路方法实现进程间通讯在发送进程中分配块内存存放数据可以GlobalAlloc或者VirtualAlloc实现: pApp→m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024); 可以得到指针地址:pApp→mpszGlobalHandlePtr=(LPSTR)GlobalLock(pApp→m_hGlobalHandle); 在接收进程中要用到用户希望影响进程打开句柄为了读写另进程应 按如下方式OpenProcess: HANDLE hTargetProcess=OpenProcess( STANDARD_RIGHTS_REQUIRED| PROCESS_VM_REDA| PROCESS_VM_WRITE| PROCESS_VM_OPERATION,//访问权限 FALSE,//继承关系 dwProcessID);//进程ID 为保证OpenProcess成功用户所影响进程必须由上述标志创建 旦用户获得个进程有效句柄就可以ReadProcessMemory读取该 进程内存: BOOL ReadProcessMemory( HANDLE hProcess, // 进程指针 LPCVOID lpBaseAddress, // 数据块首地址 LPVOID lpBuffer, // 读取数据所需缓冲区 DWORD cbRead, // 要读取字节数 LPDWORD lpNumberOfBytesRead ); 使用同样句柄也可以写入该进程内存: BOOL WriteProcessMemory( HANDLE hProcess, // 进程指针 LPVOID lpBaseAddress, // 要写入首地址 LPVOID lpBuffer, // 缓冲区地址 DWORD cbWrite, // 要写字节数 LPDWORD lpNumberOfBytesWritten ); 如下所示是读写另进程共享内存中数据: ReadProcessMemory((HANDLE)hTargetProcess,(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD), _MAX_FIELD,&cb); WriteProcessMemory((HANDLE)hTargetProcess,(LPSTR)lpsz,(LPSTR)STARS, m_strGlobal.GetLength,&cb); 4、进程的间消息发送和接收 在实际应用中进程的间需要发送和接收Windows消息来通知进程间相互通讯 发送方发送通讯消息以通知接收方接收方在收到发送方消息后就可以对内 存进行读写操作 我们在设计中采用Windows注册消息进行消息传递首先在发送进程 化过程中进行消息注册: m_nMsgMapped=::RegisterWindowsMessage(“Mapped”); m_nMsgHandle=::RegisterWindowsMessage(“Handle”); m_nMsgShared=::RegisterWindowsMessage(“Shared”); 在运行中向接收进程发送消息: CWnd* pWndRecv=FindWindow(lpClassName,“Receive”); pWndRecv→SendMessage(m_MsgMapped,0,0); pWndRecv→SendMessage(m_nMsgHandle,(UINT)GetCurrentProcessID,(LONG)pApp→m_hGlobalHandle); pWndRecv→SendMessage(m_nMsgShared,0,0); 可以按如下方式发送WM_COPYDATA消息: COPYDATASTRUCT cds;//用户存放数据pWnd→SendMessage(WM_COPYDATA,NULL,(LONG)&cds); 接收方进程化也必须进行消息注册: UNIT CRecvApp:: m_nMsgMapped=::RegisterWindowsMessage(“Mapped”); UNIT CRecvApp::m_nMsgHandle=::RegisterWindowsMessage(“Handle”); UNIT CRecvApp::m_nMsgShared=::RegisterWindowsMessage(“Shared”); 同时映射消息如下: ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnRegMsgMapped) ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnRegMsgHandle) ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnRegMsgShared) 有这些消息我们就可以采用上述技术实现接收进程中数据读写操作了 5、结束语 从以上分析中我们可以看出Windows9X内存管理对进程的间通讯有较为严 格限制这就确保了任何故障无法意外地写入用户地址空间而用户则可 根据实际情况灵活地进行进程间数据通讯从这点上来讲Windows95增强了应用 强壮性 0
相关文章
读者评论
发表评论 |