Поделиться через


Управление данными

Так как Динамический обмен данными (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, идентифицированный дескриптором, не может быть изменен; его можно освободить только.