数据管理
由于动态数据交换 (DDE) 使用内存对象将数据从一个应用程序传递到另一个应用程序,因此动态数据交换管理库 (DDEML) 提供了一组函数,DDE 应用程序可以使用这些函数创建和管理 DDE 对象。
涉及数据交换的所有事务都需要应用程序提供数据,才能创建包含数据的本地缓冲区,然后调用 DdeCreateDataHandle 函数。 此函数将分配 DDE 对象,将数据从缓冲区复制到对象,以及返回数据句柄。 数据句柄是 DDEML 用于提供对 DDE 对象中的数据的访问权限的 DWORD 值。 若要共享 DDE 对象中的数据,应用程序会将数据句柄传递给 DDEML,而 DDEML 会将句柄传递给接收数据事务的应用程序的 DDE 回调函数。
以下示例演示如何创建 DDE 对象并获取该对象的句柄。 在 XTYP_ADVREQ 事务期间,回调函数会将当前时间转换为 ASCII 字符串,将字符串复制到本地缓冲区,然后创建包含字符串的 DDE 对象。 回调函数会将 DDE 对象 (HDDEDATA) 的句柄返回给 DDEML,后者会将句柄传递给客户端应用程序。
typedef struct tagTIME
{
INT hour; // 0 - 11 hours for analog clock
INT hour12; // 12-hour format
INT hour24; // 24-hour format
INT minute;
INT second;
INT ampm; // 0 - AM , 1 - PM
} TIME;
HDDEDATA EXPENTRY DdeCallback(uType, uFmt, hconv, hsz1, hsz2,
hdata, dwData1, dwData2)
UINT uType;
UINT uFmt;
HCONV hconv;
HSZ hsz1;
HSZ hsz2;
HDDEDATA hdata;
DWORD dwData1;
DWORD dwData2;
{
CHAR szBuf[32];
HRESULT hResult;
size_t * pcch;
HRESULT hResult;
switch (uType)
{
case XTYP_ADVREQ:
if ((hsz1 == hszTime && hsz2 == hszNow) &&
(uFmt == CF_TEXT))
{
// Copy the formatted string to a buffer.
itoa(tmTime.hour, szBuf, 10);
hResult = StringCchCat(szBuf, 32/sizeof(TCHAR), ":");
if (FAILED(hResult))
{
// TO DO: Write error handler.
return;
}
if (tmTime.minute < 10)
hResult = StringCchCat(szBuf, 32/sizeof(TCHAR), "0");
if (FAILED(hResult)
{
// TO DO: Write error handler.
return;
}
hResult = StringCchLength(szBuf, 32/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TO DO: Write error handler.
return;
}
itoa(tmTime.minute, &szBuf[*pcch], 10);
hResult = StringCchCat(szBuf, 32/sizeof(TCHAR), ":");
if (FAILED(hResult)
{
// TO DO: Write error handler.
return;
}
if (tmTime.second < 10)
hResult = StringCchCat(szBuf, 32/sizeof(TCHAR), "0");
if (FAILED(hResult)
{
// TO DO: Write error handler.
return;
}
hResult = StringCchLength(szBuf, 32/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TO DO: Write error handler.
return;
}
itoa(tmTime.second, &szBuf[*pcch], 10);
hResult = StringCchLength(szBuf, 32/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TO DO: Write error handler.
return;
}
szBuf[*pcch] = '\0';
// Create a global object and return its data handle.
hResult = StringCchLength(szBuf, 32/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TO DO: Write error handler.
return;
}
return (DdeCreateDataHandle(
idInst,
(LPBYTE) szBuf, // instance identifier
*pcch + 1, // source buffer length
0, // offset from beginning
hszNow, // item name string
CF_TEXT, // clipboard format
0)); // no creation flags
} else return (HDDEDATA) NULL;
// Process other transactions.
}
}
接收应用程序会将数据句柄传递给 DdeAccessData 函数,以获取指向 DDE 对象的指针。 DdeAccessData 返回的指针提供只读访问权限。 应用程序应使用指针查看数据,然后调用 DdeUnaccessData 函数使指针失效。 应用程序可以使用 DdeGetData 函数将数据复制到本地缓冲区。
以下示例会获取指向 hData 参数标识的 DDE 对象的指针,将内容复制到本地缓冲区,然后使指针失效。
HDDEDATA hdata;
LPBYTE lpszAdviseData;
DWORD cbDataLen;
DWORD i;
char szData[32];
//
case XTYP_ADVDATA:
lpszAdviseData = DdeAccessData(hdata, &cbDataLen);
for (i = 0; i < cbDataLen; i++)
szData[i] = *lpszAdviseData++;
DdeUnaccessData(hdata);
return (HDDEDATA) TRUE;
//
通常,当创建数据句柄的应用程序将该句柄传递给 DDEML 时,该句柄会在创建应用程序中变得无效。 如果应用程序仅必须与单个应用程序共享数据,则这种情况并不是问题。 但是,如果应用程序必须与多个应用程序共享相同的数据,则创建应用程序应在 DdeCreateDataHandle 中指定 HDATA_APPOWNED 标志。 这样做会为创建应用程序提供 DDE 对象的所有权,并阻止 DDEML 使数据处理无效。 接着,应用程序可以在调用 DdeCreateDataHandle 后多次传递数据句柄。
如果应用程序在 DdeCreateDataHandle 的 afCmd 参数中指定 HDATA_APPOWNED 标志,则无论应用程序是否将句柄传递给 DDEML,都必须调用 DdeFreeDataHandle 函数来释放内存句柄。 在终止之前,应用程序必须调用 DdeFreeDataHandle 来释放它创建但未传递给 DDEML 的任何数据句柄。
尚未将句柄传递到 DDEML 的应用程序可以使用 DdeAddData 函数将数据添加到对象或覆盖对象中的数据。 通常,应用程序使用 DdeAddData 填充未初始化的 DDE 对象。 应用程序向 DDEML 传递数据句柄后,将无法更改句柄标识的 DDE 对象;只能将其释放。