Partilhar via


Conceitos Básicos (DDE)

Esses conceitos são fundamentais para entender o Troca Dinâmica de Dados (DDE) e a Biblioteca de Gerenciamento de Troca Dinâmica de Dados (DDEML).

Interação entre Cliente e Servidor

O DDE sempre ocorre entre um aplicativo cliente e um aplicativo de servidor. O aplicativo de cliente DDE inicia a troca estabelecendo uma conversação com o servidor para enviar transações ao servidor. Uma transação é uma solicitação de dados ou de serviços. O aplicativo de servidor DDE responde às transações fornecendo dados ou serviços ao cliente. Por exemplo, um aplicativo gráfico pode conter um gráfico de barras que representa os lucros trimestrais de uma corporação, mas os dados do gráfico de barras podem estar contidos em um aplicativo de planilha. Para obter os números de lucro mais recentes, o aplicativo gráfico (o cliente) pode estabelecer uma conversa com o aplicativo de planilha (o servidor). O aplicativo gráfico poderia então enviar uma transação para o aplicativo de planilha, solicitando os números de lucro mais recentes.

Um servidor pode ter muitos clientes ao mesmo tempo e um cliente pode solicitar dados de vários servidores. Um aplicativo também pode ser um cliente e um servidor. O cliente ou o servidor podem encerrar a conversa a qualquer momento.

Transações e a Função de Retorno de Chamada DDE

O DDEML notifica um aplicativo sobre a atividade DDE que afeta o aplicativo enviando transações para a função de retorno de chamada DDE do aplicativo. Uma transação DDE é semelhante a uma mensagem, é uma constante nomeada acompanhada por outros parâmetros que contêm informações adicionais sobre a transação.

O DDEML passa uma transação para uma função de retorno de chamada DDE definida pelo aplicativo que executa uma ação apropriada para o tipo de transação. Por exemplo, quando um aplicativo cliente tenta estabelecer uma conversa com um aplicativo de servidor, o cliente chama a função DdeConnect. Essa função faz com que o DDEML envie uma transação XTYP_CONNECT para a função de retorno de chamada de DDE do servidor. A função de retorno de chamada pode permitir a conversação retornando TRUE para o DDEML ou pode negar a conversa retornando FALSE. Para obter uma discussão detalhada sobre transações, consulte Gerenciamento de transações.

Nomes de Serviço, Nomes de Tópico e Nomes de Item

Um servidor DDE usa um nome de serviço de hierarquia de três níveis (chamado de "nome do aplicativo" na documentação DDE anterior), nome do tópico e nome do item para identificar exclusivamente uma unidade de dados que o servidor pode trocar durante uma conversação.

Um nome de serviço é uma cadeia de caracteres à qual um aplicativo de servidor responde quando um cliente tenta estabelecer uma conversa com o servidor. Um cliente deve especificar esse nome de serviço para estabelecer uma conversa com o servidor. Embora um servidor possa responder a muitos nomes de serviço, a maioria dos servidores responde a apenas um nome.

Um nome de tópico é uma cadeia de caracteres que identifica um contexto de dados lógico. Para servidores que operam em documentos baseados em arquivo, os nomes de tópicos geralmente são nomes de arquivo; para outros servidores, eles são outras cadeias de caracteres específicas do aplicativo. Um cliente deve especificar um nome de tópico junto com o nome de serviço de um servidor ao tentar estabelecer uma conversa com um servidor.

Um nome de item é uma cadeia de caracteres que identifica uma unidade de dados que um servidor pode passar para um cliente durante uma transação. Por exemplo, um nome de item pode identificar um número inteiro, uma cadeia de caracteres, vários parágrafos de texto ou um bitmap.

Os nomes de serviço, de tópico e de item permitem que o cliente estabeleça uma conversa com um servidor e receba dados do servidor.

Tópico do Sistema

O Tópico do sistema fornece um contexto para informações de interesse geral para qualquer cliente DDE. Recomenda-se que os aplicativos de servidor deem suporte ao Tópico do sistema em todos os momentos. O Tópico do sistema é definido no arquivo de cabeçalho DDEML.H como SZDDESYS_TOPIC.

Para determinar quais servidores estão presentes e os tipos de informações que eles podem fornecer, um aplicativo cliente pode solicitar uma conversa sobre o Tópico do sistema ao iniciar, definindo o nome do dispositivo como NULL. Essas conversas curinga são caras em termos de desempenho do sistema, portanto, devem ser reduzidas ao mínimo. Para obter mais informações sobre como iniciar conversas DDE, consulte Gerenciamento de Conversas.

Um servidor deve dar suporte aos seguintes nomes de item no Tópico do sistema e quaisquer outros nomes de item que sejam úteis para um cliente.

Item Descrição
SZDDE_ITEM_ITEMLIST Uma lista dos itens com suporte em um tópico que não seja do sistema. (Esta lista pode variar de momento a momento e de tópico para tópico).
SZDDESYS_ITEM_FORMATS Uma lista delimitada por tabulação de cadeias de caracteres que representam todos os formatos de área de transferência potencialmente com suporte do aplicativo de serviço. As cadeias de caracteres que representam formatos de área de transferência predefinidos são equivalentes aos valores CF_ com o prefixo "CF_" removido. Por exemplo, o formato CF_TEXT é representado pela cadeia de caracteres "TEXT". Essas cadeias de caracteres devem estar em maiúsculas para identificá-las ainda mais como formatos predefinidos. A lista de formatos deve aparecer na ordem do mais rico em conteúdo para o menos rico em conteúdo. Para obter mais informações sobre formatos de área de transferência e dados de renderização, consulte Área de transferência.
SZDDESYS_ITEM_HELP Informações de interesse geral legíveis para o usuário. Este item deve conter, no mínimo, informações sobre como usar os recursos DDE do aplicativo de servidor. Essas informações podem incluir, mas não se limitam a, como especificar itens dentro de tópicos, quais cadeias de caracteres de execução o servidor pode executar, quais transações de cutucada são permitidas e como encontrar ajuda em outros itens de Tópico do sistema.
SZDDESYS_ITEM_RTNMSG Detalhes de suporte para a mensagem WM_DDE_ACK usada mais recentemente. Esse item é útil quando mais de 8 bits de dados de retorno específicos do aplicativo são necessários.
SZDDESYS_ITEM_STATUS Uma indicação do status atual do servidor. Normalmente, esse item dá suporte apenas ao formato CF_TEXT e contém a cadeia de caracteres Pronto ou Ocupado.
SZDDESYS_ITEM_SYSITEMS Uma lista dos itens com suporte no Tópico do sistema por este servidor.
SZDDESYS_ITEM_TOPICS Uma lista dos tópicos com suporte do servidor no momento atual. (Esta lista pode variar de momento a momento).

Esses nomes de item são valores definidos no arquivo de cabeçalho DDEML.H. Para obter identificadores de cadeia de caracteres para essas cadeias de caracteres, um aplicativo deve usar as funções de gerenciamento de cadeia de caracteres DDEML, assim como faria para qualquer outra cadeia de caracteres em um aplicativo DDEML. Para obter mais informações sobre o gerenciamento de cadeias de caracteres, consulte Gerenciamento de Cadeias de Caracteres.

Inicialização

Antes de chamar qualquer outra função DDEML, um aplicativo deve chamar a função DdeInitialize. DdeInitialize obtém um identificador de instância para o aplicativo, registra a função de retorno de chamada DDE do aplicativo com o DDE e especifica os sinalizadores de filtro de transação para a função de retorno de chamada.

Cada instância de um aplicativo ou uma DLL deve passar seu identificador de instância como o parâmetro idInst para qualquer outra função DDEML que o exija. A finalidade de várias instâncias DDEML é dar suporte a DLLs que devem usar o DDEML ao mesmo tempo que um aplicativo. Um aplicativo não deve usar mais de uma instância do DDEML.

Os filtros de transação otimizam o desempenho do sistema, impedindo que o DDEML passe transações indesejadas para a função de retorno de chamada DDE do aplicativo. Um aplicativo define os filtros de transação no parâmetro DdeInitialize ufCmd. Um aplicativo deve especificar um sinalizador de filtro de transação para cada tipo de transação que ele não processa em sua função de retorno de chamada. Um aplicativo pode alterar seus filtros de transação com uma chamada subsequente para DdeInitialize. Para obter mais informações sobre transações, consulte Gerenciamento de Transações.

O exemplo a seguir mostra como inicializar um aplicativo para usar o DDEML.

DWORD idInst = 0; 
HINSTANCE hinst; 
 
DdeInitialize(&idInst,         // receives instance identifier 
    (PFNCALLBACK) DdeCallback, // pointer to callback function 
    CBF_FAIL_EXECUTES |        // filter XTYPE_EXECUTE 
    CBF_SKIP_ALLNOTIFICATIONS, // filter notifications 
    0); 

Um aplicativo deve chamar a função DdeUninitialize quando não for mais usar o DDEML. Essa função encerra todas as conversações abertas no momento para o aplicativo e libera os recursos DDEML que o sistema alocou para o aplicativo.

Função de retorno de chamada

Um aplicativo que usa o DDEML deve fornecer uma função de retorno de chamada que processa os eventos DDE que afetam o aplicativo. O DDEML notifica um aplicativo sobre esses eventos enviando transações para a função de retorno de chamada DDE do aplicativo. As transações que uma função de retorno de chamada recebe dependem de qual filtro de retorno de chamada sinaliza o aplicativo especificado em DdeInitialize e se o aplicativo é um cliente, um servidor ou ambos. Para obter mais informações, consulte DdeCallback.

O exemplo a seguir mostra a estrutura geral de uma função de retorno de chamada para um aplicativo cliente típico.

HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1, 
    hsz2, hdata, dwData1, dwData2) 
UINT uType;       // transaction type 
UINT uFmt;        // clipboard data format 
HCONV hconv;      // handle to conversation 
HSZ hsz1;         // handle to string 
HSZ hsz2;         // handle to string 
HDDEDATA hdata;   // handle to global memory object 
DWORD dwData1;    // transaction-specific data 
DWORD dwData2;    // transaction-specific data 
{ 
    switch (uType) 
    { 
        case XTYP_REGISTER: 
        case XTYP_UNREGISTER: 
            . 
            . 
            . 
            return (HDDEDATA) NULL; 
 
        case XTYP_ADVDATA: 
            . 
            . 
            . 
            return (HDDEDATA) DDE_FACK; 
 
        case XTYP_XACT_COMPLETE: 
            
            // 
            
            return (HDDEDATA) NULL; 
 
        case XTYP_DISCONNECT: 
            
            // 
            
            return (HDDEDATA) NULL; 
 
        default: 
            return (HDDEDATA) NULL; 
    } 
} 

O parâmetro uType especifica o tipo de transação enviado para a função de retorno de chamada pelo DDEML. Os valores dos parâmetros restantes dependem do tipo de transação. Os tipos de transação e os eventos que os geram são descritos nos tópicos a seguir. Para obter informações detalhadas sobre cada tipo de transação, consulte Gerenciamento de Transações.

Gerenciamento de Cadeias de Caracteres

Para executar uma tarefa DDE, muitas funções DDEML exigem acesso a cadeias de caracteres. Por exemplo, um cliente deve especificar um nome de serviço e um nome de tópico ao chamar a função DdeConnect para solicitar uma conversa com um servidor. Um aplicativo especifica uma cadeia de caracteres passando um identificador de cadeia de caracteres (HSZ) em vez de um ponteiro em uma função DDEML. Um identificador de cadeia de caracteres é um valor DWORD, atribuído pelo sistema, que identifica uma cadeia de caracteres.

Um aplicativo pode obter um identificador de cadeia de caracteres para uma cadeia de caracteres específica chamando a função DdeCreateStringHandle. Essa função registra a cadeia de caracteres com o sistema e retorna um identificador de cadeia de caracteres para o aplicativo. O aplicativo pode passar o identificador para funções DDEML que devem acessar a cadeia de caracteres. O exemplo a seguir obtém identificadores de cadeia de caracteres para a cadeia de caracteres de Tópico do sistema e a cadeia de caracteres do nome do serviço.

HSZ hszServName; 
HSZ hszSysTopic; 
hszServName = DdeCreateStringHandle( 
    idInst,         // instance identifier 
    "MyServer",     // string to register 
    CP_WINANSI);    // Windows ANSI code page 
 
hszSysTopic = DdeCreateStringHandle( 
    idInst,         // instance identifier 
    SZDDESYS_TOPIC, // System topic 
    CP_WINANSI);    // Windows ANSI code page 
    

O parâmetro idInst no exemplo anterior especifica o identificador de instância obtido pela função DdeInitialize.

A função de retorno de chamada DDE de um aplicativo recebe um ou mais identificadores de cadeia de caracteres durante a maioria das transações DDE. Por exemplo, um servidor recebe dois identificadores de cadeia de caracteres durante a transação XTYP_REQUEST: um identifica uma cadeia de caracteres especificando um nome de tópico e o outro identifica uma cadeia de caracteres especificando um nome de item. Um aplicativo pode obter o comprimento da cadeia de caracteres que corresponde a um identificador de cadeia de caracteres e copiar a cadeia de caracteres para um buffer definido pelo aplicativo chamando a função DdeQueryString, conforme mostrado no exemplo a seguir.

DWORD idInst; 
DWORD cb; 
HSZ hszServ; 
PSTR pszServName; 
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0, 
    CP_WINANSI) + 1; 
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb); 
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI); 

Um identificador de cadeia de caracteres específico da instância não pode ser mapeado de um identificador de cadeia de caracteres para uma cadeia de caracteres e de volta para um identificador de cadeia de caracteres. Por exemplo, embora DdeQueryString crie uma cadeia de caracteres de um identificador de cadeia de caracteres e, em seguida, DdeCreateStringHandle crie um identificador de cadeia de caracteres dessa cadeia de caracteres, os dois identificadores não são iguais, conforme mostrado no exemplo a seguir.

DWORD idInst; 
DWORD cb; 
HSZ hszInst, hszNew; 
PSZ pszInst; 
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI); 
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI); 
// hszNew != hszInst ! 

Para comparar os valores de dois identificadores de cadeia de caracteres, use a função DdeCmpStringHandles.

Um identificador de cadeia de caracteres passado para a função de retorno de chamada DDE de um aplicativo torna-se inválido quando a função de retorno de chamada retorna. Um aplicativo pode salvar um identificador de cadeia de caracteres para uso depois que a função de retorno de chamada retornar usando a função DdeKeepStringHandle.

Quando um aplicativo chama DdeCreateStringHandle, o sistema insere a cadeia de caracteres especificada em uma tabela de cadeias de caracteres e gera um identificador que ele usa para acessar a cadeia de caracteres. O sistema também mantém uma contagem de uso para cada cadeia de caracteres na tabela de cadeias de caracteres.

Quando um aplicativo chama DdeCreateStringHandle e especifica uma cadeia de caracteres que já existe na tabela, o sistema incrementa a contagem de uso em vez de adicionar outra ocorrência da cadeia de caracteres. (Um aplicativo também pode incrementar a contagem de uso usando DdeKeepStringHandle). Quando um aplicativo chama a função DdeFreeStringHandle, o sistema diminui a contagem de uso.

Uma cadeia de caracteres é removida da tabela quando sua contagem de uso é igual a zero. Como mais de um aplicativo pode obter o identificador para uma cadeia de caracteres específica, um aplicativo não deve liberar um identificador de cadeia de caracteres mais vezes do que criou ou reteve o identificador. Caso contrário, o aplicativo poderá fazer com que a cadeia de caracteres seja removida da tabela, negando a outros aplicativos o acesso à cadeia de caracteres.

As funções de gerenciamento de cadeia de caracteres DDEML são baseadas no gerenciador de átomos e estão sujeitas às mesmas restrições de tamanho do que os átomos.

DDEML e Threads

A função DdeInitialize registra um aplicativo no DDEML, criando uma instância DDEML. Uma instância DDEML é baseada em thread, associada ao thread que chamou DdeInitialize.

Todas as chamadas de função DDEML para objetos pertencentes a uma instância DDEML devem ser feitas do mesmo thread que chamou DdeInitialize para criar a instância. Se você chamar uma função DDEML de um thread diferente, a função falhará. Você não pode acessar uma conversa DDEML de um thread diferente daquele que alocou a conversa.