Grundlegende Konzepte (DDE)

Diese Konzepte sind wichtig, um dynamische Daten Exchange (DDE) und die dynamische Daten Exchange Management Library (DDEML) zu verstehen.

Client- und Serverinteraktion

DDE tritt immer zwischen einer Clientanwendung und einer Serveranwendung auf. Die DDE-Clientanwendung initiiert den Austausch, indem sie eine Konversation mit dem Server einrichtet, um Transaktionen an den Server zu senden. Eine Transaktion ist eine Anforderung für Daten oder Dienste. Die DDE-Serveranwendung reagiert auf Transaktionen, indem sie Dem Client Daten oder Dienste bereitstellt. Beispielsweise kann eine Grafikanwendung ein Balkendiagramm enthalten, das den Quartalsgewinn eines Unternehmens darstellt, aber die Daten für das Balkendiagramm können in einer Tabellenkalkulationsanwendung enthalten sein. Um die neuesten Gewinnzahlen zu erhalten, könnte die Grafikanwendung (der Client) eine Konversation mit der Tabellenkalkulationsanwendung (dem Server) herstellen. Die Grafikanwendung könnte dann eine Transaktion an die Tabellenkalkulationsanwendung senden und die neuesten Gewinnzahlen anfordern.

Ein Server kann über viele Clients gleichzeitig verfügen, und ein Client kann Daten von mehreren Servern anfordern. Eine Anwendung kann auch ein Client und ein Server sein. Entweder der Client oder der Server kann die Konversation jederzeit beenden.

Transaktionen und die DDE-Rückruffunktion

Die DDEML benachrichtigt eine Anwendung über die DDE-Aktivität, die sich auf die Anwendung auswirkt, indem Transaktionen an die DDE-Rückruffunktion der Anwendung gesendet werden. Eine DDE-Transaktion ähnelt einer Nachricht, bei der es sich um eine benannte Konstante handelt, die von anderen Parametern begleitet wird, die zusätzliche Informationen über die Transaktion enthalten.

Die DDEML übergibt eine Transaktion an eine anwendungsdefinierte DDE-Rückruffunktion, die eine Aktion ausführt, die dem Transaktionstyp entspricht. Wenn beispielsweise eine Clientanwendung versucht, eine Konversation mit einer Serveranwendung herzustellen, ruft der Client die DdeConnect-Funktion auf. Diese Funktion bewirkt, dass die DDEML eine XTYP _ CONNECT-Transaktion an die DDE-Rückruffunktion des Servers sendet. Die Rückruffunktion kann die Konversation zulassen, indem SIE TRUE an die DDEML zurückgibt, oder sie kann die Konversation ablehnen, indem false zurückgegeben wird. Eine ausführliche Erläuterung der Transaktionen finden Sie unter Transaktionsverwaltung.

Dienstnamen, Themennamen und Elementnamen

Ein DDE-Server verwendet einen Hierarchiedienstnamen mit drei Ebenen (in der vorherigen DDE-Dokumentation als "Anwendungsname" bezeichnet), einen Themennamen und einen Elementnamen, um eine Dateneinheit eindeutig zu identifizieren, die der Server während einer Konversation austauschen kann.

Ein Dienstname ist eine Zeichenfolge, auf die eine Serveranwendung antwortet, wenn ein Client versucht, eine Konversation mit dem Server herzustellen. Ein Client muss diesen Dienstnamen angeben, um eine Konversation mit dem Server herzustellen. Obwohl ein Server auf viele Dienstnamen reagieren kann, antworten die meisten Server nur auf einen Namen.

Ein Themenname ist eine Zeichenfolge, die einen logischen Datenkontext identifiziert. Bei Servern, die mit dateibasierten Dokumenten arbeiten, sind Themennamen in der Regel Dateinamen. für andere Server sind dies andere anwendungsspezifische Zeichenfolgen. Ein Client muss einen Themennamen zusammen mit dem Dienstnamen eines Servers angeben, wenn versucht wird, eine Konversation mit einem Server herzustellen.

Ein Elementname ist eine Zeichenfolge, die eine Dateneinheit identifiziert, die ein Server während einer Transaktion an einen Client übergeben kann. Beispielsweise kann ein Elementname eine ganze Zahl, eine Zeichenfolge, mehrere Textabschnitte oder eine Bitmap identifizieren.

