WINCE下进程间通信(二)

接着前面的文章《WINCE下进程间通信(一)》,现在介绍进程间通信的另一种方法。

三、管道(消息队列)

WINCE并不支持类似于PC机上匿名管道、命名管道的通信方式,但CE下提供了一种点对点消息队列的方法,其工作原理与管道非常类似:在通信的两端分别建立一个读队列和写队列,写进程往消息队列一端写入数据,读进程从消息队列另一端读取数据。

消息队列相关的系统API主要有:CreateMsgQueue()、ReadMsgQueue()、WriteMsgQuue()和CloseMsgQueue()。为了方便消息队列的操作,封装了一个消息队列操作类,参考代码如下:

头文件(CMsgQueue.h)

  1. /*******************************************************************
  2. filename: CMsgQueue.h
  3. purpose:   封装了WINCE下消息队列操作类
  4. author:    firehood
  5. created:   2011.03.23
  6. ********************************************************************/
  7. #ifndef _MSG_QUEUE_H
  8. #define _MSG_QUEUE_H
  9. // 消息队列访问模式
  10. enum ACCESSMODE
  11. {
  12. ReadMode = 0,
  13. WriteMode
  14. };
  15. // 定义消息回调函数
  16. typedef BOOL (CALLBACK *MsgQueueCallBack)(PVOID pData, DWORD dwSize);
  17. class CMsgQueue
  18. {
  19. public:
  20. CMsgQueue();
  21. CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);
  22. ~CMsgQueue();
  23. public:
  24. /**********************************************************************
  25. 函数名:Create
  26. 功能:  创建或打开消息队列
  27. 参数:
  28. [in]lpQueueName:    消息队列名称
  29. [in]dwSize:         每条消息的最大长度
  30. [in]accessMode      消息队列访问模式 ReadMode:只读  WriteMode:只写
  31. 返回值:
  32. 成功:TRUE  失败:FALSE
  33. **********************************************************************/
  34. BOOL Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);
  35. /**********************************************************************
  36. 函数名:Read
  37. 功能:  从消息队列中读取一条消息
  38. 参数:
  39. [out]lpBuffer:            存放读取的数据
  40. [in] dwSize:              读取数据的大小
  41. [out]lpNumberOfBytesRead  实际读取数据的大小
  42. [in] dwTimeout            读取超时时间(ms) 0 立即返回  INFINITE 永远等待直至消息队列中有数据
  43. 返回值:
  44. 成功:TRUE  失败:FALSE
  45. ***********************************************************************/
  46. BOOL Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout = 0);
  47. /**********************************************************************
  48. 函数名:Write
  49. 功能:  向消息队列中写入一条消息
  50. 参数:
  51. [in]lpBuffer:      待写入的数据
  52. [in]dwSize:        写入数据的大小
  53. 返回值:
  54. 成功:TRUE  失败:FALSE
  55. **********************************************************************/
  56. BOOL Write(LPVOID lpBuffer,DWORD dwSize);
  57. // 设置消息回调函数
  58. BOOL SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam);
  59. // 关闭消息队列
  60. void Close(void);
  61. private:
  62. // 开启读取消息线程
  63. BOOL StartRevMsgThread(void);
  64. // 停止读取消息线程
  65. BOOL StopRevMsgThread(void);
  66. // 读取消息线程
  67. static void WINAPI RevMsgThread(LPVOID pParam);
  68. private:
  69. HANDLE m_hMsgQueue;
  70. DWORD m_dwQueueSize;
  71. MsgQueueCallBack m_MsgCallBack;
  72. HANDLE m_hRevMsgThread;
  73. BOOL m_bThreadExit;
  74. };
  75. #endif

/*******************************************************************
filename: CMsgQueue.h
purpose:封装了WINCE下消息队列操作类
author:firehood
created:2011.03.23
********************************************************************/
#ifndef _MSG_QUEUE_H
#define _MSG_QUEUE_H

// 消息队列访问模式
enum ACCESSMODE
{
ReadMode = 0,
WriteMode
};

// 定义消息回调函数
typedef BOOL (CALLBACK *MsgQueueCallBack)(PVOID pData, DWORD dwSize);

