Управление данными
Так как Динамический обмен данными (DDE) использует объекты памяти для передачи данных из одного приложения в другое, библиотека управления динамическими данными (DDEML) предоставляет набор функций, которые приложения DDE могут использовать для создания объектов DDE и управления ими.
Все транзакции, связанные с обменом данными, требуют, чтобы приложение предоставляло данные для создания локального буфера, содержащего данные, а затем вызвать функцию DdeCreateDataHandle. Эта функция выделяет объект DDE, копирует данные из буфера в объект и возвращает дескриптор данных. Дескриптор данных — это значение DWORD , которое DDEML использует для предоставления доступа к данным в объекте DDE. Чтобы предоставить доступ к данным в объекте 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.
}
}
Принимающее приложение получает указатель на объект DDE, передав дескриптор данных функции DdeAccessData . Указатель, возвращаемый DdeAccessData , предоставляет доступ только для чтения. Приложение должно использовать указатель для проверки данных, а затем вызвать функцию DdeUnaccessData , чтобы сделать указатель недействительным. Приложение может скопировать данные в локальный буфер с помощью функции DdeGetData.
В следующем примере получает указатель на объект DDE, определенный параметром hData , копирует содержимое в локальный буфер, а затем делает указатель недействительным.
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, дескриптор становится недопустимым в создании приложения. Эта ситуация не является проблемой, если приложение должно совместно использовать данные только с одним приложением. Если приложение должно совместно использовать одни и те же данные с несколькими приложениями, то создание приложения должно указать флаг HDATA_APPOWNED в DdeCreateDataHandle. Это дает право собственности на объект DDE для создания приложения и предотвращает дескриптор данных DDEML. Затем приложение может передать обработку данных любое количество раз после вызова DdeCreateDataHandle только один раз.
Если приложение указывает флаг HDATA_APPOWNED в параметре afCmd DdeCreateDataHandle, он должен вызвать функцию DdeFreeDataHandle, чтобы освободить дескриптор памяти независимо от того, передается ли дескриптор DDEML. Прежде чем завершить работу, приложение должно вызвать DdeFreeDataHandle , чтобы освободить созданный дескриптор данных, но не передается в DDEML.
Приложение, которое еще не передало дескриптор объекту DDE в DDEML, может добавлять данные в объект или перезаписывать данные в объекте с помощью функции DdeAddData. Как правило, приложение использует DdeAddData для заполнения неинициализированного объекта DDE. После передачи дескриптора данных в DDEML объект DDE, идентифицированный дескриптором, не может быть изменен; его можно освободить только.