VC++下动态数据交换技术之会话处理

来源:互联网 发布:淘宝天下小二 橙色标志 编辑:程序博客网 时间:2024/04/29 14:41

VC++下动态数据交换技术之会话处理
2004-09-02 作者:中国电波传播研究所 郎锐 出处:天极网

动态数据交换技术概述

  动态数据交换(DDE)是建立在Windows内部消息系统、全局原子和共项全局内存基础上的一种协议,可用来协调Windows应用程序之间的数据交换和命令调用。DDE协议通过对使用消息参数wParam和lParam来传递全局原子和全局共享内存句柄的方式的精确定义,使其能在进程间传递更多的信息,增强进程间共享数据和处理数据的能力。通常DDE主要用来传递那些不需要用户经常干涉的数据流。在建立原始链路后,有关的应用程序即将其接管过去,而无需用户进一步的介入。DDE所提供的是一种更加集成的工作环境。

  DDE的实现需要有两个应用程序参与一个“对话”以便交换信息。提供数据和执行命令的一方被指定为服务器,获取数据的一方称为客户。服务器和客户机是程序在一次具体会话中的角色,其区别在于所能启动的“事务”类型的不同。对于每一个DDE对话,会话双方要指定或专门建立维护会话的不可见DDE窗口以负责对DDE消息的处理。一个DDE对话是由参与会话的窗口句柄来标识的。正因如此,任何一个窗口都不应当参与与其他窗口只的多于一个的DDE对话。如果在一个客户和服务器之间存在多个对话过程,必须为每一个新的对话过程在一对一的基础上提供一个附加窗口。

  在任何通信中,通信双方都必须统一所交换数据的标识和格式。DDE协议采用的是由服务、主题和项目组成的一个三级层次命名来对DDE所传数据单元进行标识。一个特定的DDE会话唯一地由其服务名和主题名进行定义。在初始化一个DDE对话时,由DDE客户询问此特定DDE服务器的应用程序名和主题名。通常是将使用服务器应用程序的可执行文件名作为服务名。DDE的主题分类是一个包含多个数据项的普通数据类型。有效的主题及项目的选择由DDE服务器任意设置。由于客户和服务器窗口一起来识别一个DDE对话,因此在对话过程中不能改变应用程序或主题。但却可以在需要的时候对项目名称进行更改。

DDE的事务

  DDE对话是在两个进程之间进行的一种逻辑连接,通过这种连接可以进行数据交换。在客户和服务器之间进行的每一次会话都是由一系列事务所构成的。对于每个事务可以包含一个数据请求/数据服务和一个对应的响应。DDE服务器和客户所能启动的事务是不同的。服务器只能启动两种事务:向客户发送一个项目和终止一次对话;而DDE客户则可以启动如下八种服务:枚举DDE服务及主题、与服务器建立一次对话、向服务器请求一个项目、与服务器建立一个数据连接、终止数据连接、请求服务器执行一个或多个命令、向服务器发送一个数据项和终止一次会话。

 
图1 DDE会话事务流程

  图1给出了一个典型的DDE会话事务流程。由于DDE对话是由客户程序启动的,因此在客户程序启动对话前要确保DDE服务器程序已投入运行。客户首先启动会话,服务器程序响应客户的请求并向客户发送数据,客户方则可以主动向服务器发送数据,并要求与服务器建立热/温数据链路。此后客户可以向服务器发送命令并要求服务器执行。客户和服务器中的任何一方均有权利要求对方结束此次对话。在进行这些事务处理时,必须严格按照消息接收顺序去进行处理。当应用程序在等待DDE响应而无法处理另一个请求时,会发出一条表示忙的WM_DDE_ACK消息。


启动、终止一个会话

  图1清楚给出了启动、终止一个DDE会话的消息处理流程:由客户方首先发送一条WM_DDE_INITIATE消息以启动一个DDE会话。通常的做法是客户将SendMessage()的第一个参数设置为-1,以广播的形式将此消息发送给所有的其他应用程序。当然,如果明确知道服务器DDE窗口的句柄,也可以直接将消息发送到该窗口。客户应用程序可以通过调用GlobalAddAtom()函数来准备服务名和主题名原子,也可以将服务名/主题名设置为NULL的方式与潜在的服务器进行任何可能的话题。

  支持所指定服务名/主题名的服务器用一条WM_DDE_ACK消息来应答客户,并通过消息参数wParam把服务器窗口句柄返回给客户。客户在收到并保存此句柄后,可以通过该句柄直接将DDE消息发送到服务器窗口。

  客户与服务器的任何一方都可以向对方邮寄WM_DDE_TERMINATE消息以请求此次对话的终止,另一方在接收到此消息后也会向对方发出WM_DDE_TERMINATE消息作为应答,本次DDE对话即告结束。

  下面给出一个有关DDE启动和终止会话的程序示例,客户方首先获取服务器所在应用程序的窗口句柄,并在准备好服务名原子和主题名原子后向服务器程序发送启动一次会话的消息。并在最后完成对原子的删除:

// 获取服务器所在应用程序的窗口句柄
HWND hwndServer = ::FindWindow(NULL, "DDE服务器");
// 准备服务名原子
ATOM atomService = GlobalAddAtom("DDEServer");
// 准备主题名原子
ATOM atomTopic = GlobalAddAtom("Topic A");
// 获取当前窗口的安全句柄
HWND hwndClient = GetSafeHwnd();
// 向服务器程序发送WM_DDE_INITIATE消息
::SendMessage(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient, (LPARAM)MAKELONG(atomService, atomTopic));
// 删除服务名原子
if (atomService != NULL)
GlobalDeleteAtom(atomService);
// 删除主题名原子
if (atomTopic != NULL)
GlobalDeleteAtom(atomTopic); 

  在服务器所在应用程序对WM_DDE_INITIATE消息的响应函数中,首先登记自己的服务名原子和主题名原子,如果登记的这些原子同客户随消息参数发送过来的对应原子标识相匹配,就创建DDE服务器窗口并向客户发送应答消息WM_DDE_ACK:

// 提示信息
AfxMessageBox("接收到客户发出的会话请求");
// 保存客户窗口句柄
m_hwndClient = (HWND)wParam;
// 获取当前窗口的安全句柄
HWND hwnd = GetSafeHwnd();
// 登记自己的服务名原子并获取原子标识值
ATOM atomService = GlobalAddAtom("DDEServer");
// 登记自己的主题名原子并获取原子标识值
ATOM atomTopic = GlobalAddAtom("Topic A");
// 如果服务名/主题名原子匹配,就创建DDE窗口并应答
if ((LOWORD(lParam) == NULL || LOWORD(lParam) == atomService) &&
(HIWORD(lParam) == NULL || HIWORD(lParam) == atomTopic))
{
 // 创建DDE服务器窗口
 HWND hwndServer = CreateWindow("EDIT", NULL, WS_CHILD, 0, 0, 0, 0, hwnd, NULL, AfxGetInstanceHandle(),NULL);
 // 传送客户DDE窗口句柄
 ::SetWindowWord(hwndServer, 0, (LONG)m_hwndClient);
 // 发应答消息
 ::SendMessage(m_hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, (LPARAM)MAKELONG(atomService, atomTopic));
}
else
{
 // 不建立会话, 删除所创建原子
 GlobalDeleteAtom(atomService);
 GlobalDeleteAtom(atomTopic);
}

  客户方程序在对服务器发出的WM_DDE_ACK消息的响应函数中要保存参数wParam所表示的服务器DDE窗口句柄,以备在两个DDE会话窗口传递DDE消息时使用:

// 保存服务器程序反馈回来的DDE服务窗口句柄
m_hwndServer = (HWND)wParam;
// 提示信息
AfxMessageBox("收到从服务器传来的应答");

  在成功启动DDE会话后,服务/客户的DDE窗口就明确了对方的窗口句柄并且统一了服务名和主题名。这样就可以在两个窗口之间直接传递DDE消息而且只需指定数据项名即可。在本示例中并没有显式发送WM_DDE_TERMINATE消息,但在服务器程序退出时将会自动发出此消息给客户,客户则以同样的消息作为应答,完成本次DDE会话的终止:

// 在收到WM_DDE_TERMINATE消息后以WM_DDE_TERMINATE应答
::PostMessage(m_hwndServer, WM_DDE_TERMINATE, 0, 0);
// 提示信息
AfxMessageBox("服务器终止本次对话");

  小结

  本文对动态数据交换技术的基本概念作了简要的阐述。着重讨论了会话事务处理的一般过程,并通过示例代码对动态数据交换中的会话启动、终止等基本事务的一般实现过程作了较详细的介绍,通过本文读者能够对DDE技术有一个初步认识。本文所述代码在Windows 2000 Professional下由Microsoft Visual C++ 6.0编译通过。
 

原创粉丝点击