Conceitos Básicos (DDE)

Esses conceitos são fundamentais para entender o DDE (Dynamic Data Exchange) e a DDEML (Dynamic Data Exchange Management Library).

Interação Cliente e Servidor

O DDE sempre ocorre entre um aplicativo cliente e um aplicativo servidor. O aplicativo cliente DDE inicia a troca estabelecendo uma conversa com o servidor para enviar transações ao servidor. Uma transação é uma solicitação de dados ou serviços. O aplicativo de servidor DDE responde a 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 para o gráfico de barras podem estar contidos em um aplicativo de planilha. Para obter os últimos números de lucro, o aplicativo gráfico (o cliente) poderia 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 últimos números de lucro.

Um servidor pode ter vários 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 ao 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 DDE do servidor. A função de retorno de chamada pode permitir a conversa retornando TRUE para o DDEML, ou pode negar a conversa retornando FALSE. Para obter uma discussão detalhada das 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 "nome do aplicativo" na documentação anterior do DDE), nome do tópico e nome do item para identificar exclusivamente uma unidade de dados que o servidor pode trocar durante uma conversa.

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ógicos. Para servidores que operam em documentos baseados em arquivo, os nomes de tópicos geralmente são nomes de arquivos; 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 quando ele tenta 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 inteiro, uma cadeia de caracteres, vários parágrafos de texto ou um bitmap.

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

Tópico do Sistema

O tópico Sistema fornece um contexto para informações de interesse geral para qualquer cliente DDE. É recomendável que os aplicativos de servidor ofereçam suporte ao tópico Sistema o tempo todo. O tópico System é definido no DDEML. Arquivo de cabeçalho 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 Sistema ao iniciar, definindo o nome do dispositivo como NULL. Essas conversas curinga são caras em termos de desempenho do sistema, por isso devem ser reduzidas ao mínimo. Para obter mais informações sobre como iniciar conversas DDE, consulte Gerenciamento de conversas.

Um servidor deve oferecer suporte aos seguintes nomes de item dentro do tópico Sistema e quaisquer outros nomes de item que sejam úteis para um cliente.

Item Descrição
SZDDE_ITEM_ITEMLIST Uma lista dos itens suportados em um tópico que não seja do sistema. (Esta lista pode variar de momento para 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 da área de transferência potencialmente suportados pelo aplicativo de serviço. As cadeias de caracteres que representam formatos predefinidos da área de transferência 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 ser 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 pelo utilizador. Esse 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 estão limitadas a, como especificar itens dentro de tópicos, quais cadeias de caracteres de execução o servidor pode executar, quais transações poke são permitidas e como encontrar ajuda em outros itens de tópico do sistema.
SZDDESYS_ITEM_RTNMSG Detalhes de suporte para a mensagem de WM_DDE_ACK usada mais recentemente. Este 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 oferece suporte apenas ao formato CF_TEXT e contém a cadeia de caracteres Pronto ou Ocupado.
SZDDESYS_ITEM_SYSITEMS Uma lista dos itens suportados no tópico Sistema por este servidor.
SZDDESYS_ITEM_TOPICS Uma lista dos tópicos suportados pelo servidor no momento atual. (Esta lista pode variar de momento para momento.)

Esses nomes de item são valores definidos no DDEML. Arquivo de cabeçalho 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 como gerenciar 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 exija isso. O objetivo de várias instâncias DDEML é oferecer suporte a DLLs que devem usar o DDEML ao mesmo tempo em que um aplicativo o está usando. 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 DdeInitializeufCmd. 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 conversas atualmente abertas para o aplicativo e libera os recursos DDEML do sistema alocados 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 de tais 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 String

Para executar uma tarefa DDE, muitas funções DDEML requerem acesso a cadeias de caracteres. Por exemplo, um cliente deve especificar um nome de serviço e um nome de tópico quando chama 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 System e a cadeia de caracteres de nome de 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 do identificador de cadeia de caracteres para a cadeia de caracteres e de volta para o identificador de cadeia de caracteres. Por exemplo, embora DdeQueryString crie uma cadeia de caracteres a partir de um identificador de cadeia de caracteres e, em seguida, DdeCreateStringHandle cria um identificador de cadeia de caracteres a partir dessa cadeia de caracteres, os dois identificadores não são os mesmos, 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 duas alças 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 retorna usando a função DdeKeepStringHandle.

Quando um aplicativo chama DdeCreateStringHandle, o sistema insere a cadeia de caracteres especificada em uma tabela de cadeia 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 pode 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 que os átomos.

DDEML e Threads

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

Todas as chamadas de função DDEML para objetos pertencentes a uma instância DDEML devem ser feitas a partir 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á. Não é possível acessar uma conversa DDEML a partir de um thread diferente daquele que alocou a conversa.