class CMsgQueue
{
public:
CMsgQueue();
CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);
~CMsgQueue();
public:
/**********************************************************************
函数名:Create
功能: 创建或打开消息队列
参数:
[in]lpQueueName:消息队列名称
[in]dwSize: 每条消息的最大长度
[in]accessMode 消息队列访问模式 ReadMode:只读 WriteMode:只写
返回值:
成功:TRUE 失败:FALSE
**********************************************************************/
BOOL Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);

/**********************************************************************
函数名:Read
功能: 从消息队列中读取一条消息
参数:
[out]lpBuffer: 存放读取的数据
[in] dwSize: 读取数据的大小
[out]lpNumberOfBytesRead 实际读取数据的大小
[in] dwTimeout 读取超时时间(ms) 0 立即返回 INFINITE 永远等待直至消息队列中有数据
返回值:
成功:TRUE 失败:FALSE
***********************************************************************/
BOOL Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout = 0);

/**********************************************************************
函数名:Write
功能: 向消息队列中写入一条消息
参数:
[in]lpBuffer: 待写入的数据
[in]dwSize: 写入数据的大小
返回值:
成功:TRUE 失败:FALSE
**********************************************************************/
BOOL Write(LPVOID lpBuffer,DWORD dwSize);

// 设置消息回调函数
BOOL SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam);
// 关闭消息队列
void Close(void);
private:
// 开启读取消息线程
BOOL StartRevMsgThread(void);
// 停止读取消息线程
BOOL StopRevMsgThread(void);
// 读取消息线程
static void WINAPI RevMsgThread(LPVOID pParam);
private:
HANDLE m_hMsgQueue;
DWORD m_dwQueueSize;
MsgQueueCallBack m_MsgCallBack;
HANDLE m_hRevMsgThread;
BOOL m_bThreadExit;
};
#endif

