利用消息实现不同语言间通信
发表于: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.ltesting.net