启动、终止一个会话
图1清楚给出了启动、终止一个DDE会话的消息处理流程:由客户方首先发送一条WM_DDE_INITIATE消息以启动一个DDE会话。通常的做法是客户将SendMessage()的第一个参数设置为-1,以广播的形式将此消息发送给所有的其他应用程序。当然,如果明确知道服务器DDE窗口的句柄,也可以直接将消息发送到该窗口。客户应用程序可以通过调用GlobalAddAtom()函数来准备服务名和主题名原子,也可以将服务名/主题名设置为NULL的方式与潜在的服务器进行任何可能的话题。
支持所指定服务名/主题名的服务器用一条WM_DDE_ACK消息来应答客户,并通过消息参数wParam把服务器窗口句柄返回给客户。客户在收到并保存此句柄后,可以通过该句柄直接将DDE消息发送到服务器窗口。
 图2 启动、终止一个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++(www.cppentry.com) 6.0编译通过。
|