源文件(CMsgQueue.cpp)

  1. #include "stdafx.h"
  2. #include "CMsgQueue.h"
  3. CMsgQueue::CMsgQueue()
  4. {
  5. m_hMsgQueue = NULL;
  6. m_dwQueueSize = 0;
  7. m_hRevMsgThread = NULL;
  8. m_bThreadExit = FALSE;
  9. m_MsgCallBack = NULL;
  10. }
  11. CMsgQueue::CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)
  12. {
  13. Create(lpQueueName,dwSize,accessMode);
  14. }
  15. CMsgQueue::~CMsgQueue()
  16. {
  17. Close();
  18. }
  19. BOOL CMsgQueue::Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)
  20. {
  21. if(!m_hMsgQueue)
  22. {
  23. m_hRevMsgThread = NULL;
  24. m_bThreadExit = FALSE;
  25. m_MsgCallBack = NULL;
  26. m_dwQueueSize = dwSize;
  27. // 创建消息队列
  28. MSGQUEUEOPTIONS options;
  29. options.dwSize = sizeof(options);
  30. options.dwFlags = MSGQUEUE_NOPRECOMMIT|MSGQUEUE_ALLOW_BROKEN;
  31. options.dwMaxMessages = 0;
  32. options.cbMaxMessage = dwSize;
  33. options.bReadAccess = (accessMode==ReadMode) ? TRUE : FALSE;
  34. m_hMsgQueue =::CreateMsgQueue(lpQueueName,&options);
  35. }
  36. return TRUE;
  37. }
  38. void CMsgQueue::Close(void)
  39. {
  40. if(m_hMsgQueue)
  41. {
  42. ::CloseMsgQueue(m_hMsgQueue);
  43. m_hMsgQueue = NULL;
  44. }
  45. // 注销回调函数
  46. SetMsgCallBack(NULL,NULL);
  47. }
  48. BOOL CMsgQueue::Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout)
  49. {
  50. if(m_hMsgQueue == NULL || lpBuffer == NULL)
  51. {
  52. return FALSE;
  53. }
  54. DWORD dwFlag = 0;
  55. // 从消息队列头部读出数据
  56. if(!::ReadMsgQueue(m_hMsgQueue,lpBuffer,dwSize,lpNumberOfBytesRead,dwTimeout,&dwFlag))
  57. {
  58. return FALSE;
  59. }
  60. return TRUE;
  61. }
  62. BOOL CMsgQueue::Write(LPVOID lpBuffer,DWORD dwSize)
  63. {
  64. if(m_hMsgQueue == NULL || lpBuffer == NULL)
  65. {
  66. return FALSE;
  67. }
  68. // 向消息队列尾部写入数据
  69. if(!::WriteMsgQueue(m_hMsgQueue,lpBuffer,dwSize,0,0))
  70. {
  71. return FALSE;
  72. }
  73. return TRUE;
  74. }
  75. BOOL CMsgQueue::SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam)
  76. {
  77. m_MsgCallBack = pCallBackFun;
  78. if (m_MsgCallBack)
  79. {
  80. if (m_hRevMsgThread == NULL)
  81. {
  82. // 开启读取线程
  83. return StartRevMsgThread();
  84. }
  85. }
  86. else
  87. {
  88. if (m_hRevMsgThread)
  89. {
  90. // 关闭读取线程
  91. return StopRevMsgThread();
  92. }
  93. }
  94. return TRUE;
  95. }
  96. BOOL CMsgQueue::StartRevMsgThread(void)
  97. {
  98. if(m_hRevMsgThread == NULL)
  99. {
  100. // 创建读取消息线程
  101. m_hRevMsgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CMsgQueue::RevMsgThread, this, 0, NULL);
  102. }
  103. return (m_hRevMsgThread ? TRUE : FALSE);
  104. }
  105. BOOL CMsgQueue::StopRevMsgThread(void)
  106. {
  107. if(m_hRevMsgThread)
  108. {
  109. m_bThreadExit = TRUE;
  110. // 等待线程成功退出
  111. WaitForSingleObject(m_hRevMsgThread,INFINITE);
  112. CloseHandle(m_hRevMsgThread);
  113. m_hRevMsgThread = NULL;
  114. m_hRevMsgThread = FALSE;
  115. }
  116. return ((m_hRevMsgThread==NULL) ? TRUE : FALSE);
  117. }
  118. void WINAPI CMsgQueue::RevMsgThread(LPVOID pParam)
  119. {
  120. CMsgQueue *pMsgQueue=(CMsgQueue*)pParam;
  121. LPVOID lpBuffer;
  122. DWORD dwReadNums=0;
  123. lpBuffer=(LPVOID)malloc(pMsgQueue->m_dwQueueSize);
  124. while(!pMsgQueue->m_bThreadExit)
  125. {
  126. if(!pMsgQueue->m_hMsgQueue )
  127. break;
  128. // 从消息队列中读取一条消息(阻塞模式)
  129. BOOL ret=pMsgQueue->Read(lpBuffer,pMsgQueue->m_dwQueueSize,&dwReadNums,INFINITE);
  130. printf("Read ret=%d,dwReadNums=%d/n",ret,dwReadNums);
  131. if(dwReadNums>0)
  132. {
  133. // 调用回调函数
  134. if(pMsgQueue->m_MsgCallBack)
  135. pMsgQueue->m_MsgCallBack(lpBuffer,dwReadNums);
  136. }
  137. }
  138. printf("RevMsgThread exit.../n");
  139. free(lpBuffer);
  140. }

#include "stdafx.h"
#include "CMsgQueue.h"

CMsgQueue::CMsgQueue()
{
m_hMsgQueue = NULL;
m_dwQueueSize = 0;
m_hRevMsgThread = NULL;
m_bThreadExit = FALSE;
m_MsgCallBack = NULL;
}

CMsgQueue::CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)
{
Create(lpQueueName,dwSize,accessMode);
}

CMsgQueue::~CMsgQueue()
{
Close();
}

BOOL CMsgQueue::Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)
{
if(!m_hMsgQueue)
{
m_hRevMsgThread = NULL;
m_bThreadExit = FALSE;
m_MsgCallBack = NULL;
m_dwQueueSize = dwSize;
// 创建消息队列
MSGQUEUEOPTIONS options;
options.dwSize = sizeof(options);
options.dwFlags = MSGQUEUE_NOPRECOMMIT|MSGQUEUE_ALLOW_BROKEN;
options.dwMaxMessages = 0;
options.cbMaxMessage = dwSize;
options.bReadAccess = (accessMode==ReadMode) ? TRUE : FALSE;
m_hMsgQueue =::CreateMsgQueue(lpQueueName,&options);
}
return TRUE;
}

void CMsgQueue::Close(void)
{
if(m_hMsgQueue)
{
::CloseMsgQueue(m_hMsgQueue);
m_hMsgQueue = NULL;
}
// 注销回调函数
SetMsgCallBack(NULL,NULL);
}