Die Dienst-, Themen- und Elementnamen ermöglichen es dem Client, eine Konversation mit einem Server herzustellen und Daten vom Server zu empfangen.

Systemthema

Das Thema System enthält einen Kontext für Informationen, die für jeden DDE-Client von allgemeinem Interesse sind. Es wird empfohlen, dass Serveranwendungen das Thema System jederzeit unterstützen. Das Thema System ist in der DDEML definiert. H-Headerdatei als _ SZDDESYS-THEMA.

Um zu bestimmen, welche Server vorhanden sind und welche Arten von Informationen sie bereitstellen können, kann eine Clientanwendung beim Start eine Konversation im Thema System anfordern und den Gerätenamen auf NULL festlegen. Solche Platzhalterkonversationen sind im Hinblick auf die Systemleistung teuer, daher sollten sie auf ein Minimum beschränkt werden. Weitere Informationen zum Initiieren von DDE-Konversationen finden Sie unter Conversation Management.

Ein Server muss die folgenden Elementnamen innerhalb des Themas System und alle anderen Elementnamen unterstützen, die für einen Client nützlich sind.

Element Beschreibung
SZDDE _ ITEM _ ITEMLIST Eine Liste der Elemente, die unter einem Nicht-Systemthema unterstützt werden. (Diese Liste kann von Moment zu Moment und von Thema zu Thema variieren.)
_SZDDESYS-ELEMENTFORMATE _ Eine durch Tabstopps getrennte Liste von Zeichenfolgen, die alle Zwischenablageformate darstellen, die möglicherweise von der Dienstanwendung unterstützt werden. Zeichenfolgen, die vordefinierte Zwischenablageformate darstellen, entsprechen den _ CF-Werten, wobei das _ Präfix "CF" entfernt wurde. Beispielsweise wird das CF _ TEXT-Format durch die Zeichenfolge "TEXT" dargestellt. Diese Zeichenfolgen müssen groß geschrieben werden, um sie weiter als vordefinierte Formate zu identifizieren. Die Liste der Formate muss in der Reihenfolge angezeigt werden, in der die inhalten am besten zu den am wenigsten umfangreichen Inhalten reichen. Weitere Informationen zu Zwischenablageformaten und Renderingdaten finden Sie unter Zwischenablage.
_SZDDESYS-ELEMENTHILFE _ Benutzerlesbare Informationen von allgemeinem Interesse. Dieses Element muss mindestens Informationen zur Verwendung der DDE-Funktionen der Serveranwendung enthalten. Diese Informationen können u. a. angeben, wie Elemente innerhalb von Themen angegeben werden, welche Ausführungszeichenfolgen der Server ausführen kann, welche transaktionen zulässig sind und wie Sie Hilfe zu anderen Systemthemaelementen finden.
SZDDESYS _ ITEM _ RTNMSG Unterstützende Details für die zuletzt verwendete WM _ _ DDE-ACK-Nachricht. Dieses Element ist nützlich, wenn mehr als 8 Bits anwendungsspezifischer Rückgabedaten erforderlich sind.
_SZDDESYS-ELEMENTSTATUS _ Ein Hinweis auf den aktuellen Status des Servers. In der Regel unterstützt dieses Element nur das CF _ TEXT-Format und enthält die Zeichenfolge Bereit oder Ausgelastet.
SZDDESYS _ ITEM _ SYSITEMS Eine Liste der Elemente, die unter dem Thema System von diesem Server unterstützt werden.
_SZDDESYS-ARTIKELTHEMEN _ Eine Liste der Themen, die vom Server zum aktuellen Zeitpunkt unterstützt werden. (Diese Liste kann von Moment zu Moment variieren.)

Bei diesen Elementnamen handelt es sich um Werte, die in der DDEML definiert sind. H-Headerdatei. Um Zeichenfolgenhandles für diese Zeichenfolgen abzurufen, muss eine Anwendung die DDEML-Zeichenfolgenverwaltungsfunktionen wie jede andere Zeichenfolge in einer DDEML-Anwendung verwenden. Weitere Informationen zum Verwalten von Zeichenfolgen finden Sie unter Zeichenfolgenverwaltung.

Initialisierung

