程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> VC6.0下利用消息實現內部進程通訊

VC6.0下利用消息實現內部進程通訊

編輯:vc教程

引言

  內部進程間通訊和數據交換有消息、共享內存、匿名(命名)管道、郵槽、Windows套接字等多種技術。其中利用消息機制實現IPC雖然同其他方法相比有交換的數據量小、攜帶的信息少等缺點,但由於其實現方便、應用靈活而廣泛應用於無須大量、頻繁數據交換的內部進程通訊系統之中,尤其是對於在上層主控軟件與底層工作軟件之間的命令與響應上更能充分顯示其良好的性能。本文就通過編制一個主控軟件和一個受其操作的底層工作軟件來闡述如何用VC++6.0通過消息來實現內部進程通信。

  Windows消息機制

  Windows是一種面向對象的體系結構,Windows環境和應用程序都是通過消息來交互的。Windows應用程序開始執行後,Windows為該程序創建一個“消息隊列(message queue)”,用以存放郵寄給該程序可能創建的各種不同窗口的消息。消息隊列中消息的結構(MSG)為:

typedef struct tagMSG{
 HWND hwnd;
 UINT message;
 WPARAM wParam;
 LPARAM lParam;
 DWord time;
 POINT pt;
}MSG;

  其中第一個成員變量是用以標識接收消息的窗口的窗口句柄;第二個參數便是消息標識號,如WM_PAINT;第三個和第四個參數的具體意義同message值有關,均為消息參數。前四個參數是非常重要和經常用到的,至於後兩個參數則分別表示郵寄消息的時間和光標位置(屏幕坐標)。

  把消息傳送到應用程序有兩種方法:一種是由系統將消息“郵寄(post)”到應用程序的“消息隊列”這是“進隊消息”Win32 API有對應的函數:PostMessage(),此函數不等待該消息處理完就返回;而另一種則是由系統在直接調用窗口函數時將消息“發送(send)”給應用程序的窗口函數,屬於“不進隊消息”對應的函數是SendMessage()其必須等待該消息處理完後方可返回。消息是在消息循環中被處理的,下面這段代碼就是一個典型的消息循環:

MSG msg; //定義消息名
while (GetMessage (&msg, NULL, 0, 0))
{
 TranslateMessage (&msg) ; //翻譯消息
 DispatchMessage (&msg) ; //撤去消息
}
return msg.wParam ;

  消息循環以GetMessage調用開始,它從消息隊列中取出一個消息。該函數的四個參數可以有控制地獲取消息,第一個參數指定要接收消息的MSG結構的地址,第二個參數表示窗口句柄,一般將其設置為空,表示要獲取該應用程序創建的所有窗口的消息;第三、四參數用於指定消息范圍。後面三個參數被設置為默認值,用於接收發送到屬於這個應用程序的任何一個窗口的所有消息。在接收到除WM_QUIT之外的任何一個消息後,GetMessage()返回TRUE;如果GetMessage收到一個WM_QUIT消息,則返回FALSE以退出消息循環,終止程序運行。因此,在接收到WM_QUIT之前,帶有GetMessage()的消息循環可以一直循環下去。

  當除WM_QUIT的消息用GetMessage讀入後,首先要經過函數TranslateMessage()對其進行解釋,但對大多數消息來說並不起什麼作用。這裡起關鍵作用的是DispatchMessage()函數,把由GetMessage獲取的Windows消息傳送給在MSG結構中為窗口所指定的窗口過程。在消息處理函數處理完消息之後,代碼又循環到開始去接收另一個消息,這樣就完成了一個完整的消息循環。

  主控程序的實現

  本文將設計一個主控程序和一個底層工作程序,由主控程序通過消息來控制底層工作程序的工作狀態。這裡首先對主控程序的設計過程進行介紹:

  首先創建一個單文檔工程,添加三個菜單“命令一”、“命令二”、“命令三”及與之對應的命令響應函數:

OnSendComm1()
{
 CString str="Receiver";
 CWnd *pWnd=CWnd::FindWindow(NULL,str);
 if(pWnd)
  pWnd-〉SendMessage(WM_COMM,0,0);
} 
OnSendComm2()
{

 CString str="Receiver";
 CWnd *pWnd=CWnd::FindWindow(NULL,str);
 if(pWnd)
  pWnd-〉SendMessage(WM_COMM,0,1);
}
OnSendComm3()
{
 CString str="Receiver";
 CWnd *pWnd=CWnd::FindWindow(NULL,str);
 if(pWnd)
  pWnd-〉SendMessage(WM_COMM,1,0);
}

  這裡,WM_COMM是自定義消息,用於在主控程序和底層通信程序之間進行聯系,為了能夠使用該消息,必須首先添加預定義語句:

#define WM_COMM WM_USER + 100 


  上述幾個函數的結構沒有什麼區別,首先通過FindWindow()返回由str變量指定窗口標題的應用程序主窗口句柄並將其保存到pWnd。然後再通過該句柄調用SendMessage()函數並發送剛才定義的WM_COMM消息及其消息參數。如果函數被正確執行,底層程序將收到來發自主控程序的WM_COMM消息並可在消息響應函數中完成對消息參數的判斷處理以及進一步的操作。

 底層工作程序的實現

  最後,來介紹一下底層工作程序的實現過程。底層工作程序也是一個單文檔應用程序(當然,對於多文檔應用程序也是一樣)。由於主控程序是通過對應用程序主窗口標題的捕獲來得到底層程序主窗口句柄的。因此需要在底層工作程序應用類的初始化應用函數InitInstance()中添加(在函數末尾添加)下面語句:

m_pMainWnd-〉SetWindowText("Receiver");

  以設置底層工作程序的窗口標題。同時還要在主框架類的頭文件MainFrm.h中添加與主控程序一樣的自定義消息定義:

#define WM_COMM WM_USER+100

  由於底層程序需要接收並響應主控程序發出的通知消息,因此還要在底層工作程序中添加對自定義消息WM_COMM的響應處理:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping Macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_COMM,OnSendMsg)
END_MESSAGE_MAP()
……
void CMainFrame::OnSendMsg(WPARAM wParam, LPARAM lParam)
{
 if(wParam==0 && lParam==0)
  AfxMessageBox("主控程序發送命令一!");
 if(wParam==0 && lParam==1)
  AfxMessageBox("主控程序發送命令二!");
 if(wParam==1 && lParam==0)
  AfxMessageBox("主控程序發送命令三!");
}

  此後就可以通過辨別消息的兩個消息參數來區分主控程序發送的是哪一個命令從而可以執行相應的操作。執行主控程序和底層工作程序由於本程序采用的是SendMessage()所以當主控程序發送消息給底層工作程序時,底層工作程序彈出響應的模式對話框,在沒有關閉對話框前此消息未處理完,SendMessage()也就沒有執行完,所以主控程序呈阻塞狀態,如改用PoseMessage()則不會發生阻塞,具體選用哪個函數還應根據實際要求靈活掌握。

  結論:

  通過上面的實例可以看出利用消息進行進程間通信不失為一種便捷的方法,進程間的數據交換量不大卻能完成相當的功能,上下層次有著明顯的接口,上層和底層只通過這個接口進行通訊,因此只要對上下層程序制定好規范詳盡的協議便可編制出協調性很好的軟件控制系統。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved