Gestione dei dati
Poiché Dynamic Data Exchange (DDE) usa oggetti memoria per passare dati da un'applicazione a un'altra, Dynamic Data Exchange Management Library (DDEML) fornisce un set di funzioni che le applicazioni DDE possono usare per creare e gestire oggetti DDE.
Tutte le transazioni che coinvolgono lo scambio di dati richiedono all'applicazione di fornire i dati per creare un buffer locale contenente i dati e quindi chiamare la funzione DdeCreateDataHandle. Questa funzione alloca un oggetto DDE, copia i dati dal buffer all'oggetto e restituisce un handle di dati. Un handle di dati è un valore DWORD usato da DDEML per fornire l'accesso ai dati nell'oggetto DDE. Per condividere i dati in un oggetto DDE, un'applicazione passa l'handle dati al DDEML e DDEML passa l'handle alla funzione di callback DDE dell'applicazione che riceve la transazione di dati.
Nell'esempio seguente viene illustrato come creare un oggetto DDE e ottenere un handle per l'oggetto . Durante la transazione XTYP_ADVREQ, la funzione di callback converte l'ora corrente in una stringa ASCII, copia la stringa in un buffer locale e quindi crea un oggetto DDE contenente la stringa. La funzione di callback restituisce l'handle all'oggetto DDE (HDDEDATA) al DDEML, che passa l'handle all'applicazione client.
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.
}
}
L'applicazione ricevente ottiene un puntatore all'oggetto DDE passando l'handle dati alla funzione DdeAccessData. Il puntatore restituito da DdeAccessData fornisce l'accesso in sola lettura. L'applicazione deve usare il puntatore per esaminare i dati e quindi chiamare la funzioneDdeUnaccessDataper invalidare il puntatore. L'applicazione può copiare i dati in un buffer locale usando la funzione DdeGetData.
Nell'esempio seguente viene ottenuto un puntatore all'oggetto DDE identificato dal parametro hData, copia il contenuto in un buffer locale e quindi invalida il puntatore.
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;
//
In genere, quando un'applicazione che ha creato un handle di dati passa tale handle al DDEML, l'handle non è valido nell'applicazione di creazione. Questa situazione non è un problema se l'applicazione deve condividere dati con una sola applicazione. Se un'applicazione deve condividere gli stessi dati con più applicazioni, tuttavia, l'applicazione di creazione deve specificare il flag HDATA_APPOWNED in DdeCreateDataHandle. In questo modo viene assegnata la proprietà dell'oggetto DDE all'applicazione di creazione e si impedisce a DDEML di invalidare l'handle di dati. L'applicazione può quindi passare qualsiasi numero di volte dopo aver chiamato DdeCreateDataHandle una sola volta.
Se un'applicazione specifica il flag di HDATA_APPOWNED nel parametro afCmd di DdeCreateDataHandle, deve chiamare la funzione DdeFreeDataHandle per liberare l'handle di memoria, indipendentemente dal fatto che abbia passato l'handle al DDEML. Prima di terminare, un'applicazione deve chiamare DdeFreeDataHandle per liberare qualsiasi handle di dati creato ma non passato al DDEML.
Un'applicazione che non ha ancora passato l'handle a un oggetto DDE al DDEML può aggiungere dati all'oggetto o sovrascrivere i dati nell'oggetto utilizzando la funzione DdeAddData. In genere, un'applicazione usa DdeAddData per riempire un oggetto DDE non inizializzato. Dopo che un'applicazione passa un handle di dati al DDEML, l'oggetto DDE identificato dall'handle non può essere modificato; può essere liberato solo.