Vor dem Aufrufen einer anderen DDEML-Funktion muss eine Anwendung die DdeInitialize-Funktion aufrufen. DdeInitialize ruft einen Instanzbezeichner für die Anwendung ab, registriert die DDE-Rückruffunktion der Anwendung bei DDE und gibt die Transaktionsfilterflags für die Rückruffunktion an.

Jede Instanz einer Anwendung oder DLL muss ihren Instanzbezeichner als idInst-Parameter an jede andere DDEML-Funktion übergeben, die sie erfordert. Der Zweck mehrerer DDEML-Instanzen besteht darin, DLLs zu unterstützen, die die DDEML gleichzeitig von einer Anwendung verwenden müssen. Eine Anwendung darf nicht mehr als eine Instanz der DDEML verwenden.

Transaktionsfilter optimieren die Systemleistung, indem verhindert wird, dass die DDEML unerwünschte Transaktionen an die DDE-Rückruffunktion der Anwendung übergibt. Eine Anwendung legt die Transaktionsfilter im DdeInitialize ufCmd-Parameter fest. Eine Anwendung muss ein Transaktionsfilterflag für jeden Transaktionstyp angeben, den sie nicht in ihrer Rückruffunktion verarbeitet. Eine Anwendung kann ihre Transaktionsfilter mit einem nachfolgenden Aufruf von DdeInitialize ändern. Weitere Informationen zu Transaktionen finden Sie unter Transaktionsverwaltung.

Das folgende Beispiel zeigt, wie eine Anwendung initialisiert wird, um die DDEML zu verwenden.

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); 

Eine Anwendung muss die DdeUninitialize-Funktion aufrufen, wenn sie die DDEML nicht mehr verwenden wird. Diese Funktion beendet alle Konversationen, die derzeit für die Anwendung geöffnet sind, und gibt die DDEML-Ressourcen frei, die dem System für die Anwendung zugeordnet sind.

Rückruffunktion

Eine Anwendung, die die DDEML verwendet, muss eine Rückruffunktion bereitstellen, die die DDE-Ereignisse verarbeitet, die sich auf die Anwendung auswirken. Die DDEML benachrichtigt eine Anwendung über solche Ereignisse, indem transaktionen an die DDE-Rückruffunktion der Anwendung gesendet werden. Welche Transaktionen eine Rückruffunktion empfängt, hängt davon ab, welcher Rückruffilter die in DdeInitialize angegebene Anwendung kennzeichnet und ob es sich bei der Anwendung um einen Client, einen Server oder beides handelt. Weitere Informationen finden Sie unter DdeCallback.

Das folgende Beispiel zeigt die allgemeine Struktur einer Rückruffunktion für eine typische Clientanwendung.

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; 
    } 
} 

Der uType-Parameter gibt den Transaktionstyp an, der von der DDEML an die Rückruffunktion gesendet wird. Die Werte der verbleibenden Parameter hängen vom Transaktionstyp ab. Die Transaktionstypen und die Ereignisse, die sie generieren, werden in den folgenden Themen beschrieben. Ausführliche Informationen zu den einzelnen Transaktionstypen finden Sie unter Transaktionsverwaltung.

Zeichenfolgenverwaltung

Um eine DDE-Aufgabe auszuführen, benötigen viele DDEML-Funktionen Zugriff auf Zeichenfolgen. Beispielsweise muss ein Client einen Dienstnamen und einen Themennamen angeben, wenn er die DdeConnect-Funktion aufruft, um eine Konversation mit einem Server anzufordern. Eine Anwendung gibt eine Zeichenfolge an, indem ein Zeichenfolgenhandle (HSZ) anstelle eines Zeigers in einer DDEML-Funktion übergeben wird. Ein Zeichenfolgenhandle ist ein vom System zugewiesener DWORD-Wert, der eine Zeichenfolge identifiziert.

Eine Anwendung kann ein Zeichenfolgenhandle für eine bestimmte Zeichenfolge abrufen, indem sie die DdeCreateStringHandle-Funktion aufruft. Diese Funktion registriert die Zeichenfolge beim System und gibt ein Zeichenfolgenhandle an die Anwendung zurück. Die Anwendung kann das Handle an DDEML-Funktionen übergeben, die auf die Zeichenfolge zugreifen müssen. Im folgenden Beispiel werden Zeichenfolgenhandles für die System-Themenzeichenfolge und die Dienstnamenzeichenfolge erhalten.

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 
    