BOOL CMsgQueue::Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout)
{
if(m_hMsgQueue == NULL || lpBuffer == NULL)
{
return FALSE;
}
DWORD dwFlag = 0;
// 从消息队列头部读出数据
if(!::ReadMsgQueue(m_hMsgQueue,lpBuffer,dwSize,lpNumberOfBytesRead,dwTimeout,&dwFlag))
{
return FALSE;
}
return TRUE;
}
BOOL CMsgQueue::Write(LPVOID lpBuffer,DWORD dwSize)
{
if(m_hMsgQueue == NULL || lpBuffer == NULL)
{
return FALSE;
}
// 向消息队列尾部写入数据
if(!::WriteMsgQueue(m_hMsgQueue,lpBuffer,dwSize,0,0))
{
return FALSE;
}
return TRUE;
}

BOOL CMsgQueue::SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam)
{
m_MsgCallBack = pCallBackFun;
if (m_MsgCallBack)
{
if (m_hRevMsgThread == NULL)
{
// 开启读取线程
return StartRevMsgThread();
}
}
else
{
if (m_hRevMsgThread)
{
// 关闭读取线程
return StopRevMsgThread();
}
}
return TRUE;
}

BOOL CMsgQueue::StartRevMsgThread(void)
{
if(m_hRevMsgThread == NULL)
{
// 创建读取消息线程
m_hRevMsgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CMsgQueue::RevMsgThread, this, 0, NULL);
}
return (m_hRevMsgThread ? TRUE : FALSE);
}

BOOL CMsgQueue::StopRevMsgThread(void)
{
if(m_hRevMsgThread)
{
m_bThreadExit = TRUE;
// 等待线程成功退出
WaitForSingleObject(m_hRevMsgThread,INFINITE);
CloseHandle(m_hRevMsgThread);
m_hRevMsgThread = NULL;
m_hRevMsgThread = FALSE;
}
return ((m_hRevMsgThread==NULL) ? TRUE : FALSE);
}

void WINAPI CMsgQueue::RevMsgThread(LPVOID pParam)
{
CMsgQueue *pMsgQueue=(CMsgQueue*)pParam;
LPVOID lpBuffer;
DWORD dwReadNums=0;
lpBuffer=(LPVOID)malloc(pMsgQueue->m_dwQueueSize);
while(!pMsgQueue->m_bThreadExit)
{
if(!pMsgQueue->m_hMsgQueue )
break;
// 从消息队列中读取一条消息(阻塞模式)
BOOL ret=pMsgQueue->Read(lpBuffer,pMsgQueue->m_dwQueueSize,&dwReadNums,INFINITE);
printf("Read ret=%d,dwReadNums=%d/n",ret,dwReadNums);
if(dwReadNums>0)
{
// 调用回调函数
if(pMsgQueue->m_MsgCallBack)
pMsgQueue->m_MsgCallBack(lpBuffer,dwReadNums);
}
}
printf("RevMsgThread exit.../n");
free(lpBuffer);
}

使用CMsgQueue类实现进程间通信:

  1. // 发送进程
  2. //////////////////////////////////////////////////////////////////////////////////
  3. // 创建只写消息队列
  4. CMsgQueue cMsgQueue(L"MsgQueueTest",1024,WriteMode);
  5. // 往消息队列写数据
  6. cMsgQueue.Write(L"Hello Word!",22);
  7. cMsgQueue.Close();
  8. //////////////////////////////////////////////////////////////////////////////////
  9. // 接收进程
  10. //////////////////////////////////////////////////////////////////////////////////
  11. // 声明消息回调函数
  12. BOOL CALLBACK RecvMsgProc(PVOID pData, DWORD dwSize);
  13. // 创建只读消息队列
  14. CMsgQueue cMsgQueue(L"MsgQueueTest",1024,ReadMode);
  15. // 设置消息回调函数
  16. cMsgQueue.SetMsgCallBack(RecvMsgProc,NULL);
  17. // 处理消息
  18. BOOL CALLBACK RecvMsgProc(PVOID pData, DWORD dwSize)
  19. {
  20. printf("RecvMsgProc:Rev data Size=%d/n",dwSize);
  21. wchar_t data[256];
  22. memcpy(data, pData,dwSize);
  23. return TRUE;
  24. }
  25. //////////////////////////////////////////////////////////////////////////////////
04-16 04:29