冷数据链路的建立
在建立DDE会话后,客户可以向服务窗口邮寄WM_DDE_REQUEST消息来请求指定的数据项。消息参数lParam的高字为指定数据项的原子标识值,低字为所要求的数据格式标识值。如果服务器没有找到匹配的数据项,将向客户邮寄一条否定应答消息WM_DDE_ACK;如果含有此数据项,则邮寄WM_DDE_DATA消息以响应客户的数据项请求,其消息参数lParam的高字为数据项原子标识值,低字为存放此数据项的全局共享内存块的DDEDATA结构句柄。
对于上述方式,客户每需要一个数据项,都要向服务器窗口发送一次WM_DDE_REQUSET消息去请求数据项,由此可以建立冷数据链路。图1给出了服务器在能提供数据项和无法提供数据项的情况下所进行的消息流程:
图1 服务器在不同情况下对客户的应答
客户通过下面的程序段代码完成对WM_DDE_REQUEST消息的邮寄,其中主要指定了数据项原子标识和数据格式:
HWND hwndClient = GetSafeHwnd(); // 获取服务器所在应用程序的窗口句柄 ATOM atomItem = GlobalAddAtom("Item A"); // 获取原子标识值 if (atomItem != 0) // 向服务器发出数据请求消息 ::PostMessage(m_hwndServer, WM_DDE_REQUEST, (WPARAM)hwndClient, (LPARAM)MAKELONG(CF_TEXT, atomItem)); |
DDE服务器的准备工作与消息处理
DDE服务器窗口在创建之初就要首先进行一些准备工作,主要是对DDEDATA格式化的全局共享内存块的分配与设置,并指定所使用的格式字段和数据项内容,以便在接收到客户发来的数据项请求消息后,能将此共享内存块的句柄随应答消息传送给客户:
m_hwndServer = hwndServer; // 保存创建的DDE服务窗口 CString sDataItem = "HELLO WORLD!"; // 服务器数据项内容 // 分配DDEDATA格式化的全局共享内存块 m_hDDEData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (LONG)sizeof(DDEDATA) + sDataItem.GetLength() + 2); // 锁定内存块地址 DDEDATA * lpDDEData = (DDEDATA*)GlobalLock(m_hDDEData); lpDDEData->cfFormat = CF_TEXT; // 设置格式字段 ::strcpy((LPSTR)lpDDEData->Value, sDataItem); // 填充数据项内容 ::strcat((LPSTR)lpDDEData->Value, "\r\n"); // 添加终结字符 GlobalUnlock(m_hDDEData); // 解锁内存块 |
在服务器进程对WM_DDE_REQUEST消息的响应函数中,首先从消息参数lParam中提取出请求的数据项原子标识值及数据格式。如果请求的数据格式与服务器提供的数据项格式一致,则进行枚举匹配,直至找到待请求的数据项。由于DDEDATA格式化的内存块句柄和数据项原子标识值是通过消息参数lParam传送到客户的,如果继续使用MAKELONG()进行高、低字组合,势必造成32位句柄值的破坏。对于这种情况应当使用PackDDElParam()函数进行组合。需要注意的是,在向客户传递WM_DDE_DATA消息时只能用PostMessage()函数去邮寄,而不能使用SendMessage()。如果服务器枚举完其提供的所有数据项后仍未找到匹配的数据项,就认为客户的本次请求失败,将向其邮寄WM_DDE_ACK消息作为否定应答,消息参数lParam的低字包含了状态信息。下面给出此部分的完整代码清单:
int ITEM_NUM = 3; // 服务器提供的数据项数目 CString ItemName[3] = {"Item A", "Item B", "Item C"}; // 服务器提供的数据项名 char szItemNameClient[255]; // 客户请求的数据项名 HWND hwndClient = (HWND)wParam; // 客户窗口句柄 short cfFormat = LOWORD(lParam); // 客户传来的数据格式 if (cfFormat == CF_TEXT){ // 格式一致则进入下一步操作 // 取客户请求的数据项名 GlobalGetAtomName(HIWORD(lParam), szItemNameClient, sizeof(szItemNameClient)); for (int i = 0; i < ITEM_NUM; i++){// 检索与服务器提供的哪个数据项匹配 if (strcmp(szItemNameClient, ItemName[i]) == 0) // 如检索到则跳出
break; } ATOM atomItem = GlobalAddAtom(ItemName[i]); // 获取原子标识值 // 若检索到数据项就发送WM_DDE_DATA消息,否则发送WM_DDE_ACK消息 if (i < ITEM_NUM){ LONG lDataPack = PackDDElParam(WM_DDE_DATA, (UINT)m_hDDEData, atomItem); // 组合消息参数lParam ::PostMessage(hwndClient, WM_DDE_DATA, (WPARAM)m_hwndServer, (LPARAM)lDataPack); // 邮寄WM_DDE_DATA消息 } else { DDEACK DDEAck; // 填充DDEACK结构 DDEAck.bAppReturnCode = 0; DDEAck.reserved = 0; DDEAck.fBusy = FALSE; DDEAck.fAck = FALSE; WORD wStatus = *(WORD*)&DDEAck; ::PostMessage(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, MAKELONG(wStatus, atomItem)); // 邮寄WM_DDE_ACK否定应答消息 } GlobalDeleteAtom(atomItem); // 删除原子 GlobalFree(m_hDDEData); // 释放申请的内存 } |
|