WINCE下进程间通信(一)

在WINCE开发中经常需要在不同的进程之间传递、共享数据,总结了一下,WINCE下进程间通信常用的方式有:Windows消息,共享内存,socket通信,管道,全局原子,邮槽等,下面就分别对这几种方法做个小结。(当然还可以采用注册表,磁盘文件以及数据库方式,只是这几种方式的通信效率和实时性比较低,所以一般不考虑。)

一、Windows消息

通过Windows消息,可以很方便的在进程与进程之间传递数据。对于传递像字符串这种小的数据,可以直接将字符串以消息参数wParam、lParam的方式传递给其他进程,对于大一点的数据,可以采用发送WM_COPYDATA消息,参考代码如下:

  1. void SendMsg(HWND hwnd,LPVOID lpData,DWORD dwSize)
  2. {
  3. // 填充COPYDATASTRUCT结构
  4. COPYDATASTRUCT cpd;
  5. cpd.cbData = dwSize;
  6. cpd.lpData = lpData;
  7. // 向指定窗口发送WM_COPYDATA消息,不能用PostMessage方式发送
  8. ::SendMessage(hwnd, WM_COPYDATA, NULL,(LPARAM)&cpd);
  9. }
  10. // 发送端
  11. TCHAR *data=_T("要发送的内容");
  12. SendMsg(::FindWindow(NULL,_T("processB")),(void*)data,_tcslen(data)*2);

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消息的处理

  1. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {
  3. PAINTSTRUCT ps;
  4. HDC hdc;
  5. TCHAR data[256]={0};
  6. switch (message)
  7. {
  8. case WM_COPYDATA:
  9. {
  10. COPYDATASTRUCT *pCopyDataStruct=(COPYDATASTRUCT *)lParam;
  11. memcpy(data,pCopyDataStruct->lpData,pCopyDataStruct->cbData);
  12. }
  13. break;
  14. // ...
  15. }
  16. return DefWindowProc(hWnd, message, wParam, lParam);
  17. }

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:

  1. /*******************************************************************
  2. filename: CShareMemory.h
  3. purpose:   封装了共享内存操作类
  4. author:    firehood
  5. created:   2011.03.16
  6. ********************************************************************/
  7. #ifndef _SHARE_MEMORY_H
  8. #define _SHARE_MEMORY_H
  9. class CShareMemory
  10. {
  11. public:
  12. CShareMemory();
  13. ~CShareMemory();
  14. public:
  15. /**********************************************************
  16. 函数名:Open
  17. 功能:  创建或打开内存映射文件
  18. 参数:
  19. [in]szMapName:      要创建的共享内存名称
  20. [in]dwSize:         创建共享内存的大小
  21. 返回值:
  22. 0:      失败
  23. 1:      创建成功
  24. 2:      文件已存在
  25. ***********************************************************/
  26. DWORD Open(LPCTSTR szMapName,DWORD dwSize);
  27. /**********************************************************
  28. 函数名:Read
  29. 功能:  从共享内存指定位置读取数据
  30. 参数:
  31. [out]pBuf:          存放读取的数据
  32. [in]dwSize:         读取数据的大小
  33. [in]dwOffset        距共享内存起始位置的偏移量
  34. 返回值:
  35. TRUE: 成功 FALSE:失败
  36. ***********************************************************/
  37. BOOL Read(void* pBuf,DWORD dwSize,DWORD dwOffset = 0);
  38. /**********************************************************
  39. 函数名:Write
  40. 功能:  从共享内存指定位置写入数据
  41. 参数:
  42. [in]pBuf:           待写入的数据指针
  43. [in]dwSize:         写入数据的大小
  44. [in]dwOffset        距共享内存起始位置的偏移量
  45. 返回值:
  46. TRUE: 失败 FALSE:失败
  47. ***********************************************************/
  48. BOOL Write(const void* pBuf,DWORD dwSize,DWORD dwOffset = 0);
  49. void Close(void);
  50. private:
  51. HANDLE m_hShareMemory;
  52. LPVOID m_pMapBuffer;
  53. HANDLE m_hAccessMutex;
  54. };
  55. #endif

