Gerenciamento de Conversas
Uma conversa entre um cliente e um servidor é sempre estabelecida a pedido do cliente. Quando uma conversa é estabelecida, cada parceiro recebe um identificador que identifica a conversa. Os parceiros usam esse identificador em outras funções da Biblioteca de Gerenciamento de Intercâmbio de Dados Dinâmicos (DDEML) para enviar transações e gerenciar a conversa. Um cliente pode solicitar uma conversa com um único servidor ou pode solicitar várias conversas com um ou mais servidores.
Os tópicos a seguir descrevem como um aplicativo estabelece novas conversas e obtém informações sobre conversas existentes.
Conversas Individuais
Um aplicativo cliente solicita uma única conversa com um servidor chamando a função DdeConnect e especificando identificadores de cadeia de caracteres que identificam as cadeias de caracteres que contêm o nome do serviço do aplicativo de servidor e o nome do tópico da conversa. O DDEML responde enviando a transação XTYP_CONNECT para a função de retorno de chamada DDE (Dynamic Data Exchange) de cada aplicativo de servidor que registrou um nome de serviço que corresponde ao especificado no DdeConnect ou desativou a filtragem de nome de serviço chamando DdeNameService. Um servidor também pode filtrar transações XTYP_CONNECT especificando o sinalizador de filtro CBF_FAIL_CONNECTIONS na função DdeInitialize . Durante a transação XTYP_CONNECT, o DDEML passa o nome do serviço e o nome do tópico para o servidor. O servidor deve examinar os nomes e retornar TRUE se ele oferece suporte ao par de nomes de nome de serviço e tópico ou FALSE se não o fizer.
Se nenhum servidor responder positivamente à solicitação de conexão do cliente, o cliente receberá NULL do DdeConnect e nenhuma conversa será estabelecida. Se um servidor retornar TRUE, uma conversa será estabelecida e o cliente receberá um identificador de conversa — um valor DWORD que identifica a conversa. O cliente usa o identificador em chamadas DDEML subsequentes para obter dados do servidor. O servidor recebe a transação XTYP_CONNECT_CONFIRM (a menos que o servidor tenha especificado o sinalizador de filtro CBF_SKIP_CONNECT_CONFIRMS). Essa transação passa o identificador de conversa para o servidor.
O exemplo a seguir solicita uma conversa no tópico System com um servidor que reconhece o nome de serviço MyServer. Os parâmetros hszServName e hszSysTopic são identificadores de cadeia de caracteres criados anteriormente.
HCONV hConv; // conversation handle
HWND hwndParent; // parent window handle
HSZ hszServName; // service name string handle
HSZ hszSysTopic; // System topic string handle
hConv = DdeConnect(
idInst, // instance identifier
hszServName, // service name string handle
hszSysTopic, // System topic string handle
(PCONVCONTEXT) NULL); // use default context
if (hConv == NULL)
{
MessageBox(hwndParent, "MyServer is unavailable.",
(LPSTR) NULL, MB_OK);
return FALSE;
}
No exemplo anterior, o DdeConnect faz com que a função de retorno de chamada DDE do aplicativo MyServer receba uma transação XTYP_CONNECT.
No exemplo a seguir, o servidor responde à transação XTYP_CONNECT comparando o identificador de cadeia de caracteres de nome de tópico que o DDEML passou para o servidor com cada elemento na matriz de identificadores de cadeia de caracteres de nome de tópico suportados pelo servidor. Se o servidor encontrar uma correspondência, ele estabelecerá a conversa.
#define CTOPICS 5
HSZ hsz1; // string handle passed by DDEML
HSZ ahszTopics[CTOPICS]; // array of supported topics
int i; // loop counter
// Use a switch statement to examine transaction types.
// Here is the connect case.
case XTYP_CONNECT:
for (i = 0; i < CTOPICS; i++)
{
if (hsz1 == ahszTopics[i])
return TRUE; // establish a conversation
}
return FALSE; // Topic not supported; deny conversation.
// Process other transaction types.
Se o servidor retornar TRUE em resposta à transação XTYP_CONNECT, o DDEML enviará uma transação XTYP_CONNECT_CONFIRM para a função de retorno de chamada DDE do servidor. O servidor pode obter o identificador para a conversa processando essa transação.
Um cliente pode estabelecer uma conversa curinga especificando NULL para o identificador de cadeia de caracteres de nome de serviço, o identificador de cadeia de caracteres de nome de tópico ou ambos em uma chamada para DdeConnect. Se pelo menos um dos identificadores de cadeia de caracteres for NULL, o DDEML enviará a transação XTYP_WILDCONNECT para as funções de retorno de chamada de todos os aplicativos DDE (exceto aqueles que filtram a transação XTYP_WILDCONNECT). Cada aplicativo de servidor deve responder retornando um identificador de dados que identifica uma matriz terminada em nulo de estruturas HSZPAIR. Se o aplicativo de servidor não tiver chamado DdeNameService para registrar seus nomes de serviço e se a filtragem estiver ativada, o servidor não receberá XTYP_WILDCONNECT transações. Para obter mais informações sobre identificadores de dados, consulte Gerenciamento de dados.
A matriz deve conter uma estrutura para cada par de nome de serviço e nome de tópico que corresponda ao par especificado pelo cliente. O DDEML seleciona um dos pares para estabelecer uma conversa e devolve ao cliente um identificador que identifica a conversa. O DDEML envia a transação XTYP_CONNECT_CONFIRM para o servidor (a menos que o servidor filtre essa transação). O exemplo a seguir mostra uma resposta típica do servidor à transação XTYP_WILDCONNECT.
#define CTOPICS 2
UINT uType;
HSZPAIR ahszp[(CTOPICS + 1)];
HSZ ahszTopicList[CTOPICS];
HSZ hszServ, hszTopic;
WORD i, j;
if (uType == XTYP_WILDCONNECT)
{
// Scan the topic list and create an array of HSZPAIR structures.
j = 0;
for (i = 0; i < CTOPICS; i++)
{
if (hszTopic == (HSZ) NULL ||
hszTopic == ahszTopicList[i])
{
ahszp[j].hszSvc = hszServ;
ahszp[j++].hszTopic = ahszTopicList[i];
}
}
// End the list with an HSZPAIR structure that contains NULL
// string handles as its members.
ahszp[j].hszSvc = NULL;
ahszp[j++].hszTopic = NULL;
// Return a handle to a global memory object containing the
// HSZPAIR structures.
return DdeCreateDataHandle(
idInst, // instance identifier
(LPBYTE) &ahszp, // pointer to HSZPAIR array
sizeof(HSZ) * j, // length of the array
0, // start at the beginning
(HSZ) NULL, // no item name string
0, // return the same format
0); // let the system own it
}
O cliente ou o servidor pode encerrar uma conversa a qualquer momento chamando a função DdeDisconnect. Essa função faz com que a função de retorno de chamada do parceiro na conversa receba a transação XTYP_DISCONNECT (a menos que o parceiro tenha especificado o sinalizador de filtro CBF_SKIP_DISCONNECTS). Normalmente, um aplicativo responde à transação XTYP_DISCONNECT usando a função DdeQueryConvInfo para obter informações sobre a conversa que terminou. Depois que a função de retorno de chamada retorna do processamento da transação XTYP_DISCONNECT , o identificador de conversa não é mais válido.
Um aplicativo cliente que recebe uma transação XTYP_DISCONNECT em sua função de retorno de chamada DDE pode tentar restabelecer a conversa chamando a função DdeReconnect. O cliente deve chamar DdeReconnect de dentro de sua função de retorno de chamada DDE.
Várias conversas
Um aplicativo cliente pode usar a função DdeConnectList para determinar se algum servidor de interesse está disponível no sistema. Um cliente especifica um nome de serviço e um nome de tópico quando chama DdeConnectList, fazendo com que o DDEML transmita a transação XTYP_WILDCONNECT para as funções de retorno de chamada DDE de todos os servidores que correspondem ao nome do serviço (exceto aqueles que filtram a transação). A função de retorno de chamada de um servidor deve retornar um identificador de dados que identifique uma matriz terminada em nulo de estruturas HSZPAIR. A matriz deve conter uma estrutura para cada par de nome de serviço e nome de tópico que corresponda ao par especificado pelo cliente. O DDEML estabelece uma conversa para cada estrutura HSZPAIR preenchida pelo servidor e retorna um identificador de lista de conversação para o cliente. O servidor recebe o identificador de conversa por meio da transação XTYP_CONNECT (a menos que o servidor filtre essa transação).
Um cliente pode especificar NULL para o nome do serviço, nome do tópico ou ambos quando chama DdeConnectList. Se o nome do serviço for NULL, todos os servidores no sistema que oferecem suporte ao nome de tópico especificado responderão. Uma conversa é estabelecida com cada servidor que responde, incluindo várias instâncias do mesmo servidor. Se o nome do tópico for NULL, uma conversa será estabelecida em cada tópico reconhecido por cada servidor que corresponda ao nome do serviço.
Um cliente pode usar as funções DdeQueryNextServer e DdeQueryConvInfo para identificar os servidores que respondem a DdeConnectList. DdeQueryNextServer retorna o próximo identificador de conversa em uma lista de conversação e DdeQueryConvInfo preenche uma estrutura CONVINFO com informações sobre a conversa. O cliente pode manter os identificadores de conversa necessários e descartar o restante da lista de conversas.
O exemplo a seguir usa DdeConnectList para estabelecer conversas com todos os servidores que oferecem suporte ao tópico System e, em seguida, usa as funções DdeQueryNextServer e DdeQueryConvInfo para obter os identificadores de cadeia de caracteres de nome de serviço dos servidores e armazená-los em um buffer.
HCONVLIST hconvList; // conversation list
DWORD idInst; // instance identifier
HSZ hszSystem; // System topic
HCONV hconv = NULL; // conversation handle
CONVINFO ci; // holds conversation data
UINT cConv = 0; // count of conv. handles
HSZ *pHsz, *aHsz; // point to string handles
// Connect to all servers that support the System topic.
hconvList = DdeConnectList(idInst, NULL, hszSystem, NULL, NULL);
// Count the number of handles in the conversation list.
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL)
cConv++;
// Allocate a buffer for the string handles.
hconv = NULL;
aHsz = (HSZ *) LocalAlloc(LMEM_FIXED, cConv * sizeof(HSZ));
// Copy the string handles to the buffer.
pHsz = aHsz;
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL)
{
DdeQueryConvInfo(hconv, QID_SYNC, (PCONVINFO) &ci);
DdeKeepStringHandle(idInst, ci.hszSvcPartner);
*pHsz++ = ci.hszSvcPartner;
}
// Use the handles; converse with the servers.
// Free the memory and terminate the conversations.
LocalFree((HANDLE) aHsz);
DdeDisconnectList(hconvList);
Um aplicativo pode encerrar uma conversa individual em uma lista de conversas chamando a função DdeDisconnect. Um aplicativo pode encerrar todas as conversas em uma lista de conversas chamando a função DdeDisconnectList. Ambas as funções fazem com que o DDEML envie transações XTYP_DISCONNECT para a função de retorno de chamada DDE de cada parceiro. DdeDisconnectList envia uma transação XTYP_DISCONNECT para cada identificador de conversa na lista.
Um cliente pode recuperar uma lista dos identificadores de conversa em uma lista de conversação passando um identificador de lista de conversação existente para DdeConnectList. O processo de enumeração remove os identificadores de conversas encerradas da lista e conversas não duplicadas que se ajustam ao nome de serviço e ao nome de tópico especificados são adicionadas.
Se DdeConnectList especificar um identificador de lista de conversação existente, a função criará uma nova lista de conversação que contém os identificadores de quaisquer novas conversas e os identificadores da lista existente.
Se existirem conversas duplicadas, o DdeConnectList tentará impedir identificadores de conversa duplicados na lista de conversas. Uma conversa duplicada é uma segunda conversa com o mesmo servidor no mesmo nome de serviço e nome de tópico. Duas dessas conversas teriam pegadas diferentes, mas identificariam a mesma conversa.