接著前面的文章《WINCE下處理序間通訊(一)》,現在介紹處理序間通訊的另一種方法。
三、管道(訊息佇列)
WINCE並不支援類似於PC機上匿名管道、具名管道的通訊方式,但CE下提供了一種點對點訊息佇列的方法,其工作原理與管道非常類似:在通訊的兩端分別建立一個讀隊列和寫隊列,寫進程往訊息佇列一端寫入資料,讀進程從訊息佇列另一端讀取資料。
訊息佇列相關的系統API主要有:CreateMsgQueue()、ReadMsgQueue()、WriteMsgQuue()和CloseMsgQueue()。為了方便訊息佇列的操作,封裝了一個訊息佇列操作類,參考代碼如下:
標頭檔(CMsgQueue.h)/*******************************************************************<br /> filename: CMsgQueue.h<br /> purpose:封裝了WINCE下訊息佇列操作類<br /> author:firehood<br /> created:2011.03.23<br />********************************************************************/<br />#ifndef _MSG_QUEUE_H<br />#define _MSG_QUEUE_H</p><p>// 訊息佇列訪問模式<br />enum ACCESSMODE<br />{<br />ReadMode = 0,<br />WriteMode<br />};</p><p>// 定義訊息回呼函數<br />typedef BOOL (CALLBACK *MsgQueueCallBack)(PVOID pData, DWORD dwSize);</p><p>class CMsgQueue<br />{<br />public:<br />CMsgQueue();<br />CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);<br />~CMsgQueue();<br />public:<br />/**********************************************************************<br />函數名:Create<br />功能: 建立或開啟訊息佇列<br />參數:<br /> [in]lpQueueName:訊息佇列名稱<br /> [in]dwSize: 每條訊息的最大長度<br />[in]accessMode 訊息佇列訪問模式 ReadMode:唯讀 WriteMode:唯寫<br />傳回值:<br /> 成功:TRUE 失敗:FALSE<br />**********************************************************************/<br />BOOL Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode);</p><p>/**********************************************************************<br />函數名:Read<br />功能: 從訊息佇列中讀取一條訊息<br />參數:<br /> [out]lpBuffer: 存放讀取的資料<br /> [in] dwSize: 讀取資料的大小<br />[out]lpNumberOfBytesRead 實際讀取資料的大小<br />[in] dwTimeout 讀取逾時時間(ms) 0 立即返回 INFINITE 永遠等待直至訊息佇列中有資料<br />傳回值:<br /> 成功:TRUE 失敗:FALSE<br />***********************************************************************/<br />BOOL Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout = 0);</p><p>/**********************************************************************<br />函數名:Write<br />功能: 向訊息佇列中寫入一條訊息<br />參數:<br /> [in]lpBuffer: 待寫入的資料<br /> [in]dwSize: 寫入資料的大小<br />傳回值:<br /> 成功:TRUE 失敗:FALSE<br />**********************************************************************/<br />BOOL Write(LPVOID lpBuffer,DWORD dwSize);</p><p>// 設定訊息回呼函數<br />BOOL SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam);<br />// 關閉訊息佇列<br />void Close(void);<br />private:<br /> // 開啟讀取訊息線程<br />BOOL StartRevMsgThread(void);<br />// 停止讀取訊息線程<br />BOOL StopRevMsgThread(void);<br />// 讀取訊息線程<br />static void WINAPI RevMsgThread(LPVOID pParam);<br />private:<br />HANDLE m_hMsgQueue;<br />DWORD m_dwQueueSize;<br />MsgQueueCallBack m_MsgCallBack;<br />HANDLE m_hRevMsgThread;<br />BOOL m_bThreadExit;<br />};<br />#endif
源檔案(CMsgQueue.cpp)
#include "stdafx.h"<br />#include "CMsgQueue.h"</p><p>CMsgQueue::CMsgQueue()<br />{<br />m_hMsgQueue = NULL;<br />m_dwQueueSize = 0;<br />m_hRevMsgThread = NULL;<br />m_bThreadExit = FALSE;<br />m_MsgCallBack = NULL;<br />}</p><p>CMsgQueue::CMsgQueue(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)<br />{<br />Create(lpQueueName,dwSize,accessMode);<br />}</p><p>CMsgQueue::~CMsgQueue()<br />{<br />Close();<br />}</p><p>BOOL CMsgQueue::Create(LPCWSTR lpQueueName,DWORD dwSize,ACCESSMODE accessMode)<br />{<br />if(!m_hMsgQueue)<br />{<br />m_hRevMsgThread = NULL;<br />m_bThreadExit = FALSE;<br />m_MsgCallBack = NULL;<br />m_dwQueueSize = dwSize;<br />// 建立訊息佇列<br />MSGQUEUEOPTIONS options;<br />options.dwSize = sizeof(options);<br />options.dwFlags = MSGQUEUE_NOPRECOMMIT|MSGQUEUE_ALLOW_BROKEN;<br />options.dwMaxMessages = 0;<br />options.cbMaxMessage = dwSize;<br />options.bReadAccess = (accessMode==ReadMode) ? TRUE : FALSE;<br />m_hMsgQueue =::CreateMsgQueue(lpQueueName,&options);<br />}<br />return TRUE;<br />}</p><p>void CMsgQueue::Close(void)<br />{<br />if(m_hMsgQueue)<br />{<br />::CloseMsgQueue(m_hMsgQueue);<br />m_hMsgQueue = NULL;<br />}<br />// 登出回呼函數<br />SetMsgCallBack(NULL,NULL);<br />}</p><p>BOOL CMsgQueue::Read(LPVOID lpBuffer,DWORD dwSize,LPDWORD lpNumberOfBytesRead,DWORD dwTimeout)<br />{<br />if(m_hMsgQueue == NULL || lpBuffer == NULL)<br />{<br />return FALSE;<br />}<br /> DWORD dwFlag = 0;<br />// 從訊息佇列頭部讀出資料<br />if(!::ReadMsgQueue(m_hMsgQueue,lpBuffer,dwSize,lpNumberOfBytesRead,dwTimeout,&dwFlag))<br />{<br />return FALSE;<br />}<br />return TRUE;<br />}<br />BOOL CMsgQueue::Write(LPVOID lpBuffer,DWORD dwSize)<br />{<br />if(m_hMsgQueue == NULL || lpBuffer == NULL)<br />{<br />return FALSE;<br />}<br />// 向訊息佇列尾部寫入資料<br />if(!::WriteMsgQueue(m_hMsgQueue,lpBuffer,dwSize,0,0))<br />{<br />return FALSE;<br />}<br />return TRUE;<br />}</p><p>BOOL CMsgQueue::SetMsgCallBack(MsgQueueCallBack pCallBackFun, PVOID pParam)<br />{<br />m_MsgCallBack = pCallBackFun;<br />if (m_MsgCallBack)<br />{<br />if (m_hRevMsgThread == NULL)<br />{<br />// 開啟讀取線程<br />return StartRevMsgThread();<br />}<br />}<br />else<br />{<br />if (m_hRevMsgThread)<br />{<br />// 關閉讀取線程<br />return StopRevMsgThread();<br />}<br />}<br />return TRUE;<br />}</p><p>BOOL CMsgQueue::StartRevMsgThread(void)<br />{<br />if(m_hRevMsgThread == NULL)<br />{<br />// 建立讀取訊息線程<br />m_hRevMsgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CMsgQueue::RevMsgThread, this, 0, NULL);<br />}<br />return (m_hRevMsgThread ? TRUE : FALSE);<br />}</p><p>BOOL CMsgQueue::StopRevMsgThread(void)<br />{<br />if(m_hRevMsgThread)<br />{<br />m_bThreadExit = TRUE;<br />// 等待線程成功退出<br />WaitForSingleObject(m_hRevMsgThread,INFINITE);<br />CloseHandle(m_hRevMsgThread);<br />m_hRevMsgThread = NULL;<br />m_hRevMsgThread = FALSE;<br />}<br />return ((m_hRevMsgThread==NULL) ? TRUE : FALSE);<br />}</p><p>void WINAPI CMsgQueue::RevMsgThread(LPVOID pParam)<br />{<br /> CMsgQueue *pMsgQueue=(CMsgQueue*)pParam;<br /> LPVOID lpBuffer;<br /> DWORD dwReadNums=0;<br /> lpBuffer=(LPVOID)malloc(pMsgQueue->m_dwQueueSize);<br /> while(!pMsgQueue->m_bThreadExit)<br /> {<br /> if(!pMsgQueue->m_hMsgQueue )<br /> break;<br /> // 從訊息佇列中讀取一條訊息(阻塞模式)<br /> BOOL ret=pMsgQueue->Read(lpBuffer,pMsgQueue->m_dwQueueSize,&dwReadNums,INFINITE);<br /> printf("Read ret=%d,dwReadNums=%d/n",ret,dwReadNums);<br /> if(dwReadNums>0)<br /> {<br /> // 調用回呼函數<br /> if(pMsgQueue->m_MsgCallBack)<br /> pMsgQueue->m_MsgCallBack(lpBuffer,dwReadNums);<br /> }<br /> }<br /> printf("RevMsgThread exit.../n");<br /> free(lpBuffer);<br />}
使用CMsgQueue類實現處理序間通訊:
// 發送進程<br />//////////////////////////////////////////////////////////////////////////////////<br />// 建立唯寫訊息佇列<br />CMsgQueue cMsgQueue(L"MsgQueueTest",1024,WriteMode);<br />// 往訊息佇列寫資料<br />cMsgQueue.Write(L"Hello Word!",22);<br />cMsgQueue.Close();<br />//////////////////////////////////////////////////////////////////////////////////</p><p>// 接收進程<br />//////////////////////////////////////////////////////////////////////////////////<br />// 聲明訊息回呼函數<br />BOOL CALLBACK RecvMsgProc(PVOID pData, DWORD dwSize);</p><p>// 建立唯讀訊息佇列<br />CMsgQueue cMsgQueue(L"MsgQueueTest",1024,ReadMode);<br />// 設定訊息回呼函數<br />cMsgQueue.SetMsgCallBack(RecvMsgProc,NULL);</p><p>// 處理訊息<br />BOOL CALLBACK RecvMsgProc(PVOID pData, DWORD dwSize)<br />{<br />printf("RecvMsgProc:Rev data Size=%d/n",dwSize);<br />wchar_t data[256];<br />memcpy(data, pData,dwSize);<br />return TRUE;<br />}<br />//////////////////////////////////////////////////////////////////////////////////<br />