利用消息實現不同語言間通信
發表于:2007-07-14來源:作者:點擊數:
標簽:
信息產業部電子第二十二研究所 郎銳 在編制較大的程序時,往往需要將一個程序分割成若干個模塊,然后由若干個 開發 小組分別完成。根據程序的功能需要,這些不同的模塊可能需要用不同的語言進行編制。這樣,在一個程序完成時就需要在不同語言編制的模塊間實
信息產業部電子第二十二研究所 郎銳
在編制較大的程序時,往往需要將一個程序分割成若干個模塊,然后由若干個
開發小組分別完成。根據程序的功能需要,這些不同的模塊可能需要用不同的語言進行編制。這樣,在一個程序完成時就需要在不同語言編制的模塊間實現通信。這種通信的實現一般根據預先定義的接口協議來完成,由于接口的預定義性決定了這種通信方式的局限性。本文介紹在
Windows平臺下如何利用消息機制解決這種混合語言編程的通信問題。
設計思路
由于編程人員可以用Microsoft Visual Studio 6.0附帶的DDE Spy工具攔截運行于
Windows操作系統上的應用程序所發出的各種消息,而不管這些應用程序是使用何種語言編制的,所以只要捕獲到目標程序的窗口句柄,就能向其發送消息。用于發送消息的兩個函數PostMessage和SendMessage的聲明如下:
BOOL PostMessage( HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
BOOL SendMessage( HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
下面通過兩個分別由VC++ 6.0和Delphi 5.0編制的模擬程序來簡要介紹一下該方法的實現過程。
Delphi 5.0編制的模擬程序
在VC++ 6.0下捕獲其他應用程序的窗口句柄要通過API函數FindWindow()來實現,該函數是根據目標窗口的窗口標題來判斷窗口的,所以要保證兩種語言編制的程序能進行可靠的通信,必須要保證各自的窗口標題不發生改變。本文修改窗口的標題屬性,將其設為“Delphi消息接收、發送程序”。
在Delphi 5.0下向VC++ 6.0發送消息比較簡單,只須調用Win32 API函數FindWindow(),在當前所有窗口中根據對方程序窗體的標題進行搜尋即可。當獲取到對方程序的窗口句柄后,就可以用PostMessage()或SendMessage()函數向其發送消息。這兩個函數雖然都是向指定的窗口發送消息,但前者是“郵遞”性質,把消息發出去后立即返回,不關心對方接收到消息后是否處理;而后者卻是一直等待對方把消息處理完,若對方不處理該消息,函數不會返回。發送消息的關鍵代碼如下:
……
{nil參數指定搜尋所有的窗口,捕獲窗口標題為
“VC消息接收、發送程序”的應用程序的窗口句柄}
hwnd:=FindWindow(nil,pchar(‘VC消息接收、發送程序’));
{向該窗體發送2000號自定義消息,附帶參數0
和1,表示是第一個按鈕向該窗體發出的消息}
PostMessage(hwnd,2000,0,1);
……
要響應從VC++ 6.0發送來的消息,則相對比較麻煩。首先要添加一個用來描述消息的數據結構,定義如下:
type
Tmymessage=record
a:cardinal;
b:integer; {附帶的第一個參數}
c:integer; {附帶的第二個參數}
d:integer;
end;
在Delphi 5.0里響應消息不需要有消息映射,只要像添加一個普通的過程一樣即可,但其入口參數必須為剛才所添加的消息結構對象并在其后要添加一個消息號。如:
procedure receive(var message:Tmymessage);message 2000;
在消息響應函數里可以通過判斷入口參數消息結構里的b、c數據成員變量來獲取隨消息發送來的兩個消息參數,并根據特定的數值作出相應的反應。
VC++ 6.0 編制的模擬程序
在VC++ 6.0下實現消息的發送和響應的思路和實現方法與上述的方法基本類似,也是將自己的標題固定以便對方獲取自己的窗口句柄來向自己發消息,但響應消息時需要靠消息映射來顯式實現。
固定自己的程序窗口標題一般是在工程的應用程序類的初始化函數OnInitial()里進行:
……
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->SetWindowText(“VC消息接收、發送程序”);
m_pMainWnd->UpdateWindow();
……
需要特別說明的是并非在所有的類里都可以添加從其他程序發來消息的響應函數,只有在主框架類里才能接收到外部程序發送來的消息。因為外部程序捕獲的句柄只是根據程序標題捕獲到的程序主框架的句柄,所以只能將消息發送到主框架類。自定義消息和消息映射的添加如下:
在主框架類的頭文件中添加如下代碼:
……
#define WM_MYMSG 2000
……
//{{AFX_MSG(CMainFrame)
// NOTE - the ClassWizard will add and remove member functions here. DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
//聲明消息映射
void OnRecvMsg(WPARAM wParam,LPARAM lParam);
DECLARE_MESSAGE_MAP()
……
在主框架類的實現文件里添加如下代碼:
……
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 !
//}}AFX_MSG_MAP
//加入消息映射
ON_MESSAGE(WM_TODELPHI,OnRecvMsg)
END_MESSAGE_MAP()
……
//編制消息映射處理代碼
void CMainFrame::OnRecvMsg(WPARAM
wParam,LPARAM lParam)
{
……
}
從VC++ 6 .0向外發送消息的方法與Delphi 5.0非常類似。尋找對方窗口可以用Win32 API的FindWindow()函數,也可以使用MFC的CWnd類的FindWindow()函數,后者直接返回窗口指針。實現的主要代碼如下:
……
//獲取以“Delphi消息接收、發送程序”為標題的Delphi程序的窗口句柄
CWnd *pWnd=CWnd::FindWindow(NULL,“Delphi消息接收、發送程序”);
//只有當確實捕獲到窗口時才向其發送消息,否則會引起異常錯誤
if (pWnd)
pWnd->PostMessage(WM_MYMSG,0,1);
……
其中WM_MYMSG是自定義消息,0和1是附帶的兩個消息參數。
檢驗程序的交互情況
首先把上述代碼在各自的編程環境下編譯完畢,運行后打開Microsoft Visual Studio 6.0附帶的調試工具包DDE Spy,當一個程序從另外一個程序接收到發送來的消息并執行完特定的工作后,可以通過DDE Spy監視到確實是從一個進程發出自定義消息,然后經過Win 32系統的消息隊列被另外一個進程所接收并響應。
小 結
本文通過一個簡單的例子對在異種語言編制的程序中使用消息作為通信工具的方法做了簡單的介紹,通過這種方式來解決混合編程中的小數據量的頻繁數據通信是一個不錯的選擇。但在實際應用中還需要考慮許多具體的細節問題,實現起來要比本文程序復雜得多。
原文轉自:http://www.anti-gravitydesign.com