在WINCE开发中经常需要在不同的进程之间传递、共享数据,总结了一下,WINCE下进程间通信常用的方式有:Windows消息,共享内存,socket通信,管道,全局原子,邮槽等,下面就分别对这几种方法做个小结。(当然还可以采用注册表,磁盘文件以及数据库方式,只是这几种方式的通信效率和实时性比较低,所以一般不考虑。)
一、Windows消息
通过Windows消息,可以很方便的在进程与进程之间传递数据。对于传递像字符串这种小的数据,可以直接将字符串以消息参数wParam、lParam的方式传递给其他进程,对于大一点的数据,可以采用发送WM_COPYDATA消息,参考代码如下:
void SendMsg(HWND hwnd,LPVOID lpData,DWORD dwSize) { // 填充COPYDATASTRUCT结构 COPYDATASTRUCT cpd; cpd.cbData = dwSize; cpd.lpData = lpData; // 向指定窗口发送WM_COPYDATA消息,不能用PostMessage方式发送 ::SendMessage(hwnd, WM_COPYDATA, NULL,(LPARAM)&cpd); } // 发送端 TCHAR *data=_T("要发送的内容"); SendMsg(::FindWindow(NULL,_T("processB")),(void*)data,_tcslen(data)*2);
在接收端的窗口过程处理函数中添加对WM_COPYDATA消息的处理LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; TCHAR data[256]={0}; switch (message) { case WM_COPYDATA: { COPYDATASTRUCT *pCopyDataStruct=(COPYDATASTRUCT *)lParam; memcpy(data,pCopyDataStruct->lpData,pCopyDataStruct->cbData); } break; // ... } return DefWindowProc(hWnd, message, wParam, lParam); }
需要注意的是在发送数据量较大且数据交换频繁的时候通过发送WM_COPYDATA消息是不可取的,因为当数据传输过于频繁时将有可能导致数据的丢失。
二、共享内存
共享内存顾名思义是在内存中创建一个公共区域,供不同的进程间的数据共享。因为是直接对内存进行读写操作,效率非常高,所以共享内存特别适用于大批量的数据传输且实时性要求比较高的场合。
具体操作步骤如下:
1.进程A调用CreateFileMapping创建一个内存映射文件。
2.进程A调用MapViewOfFile获取到映射到文件的内存起始地址,调用memcpy往内存中拷贝数据。
3.进程B调用CreateFileMapping打开进程A创建的内存映射文件。
4.进程B调用MapViewOfFile获取到映射到文件的内存起始地址,调用memcpy从内存中读出数据。
5.通信完后进程A,B分别调用UnmapViewOfFile,CloseHandle取消内存映射和关闭内存映射对象句柄。
为了简化操作,这里封装了一个共享内存操作类,参考代码如下:
头文件CShareMemory.h:
/******************************************************************* filename: CShareMemory.h purpose: 封装了共享内存操作类 author: firehood created: 2011.03.16 ********************************************************************/ #ifndef _SHARE_MEMORY_H #define _SHARE_MEMORY_H class CShareMemory { public: CShareMemory(); ~CShareMemory(); public: /********************************************************** 函数名:Open 功能: 创建或打开内存映射文件 参数: [in]szMapName: 要创建的共享内存名称 [in]dwSize: 创建共享内存的大小 返回值: 0: 失败 1: 创建成功 2: 文件已存在 ***********************************************************/ DWORD Open(LPCTSTR szMapName,DWORD dwSize); /********************************************************** 函数名:Read 功能: 从共享内存指定位置读取数据 参数: [out]pBuf: 存放读取的数据 [in]dwSize: 读取数据的大小 [in]dwOffset 距共享内存起始位置的偏移量 返回值: TRUE: 成功 FALSE:失败 ***********************************************************/ BOOL Read(void* pBuf,DWORD dwSize,DWORD dwOffset = 0); /********************************************************** 函数名:Write 功能: 从共享内存指定位置写入数据 参数: [in]pBuf: 待写入的数据指针 [in]dwSize: 写入数据的大小 [in]dwOffset 距共享内存起始位置的偏移量 返回值: TRUE: 失败 FALSE:失败 ***********************************************************/ BOOL Write(const void* pBuf,DWORD dwSize,DWORD dwOffset = 0); void Close(void); private: HANDLE m_hShareMemory; LPVOID m_pMapBuffer; HANDLE m_hAccessMutex; }; #endif
源文件CShareMemory.cpp:
#include "stdafx.h" #include "CShareMemory.h" CShareMemory::CShareMemory() { m_hShareMemory = NULL; m_pMapBuffer = NULL; m_hAccessMutex =NULL; } CShareMemory::~CShareMemory() { Close(); } DWORD CShareMemory::Open(LPCTSTR szMapName,DWORD dwSize) { DWORD dwRet = 1; if(szMapName == NULL) return 0; if(m_hShareMemory) { Close(); } // 创建内存映射文件对象 m_hShareMemory = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,dwSize,szMapName); if(!m_hShareMemory) { return 0; } // 内存映射文件对象已存在 if(GetLastError() == ERROR_ALREADY_EXISTS) { dwRet = 2; } // 获取内存映射文件指针 m_pMapBuffer = MapViewOfFile(m_hShareMemory,FILE_MAP_ALL_ACCESS,0,0,0); if(!m_pMapBuffer) { CloseHandle(m_hShareMemory); return 0; } // 创建互斥体,用于读写同步 TCHAR szMutexName[MAX_PATH]; _tcscpy(szMutexName, szMapName); _tcscat(szMutexName, _T("_Mutex")); m_hAccessMutex=CreateMutex(NULL, FALSE, szMutexName); if(!m_hAccessMutex) { Close(); return 0; } return dwRet; } BOOL CShareMemory::Read(void* pBuf,DWORD dwSize,DWORD dwOffset) { BOOL bRet; if(!m_pMapBuffer) return FALSE; if(WaitForSingleObject(m_hAccessMutex,INFINITE)==WAIT_OBJECT_0) { memcpy(pBuf,(BYTE*)m_pMapBuffer+dwOffset,dwSize); bRet = TRUE; } ReleaseMutex(m_hAccessMutex); return bRet; } BOOL CShareMemory::Write(const void* pBuf,DWORD dwSize,DWORD dwOffset) { BOOL bRet; if(!m_pMapBuffer) return FALSE; if(WaitForSingleObject(m_hAccessMutex,INFINITE)==WAIT_OBJECT_0) { memcpy((BYTE*)m_pMapBuffer+dwOffset,pBuf,dwSize); bRet = TRUE; } ReleaseMutex(m_hAccessMutex); return TRUE; } void CShareMemory::Close(void) { if(m_hShareMemory) { UnmapViewOfFile(m_pMapBuffer); CloseHandle(m_hShareMemory); m_pMapBuffer = NULL; m_hShareMemory = NULL; } if(m_hAccessMutex) { CloseHandle(m_hAccessMutex); m_hAccessMutex = NULL; } }