Gerenciamento de Dados
Como o DDE (Dynamic Data Exchange) usa objetos de memória para passar dados de um aplicativo para outro, a DDEML (Dynamic Data Exchange Management Library) fornece um conjunto de funções que os aplicativos DDE podem usar para criar e gerenciar objetos DDE.
Todas as transações que envolvem a troca de dados exigem que o aplicativo que fornece os dados crie um buffer local contendo os dados e, em seguida, chame a função DdeCreateDataHandle. Essa função aloca um objeto DDE, copia os dados do buffer para o objeto e retorna um identificador de dados. Um identificador de dados é um valor DWORD que o DDEML usa para fornecer acesso a dados no objeto DDE. Para compartilhar os dados em um objeto DDE, um aplicativo passa o identificador de dados para o DDEML e o DDEML passa o identificador para a função de retorno de chamada DDE do aplicativo que está recebendo a transação de dados.
O exemplo a seguir mostra como criar um objeto DDE e obter um identificador para o objeto. Durante a transação XTYP_ADVREQ, a função de retorno de chamada converte a hora atual em uma cadeia de caracteres ASCII, copia a cadeia de caracteres para um buffer local e cria um objeto DDE que contém a cadeia de caracteres. A função de retorno de chamada retorna o identificador para o objeto DDE (HDDEDATA) para o DDEML, que passa o identificador para o aplicativo cliente.
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.
}
}
O aplicativo de recebimento obtém um ponteiro para o objeto DDE passando o identificador de dados para a função DdeAccessData. O ponteiro retornado por DdeAccessData fornece acesso somente leitura. O aplicativo deve usar o ponteiro para revisar os dados e, em seguida, chamar a função DdeUnaccessData para invalidar o ponteiro. O aplicativo pode copiar os dados para um buffer local usando a função DdeGetData.
O exemplo a seguir obtém um ponteiro para o objeto DDE identificado pelo parâmetro hData , copia o conteúdo para um buffer local e invalida o ponteiro.
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;
//
Normalmente, quando um aplicativo que criou um identificador de dados passa esse identificador para o DDEML, o identificador se torna inválido no aplicativo de criação. Essa situação não é um problema se o aplicativo deve compartilhar dados com apenas um único aplicativo. No entanto, se um aplicativo deve compartilhar os mesmos dados com vários aplicativos, o aplicativo de criação deve especificar o sinalizador HDATA_APPOWNED em DdeCreateDataHandle. Isso dá a propriedade do objeto DDE ao aplicativo de criação e impede que o DDEML invalide o identificador de dados. O aplicativo pode então passar o identificador de dados qualquer número de vezes depois de chamar DdeCreateDataHandle apenas uma vez.
Se um aplicativo especificar o sinalizador HDATA_APPOWNED no parâmetro afCmd de DdeCreateDataHandle, ele deverá chamar a função DdeFreeDataHandle para liberar o identificador de memória, independentemente de ter passado o identificador para o DDEML. Antes de terminar, um aplicativo deve chamar DdeFreeDataHandle para liberar qualquer identificador de dados que ele criou, mas não passou para o DDEML.
Um aplicativo que ainda não passou o identificador para um objeto DDE para o DDEML pode adicionar dados ao objeto ou substituir dados no objeto usando a função DdeAddData. Normalmente, um aplicativo usa DdeAddData para preencher um objeto DDE não inicializado. Depois que um aplicativo passa um identificador de dados para o DDEML, o objeto DDE identificado pelo identificador não pode ser alterado; só pode ser libertado.