Der idInst-Parameter im vorherigen Beispiel gibt den Instanzbezeichner an, der von der DdeInitialize-Funktion abgerufen wurde.

Die DDE-Rückruffunktion einer Anwendung empfängt während der meisten DDE-Transaktionen mindestens ein Zeichenfolgenhandles. Beispielsweise empfängt ein Server während der XTYP _ REQUEST-Transaktion zwei Zeichenfolgenhandles: eine identifiziert eine Zeichenfolge, die einen Themennamen angibt, und der andere identifiziert eine Zeichenfolge, die einen Elementnamen angibt. Eine Anwendung kann die Länge der Zeichenfolge abrufen, die einem Zeichenfolgenhandle entspricht, und die Zeichenfolge in einen von der Anwendung definierten Puffer kopieren, indem sie die DdeQueryString-Funktion aufruft, wie im folgenden Beispiel gezeigt.

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); 

Ein instanzspezifisches Zeichenfolgenhandle kann nicht vom Zeichenfolgenhandle zur Zeichenfolge und zurück zum Zeichenfolgenhandle zugeordnet werden. Obwohl DdeQueryString beispielsweise eine Zeichenfolge aus einem Zeichenfolgenhandle und dann DdeCreateStringHandle ein Zeichenfolgenhandle aus dieser Zeichenfolge erstellt, sind die beiden Handles nicht identisch, wie im folgenden Beispiel gezeigt.

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

Verwenden Sie die DdeCmpStringHandles-Funktion, um die Werte von zwei Zeichenfolgenhandles zu vergleichen.

Ein Zeichenfolgenhandle, das an die DDE-Rückruffunktion einer Anwendung übergeben wird, wird ungültig, wenn die Rückruffunktion zurückgegeben wird. Eine Anwendung kann ein Zeichenfolgenhandle zur Verwendung speichern, nachdem die Rückruffunktion mithilfe der DdeKeepStringHandle-Funktion zurückgegeben wurde.

Wenn eine Anwendung DdeCreateStringHandle aufruft,gibt das System die angegebene Zeichenfolge in eine Zeichenfolgentabelle ein und generiert ein Handle, das für den Zugriff auf die Zeichenfolge verwendet wird. Das System verwaltet auch eine Nutzungsanzahl für jede Zeichenfolge in der Zeichenfolgentabelle.

Wenn eine Anwendung DdeCreateStringHandle aufruft und eine Zeichenfolge angibt, die bereits in der Tabelle vorhanden ist, erhöht das System die Nutzungsanzahl, anstatt ein weiteres Vorkommen der Zeichenfolge hinzuzufügen. (Eine Anwendung kann die Nutzungsanzahl auch mithilfe von DdeKeepStringHandleerhöhen.) Wenn eine Anwendung die DdeFreeStringHandle-Funktion aufruft, schränkt das System die Nutzungsanzahl ein.

Eine Zeichenfolge wird aus der Tabelle entfernt, wenn ihre Verwendungsanzahl gleich 0 (null) ist. Da mehrere Anwendungen das Handle für eine bestimmte Zeichenfolge abrufen können, darf eine Anwendung ein Zeichenfolgenhandle nicht mehrmals freigeben, als sie das Handle erstellt oder beibehalten hat. Andernfalls kann die Anwendung dazu führen, dass die Zeichenfolge aus der Tabelle entfernt wird, wodurch anderen Anwendungen der Zugriff auf die Zeichenfolge verweigert wird.

Die DDEML-Zeichenfolgenverwaltungsfunktionen basieren auf dem Atom-Manager und unterliegen denselben Größenbeschränkungen wie Atome.

DDEML und Threads

Die DdeInitialize-Funktion registriert eine Anwendung bei der DDEML und erstellt eine DDEML-Instanz. Eine DDEML-Instanz ist threadbasiert und dem Thread zugeordnet, der DdeInitialize aufgerufen hat.

Alle DDEML-Funktionsaufrufe für Objekte, die zu einer DDEML-Instanz gehören, müssen aus demselben Thread erfolgen, der DdeInitialize aufgerufen hat, um die Instanz zu erstellen. Wenn Sie eine DDEML-Funktion aus einem anderen Thread aufrufen, schlägt die Funktion fehl. Sie können nicht über einen anderen Thread als den, der die Konversation zugeordnet hat, auf eine DDEML-Konversation zugreifen.