/*******************************************************************
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:

  1. #include "stdafx.h"
  2. #include "CShareMemory.h"
  3. CShareMemory::CShareMemory()
  4. {
  5. m_hShareMemory = NULL;
  6. m_pMapBuffer = NULL;
  7. m_hAccessMutex =NULL;
  8. }
  9. CShareMemory::~CShareMemory()
  10. {
  11. Close();
  12. }
  13. DWORD CShareMemory::Open(LPCTSTR szMapName,DWORD dwSize)
  14. {
  15. DWORD dwRet = 1;
  16. if(szMapName == NULL)
  17. return 0;
  18. if(m_hShareMemory)
  19. {
  20. Close();
  21. }
  22. // 创建内存映射文件对象
  23. m_hShareMemory = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,dwSize,szMapName);
  24. if(!m_hShareMemory)
  25. {
  26. return 0;
  27. }
  28. // 内存映射文件对象已存在
  29. if(GetLastError() == ERROR_ALREADY_EXISTS)
  30. {
  31. dwRet = 2;
  32. }
  33. // 获取内存映射文件指针
  34. m_pMapBuffer = MapViewOfFile(m_hShareMemory,FILE_MAP_ALL_ACCESS,0,0,0);
  35. if(!m_pMapBuffer)
  36. {
  37. CloseHandle(m_hShareMemory);
  38. return 0;
  39. }
  40. // 创建互斥体,用于读写同步
  41. TCHAR szMutexName[MAX_PATH];
  42. _tcscpy(szMutexName, szMapName);
  43. _tcscat(szMutexName, _T("_Mutex"));
  44. m_hAccessMutex=CreateMutex(NULL, FALSE, szMutexName);
  45. if(!m_hAccessMutex)
  46. {
  47. Close();
  48. return 0;
  49. }
  50. return dwRet;
  51. }
  52. BOOL CShareMemory::Read(void* pBuf,DWORD dwSize,DWORD dwOffset)
  53. {
  54. BOOL bRet;
  55. if(!m_pMapBuffer) return FALSE;
  56. if(WaitForSingleObject(m_hAccessMutex,INFINITE)==WAIT_OBJECT_0)
  57. {
  58. memcpy(pBuf,(BYTE*)m_pMapBuffer+dwOffset,dwSize);
  59. bRet = TRUE;
  60. }
  61. ReleaseMutex(m_hAccessMutex);
  62. return bRet;
  63. }
  64. BOOL CShareMemory::Write(const void* pBuf,DWORD dwSize,DWORD dwOffset)
  65. {
  66. BOOL bRet;
  67. if(!m_pMapBuffer) return FALSE;
  68. if(WaitForSingleObject(m_hAccessMutex,INFINITE)==WAIT_OBJECT_0)
  69. {
  70. memcpy((BYTE*)m_pMapBuffer+dwOffset,pBuf,dwSize);
  71. bRet = TRUE;
  72. }
  73. ReleaseMutex(m_hAccessMutex);
  74. return TRUE;
  75. }
  76. void CShareMemory::Close(void)
  77. {
  78. if(m_hShareMemory)
  79. {
  80. UnmapViewOfFile(m_pMapBuffer);
  81. CloseHandle(m_hShareMemory);
  82. m_pMapBuffer = NULL;
  83. m_hShareMemory = NULL;
  84. }
  85. if(m_hAccessMutex)
  86. {
  87. CloseHandle(m_hAccessMutex);
  88. m_hAccessMutex = NULL;
  89. }
  90. }

WINCE下进程间通信(一)的更多相关文章

  1. WINCE下进程间通信(二)

    WINCE下进程间通信(二) 接着前面的文章<WINCE下进程间通信(一)>,现在介绍进程间通信的另一种方法. 三.管道(消息队列) WINCE并不支持类似于PC机上匿名管道.命名管道的通 ...

  2. WinCE下读取注册表获得SD路径

    WinCE下读取注册表获得SD路径 [要点]WinCE注册表中[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory\] 下键Folde ...

  3. WinCE下GPRS自动拨号软件(GPRS AutoDial)

    之前在WinCE下调试USB的3G Modem时,写过一个拨号助手RASManager,基本能用.后来车机卖到俄罗斯去,客户老M提供了一个更好的GPRS自动拨号软件GPRS AutoDial,功能完善 ...

  4. Wince下sqlce数据库开发(二)

    上次写到使用数据绑定的方法测试本地sqlce数据库,这次使用访问SQL Server的方法访问sqlce,你会发现他们是如此的相似... 参考资料:http://www.cnblogs.com/rai ...

  5. Wince下sqlce数据库开发(一)

    对于Wince下的sqlce数据库虽然很多人在用,但在我查找资料时,却发现资料是多么的匮乏,在此对自己这几天的了解做个简单介绍,希望对大家能有所帮助! 本文的最后附有所使用到的sqlce在wince下 ...

  6. 浅析Linux下进程间通信:共享内存

    浅析Linux下进程间通信:共享内存 共享内存允许两个或多个进程共享一给定的存储区.因为数据不需要在客户进程和服务器进程之间复制,所以它是最快的一种IPC.使用共享内存要注意的是,多个进程之间对一给定 ...

  7. 在Window Embedded CE(Wince)下使用OpenNETCF进行路由表的开发

    点击打开链接 背景 在开发3G项目的是时候,发现尽管3G网络连接已经建立成功了,但是数据不能发送成功,查明原因,由于路由表的问题,导致数据往ActiveSync连接的对端,也就是PC发送,而不是发送到 ...

  8. WinCE下使用C#获得带毫秒的DateTime.Now

    在WinCE下,使用DateTime.Now获取的系统时间是不带毫秒的,如果想要它带毫秒,需要耍点手段.话不多说,直接上代码: public static DateTimePrecisely { // ...

  9. wince下sources\sources.cmn\Makefile.def的相关作用

    1:首先是Makefile.def: ---------------------------------------- 在所有驱动的makefile中有!INCLUDE $(_MAKEENVROOT) ...

随机推荐

  1. 巧用weui.topTips验证数据

    场景一.有一个输入金额的场景,这个金额需要验证,验证说明如下: 不能为空格: 不能为0: 不能为汉字: 不能为其它字符: 不能大于200: 唯一可以的是,只有输入3~199之间的数字,下面的确定按钮才 ...

  2. ASP.NET ValidationGroup 属性和CssClass 属性

    定义和用法 获取或设置在 Button 控件回发到服务器时要进行验证的控件组. 通常在表单中存在多个按钮时使用该属性. 语法 <asp:Button ValidationGroup=" ...

  3. 第7章 一个java源文件中只能有一个public类

    一个Java源文件中最多只能有一个public类, 1)当有一个public类时,源文件名必须与之一致,否则无法编译, 2)如果源文件中没有一个public类,则文件名与类中没有一致性要求. 至于ma ...

  4. ios控件 UIControl

    < UIControl> 1 处理用户事件的控件的基类,如UIButton,UISlider等 2 一般不直接实例化,而是使用他的子类 3 可以通过跟踪触摸事件来设置和获取控件状态,并且这 ...

  5. tar.gz tar.bz2 解压

    从网络上下载到的源码包, 最常见的是 .tar.gz 包, 还有一部分是 .tar.bz2包   要解压很简单 :   .tar.gz     格式解压为          tar   -zxvf   ...

  6. linux 进程监控和自动重启的简单实现(转)

    目的:linux 下服务器程序会因为各种原因dump掉,就会影响用户使用,这里提供一个简单的进程监控和重启功能. 实现原理:由定时任务crontab调用脚本,脚本用ps检查进程是否存在,如果不存在则重 ...

  7. JSP导出Excel后身份证后三位为0

    JSP导出Excel身份证号码超出Excel最大限制,用科学计数法表示,但后三位为0,修改方式: <style type="text/css">.txt    {    ...

  8. linux centos下安装g++

    1.查看是否安装 g++ -v 2.命令直接安装 yum install gcc-c++ 3.提示你找不到g++安装包,执行下面命令 yum install gcc-c++ libstdc++-dev ...

  9. Object调用控件的办法

    <OBJECT id="pwdpad" style="LEFT: 0px; WIDTH: 35px; TOP: 0px; HEIGHT: 16px" cl ...

  10. Linux试题及答案

    一. 单选题: 1.添加一条静态路由,使到网络196.199.3通过eth2接口出去,用: A. route add -net 196.199.3.0 B. route add -net 196.19 ...