Freigeben über


Grundlegende Konzepte (DDE)

Diese Konzepte sind der Schlüssel zum Verständnis von Dynamic Data Exchange (DDE) und der Dynamic Data Exchange Management Library (DDEML).

Interaktion zwischen Client und Server

DDE findet immer zwischen einer Client-Anwendung und einer Server-Anwendung statt. Die DDE-Client-Anwendung initiiert den Austausch, indem sie eine Konversation mit dem Server aufbaut, um Transaktionen an den Server zu senden. Eine Transaktion ist eine Anfrage nach Daten oder Diensten. Die DDE-Server-Anwendung reagiert auf Transaktionen, indem sie Daten oder Dienste für den Client bereitstellt. Eine Grafikanwendung könnte beispielsweise ein Balkendiagramm enthalten, das die vierteljährlichen Gewinne eines Unternehmens darstellt, aber die Daten für das Balkendiagramm könnten in einer Tabellenkalkulationsanwendung enthalten sein. Um die neuesten Gewinnzahlen abzurufen, könnte die Grafikanwendung (der Client) eine Konversation mit der Tabellenkalkulationsanwendung (dem Server) aufbauen. Die Grafikanwendung könnte dann eine Transaktion an die Tabellenkalkulationsanwendung senden, um die neuesten Gewinnzahlen anzufordern.

Ein Server kann viele Clients gleichzeitig haben, und ein Client kann Daten von mehreren Servern anfragen. Eine Anwendung kann sowohl ein Client als auch ein Server sein. Sowohl der Client als auch der Server können die Konversation jederzeit beenden.

Transaktionen und die DDE-Callback-Funktion

Die DDEML benachrichtigt eine Anwendung über DDE-Aktivitäten, die die Anwendung betreffen, indem sie Transaktionen an die DDE-Callback-Funktion der Anwendung sendet. Eine DDE-Transaktion ist ähnlich wie eine Nachricht eine benannte Konstante, die von weiteren Parametern begleitet wird, die zusätzliche Informationen über die Transaktion enthalten.

Die DDEML übergibt eine Transaktion an eine anwendungsdefinierte DDE-Callback-Funktion, die eine der Art der Transaktion entsprechende Aktion ausführt. Wenn zum Beispiel eine Client-Anwendung versucht, eine Konversation mit einer Server-Anwendung aufzubauen, ruft der Client die Funktion DdeConnect auf. Diese Funktion veranlasst die DDEML, eine XTYP_CONNECT-Transaktion an die DDE-Callback-Funktion des Servers zu senden. Die Callback-Funktion kann die Konversation zulassen, indem sie WAHR an die DDEML zurückgibt, oder sie kann die Konversation verweigern, indem sie FALSCH zurückgibt. Eine detaillierte Beschreibung von Transaktionen finden Sie unter Transaktionsmanagement.

Dienstnamen, Themennamen und Elementnamen

Ein DDE-Server verwendet eine dreistufige Hierarchie aus Dienstname (in der früheren DDE-Dokumentation „Anwendungsname“ genannt), Themenname und Elementname, um eine Dateneinheit, die der Server während einer Konversation austauschen kann, eindeutig zu identifizieren.

Ein Dienstname ist eine Zeichenfolge, auf die eine Serveranwendung reagiert, wenn ein Client versucht, eine Konversation mit dem Server aufzubauen. Ein Client muss diesen Dienstnamen angeben, um eine Konversation mit dem Server aufzubauen. Obwohl ein Server auf viele Dienstnamen reagieren kann, reagieren 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; bei anderen Servern sind es andere anwendungsspezifische Zeichenfolgen. Ein Client muss einen Themennamen zusammen mit dem Dienstnamen eines Servers angeben, wenn er versucht, eine Konversation mit einem Server aufzubauen.

Ein Elementname ist eine Zeichenfolge, die eine Einheit von Daten identifiziert, die ein Server während einer Transaktion an einen Client weitergeben kann. Ein Elementname kann zum Beispiel eine ganze Zahl, eine Zeichenfolge, mehrere Textabsätze oder eine Bitmap bezeichnen.

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

Systemthema

Das Thema System bietet einen Kontext für Informationen von allgemeinem Interesse für jeden DDE-Client. Es wird empfohlen, dass Serveranwendungen das Systemthema stets unterstützen. Das Systemthema ist in der Header-Datei DDEML.H als SZDDESYS_TOPIC definiert.

Um festzustellen, welche Server vorhanden sind und welche Art von Informationen sie bereitstellen können, kann eine Client-Anwendung beim Start eine Konversation über das Systemthema anfragen und dabei den Gerätenamen auf NULL festlegen. Solche Platzhalterkonversationen sind kostspielig für die Systemleistung und sollten daher auf ein Minimum beschränkt werden. Weitere Informationen zum Starten von DDE-Konversationen finden Sie unter Konversationsmanagement.

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

Artikel Beschreibung
SZDDE_ITEM_ITEMLIST Eine Liste der Elemente, die unter einem Nicht-System-Thema unterstützt werden. (Diese Liste kann von Moment zu Moment und von Thema zu Thema variieren.)
SZDDESYS_ITEM_FORMATS Eine tabulatorgetrennte Liste von Zeichenfolgen, die alle von der Dienstanwendung potenziell unterstützten Zwischenablageformate darstellen. Zeichenfolgen, die vordefinierte Zwischenablageformate darstellen, entsprechen den CF_-Werten, wobei das Präfix „CF_“ entfernt wurde. Zum Beispiel wird das Format CF_TEXT durch die Zeichenfolge „TEXT“ dargestellt. Diese Zeichenfolgen müssen in Großbuchstaben geschrieben werden, um sie als vordefinierte Formate zu kennzeichnen. Die Liste der Formate muss in der Reihenfolge des größten Inhaltsumfangs und des geringsten Inhaltsumfangs erscheinen. Weitere Informationen über die Formate der Zwischenablage und das Rendern von Daten finden Sie unter Zwischenablage.
SZDDESYS_ITEM_HELP Für Benutzer*innen lesbare Informationen von allgemeinem Interesse. Dieses Element muss mindestens Informationen über die Verwendung der DDE-Funktionen der Serveranwendung enthalten. Diese Informationen können u. a. beinhalten, wie Sie Elemente innerhalb von Themen angeben, welche Zeichenfolgen der Server ausführen kann, welche Poke-Transaktionen zulässig sind und wie Sie Hilfe zu anderen Systemthemen finden.
SZDDESYS_ITEM_RTNMSG Support-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_ITEM_STATUS 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 Ready oder Busy.
SZDDESYS_ITEM_SYSITEMS Eine Liste der Elemente, die von diesem Server unter dem Systemthema unterstützt werden.
SZDDESYS_ITEM_TOPICS Eine Liste der Themen, die der Server zum aktuellen Zeitpunkt unterstützt. (Diese Liste kann sich von Moment zu Moment ändern.)

Diese Elementnamen sind Werte, die in der Header-Datei DDEML.H definiert sind. Um Zeichenfolgen-Handles für diese Zeichenfolgen abzurufen, muss eine Anwendung die DDEML-Funktionen für das Zeichenfolgenmanagement verwenden, genau wie für jede andere Zeichenfolge in einer DDEML-Anwendung. Weitere Informationen zum Zeichenfolgenmanagement finden Sie unter Zeichenfolgenmanagement.

Initialisierung

Bevor Sie eine andere DDEML-Funktion aufrufen, muss eine Anwendung die Funktion DdeInitialize aufrufen. DdeInitialize ruft einen Instanzidentifikator für die Anwendung ab, registriert die DDE-Callback-Funktion der Anwendung bei der DDE und gibt die Transaktionsfilter-Flags für die Callback-Funktion an.

Jede Instanz einer Anwendung oder einer DLL muss ihren Instanzidentifikator als Parameter idInst an jede andere DDEML-Funktion übergeben, die ihn benötigt. Der Zweck mehrerer DDEML-Instanzen besteht darin, DLLs zu unterstützen, die die DDEML zur gleichen Zeit wie eine Anwendung verwenden müssen. Eine Anwendung darf nicht mehr als eine Instanz der DDEML verwenden.

Transaktionsfilter optimieren die Systemleistung, indem sie verhindern, dass die DDEML unerwünschte Transaktionen an die DDE-Callback-Funktion der Anwendung weitergibt. Eine Anwendung legt die Transaktionsfilter in dem DdeInitialize-Parameter ufCmd fest. Eine Anwendung muss für jede Art von Transaktion, die sie in ihrer Callback-Funktion nicht verarbeitet, ein Flag für den Transaktionsfilter angeben. Eine Anwendung kann ihre Transaktionsfilter mit einem nachfolgenden Aufruf von DdeInitialize ändern. Weitere Informationen über Transaktionen finden Sie unter Transaktionsmanagement.

Das folgende Beispiel zeigt, wie Sie eine Anwendung für die Verwendung der DDEML initialisieren.

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 Funktion DdeUninitialize aufrufen, wenn sie die DDEML nicht mehr verwenden will. Diese Funktion beendet alle derzeit für die Anwendung geöffneten Konversationen und gibt die DDEML-Ressourcen frei, die das System für die Anwendung bereitgestellt hat.

Callback-Funktion

Eine Anwendung, die die DDEML verwendet, muss eine Callback-Funktion bereitstellen, die die DDE-Ereignisse verarbeitet, die die Anwendung betreffen. Die DDEML benachrichtigt eine Anwendung über solche Ereignisse, indem sie Transaktionen an die DDE-Callback-Funktion der Anwendung sendet. Welche Transaktionen eine Callback-Funktion empfängt, hängt davon ab, welche Callback-Filter-Flags die Anwendung in DdeInitialize angegeben hat und ob die Anwendung ein Client, ein Server oder beides ist. Weitere Informationen finden Sie unter DdeCallback.

Das folgende Beispiel zeigt die allgemeine Struktur einer Callback-Funktion für eine typische Client-Anwendung.

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 Parameter uType gibt den Transaktionstyp an, der von der DDEML an die Callback-Funktion gesendet wird. Die Werte der übrigen Parameter hängen von der Art der Transaktion ab. Die Transaktionsarten und die Ereignisse, die sie erzeugen, werden in den folgenden Themen beschrieben. Ausführliche Informationen zu den einzelnen Transaktionstypen finden Sie unter Transaktionsmanagement.

Zeichenfolgenmanagement

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

Eine Anwendung kann ein Zeichenfolgen-Handle für eine bestimmte Zeichenfolge abrufen, indem sie die Funktion DdeCreateStringHandle aufruft. Diese Funktion registriert die Zeichenfolge beim System und gibt ein Zeichenfolge-Handle an die Anwendung zurück. Die Anwendung kann das Handle an DDEML-Funktionen weitergeben, die auf die Zeichenfolge zugreifen müssen. Das folgende Beispiel ruft Zeichenfolgen-Handles für die Systemthema- und die Dienstnamen-Zeichenfolge ab.

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 Parameter idInst im vorangehenden Beispiel gibt den Instanzidentifikator an, der von der Funktion DdeInitialize abgerufen wird.

Die DDE-Callback-Funktion einer Anwendung empfängt bei den meisten DDE-Transaktionen eine oder mehrere Zeichenfolgen. Ein Server empfängt beispielsweise zwei Zeichenfolgen-Handles während der XTYP_REQUEST-Transaktion: Eine identifiziert eine Zeichenfolge, die einen Themennamen angibt, und die andere identifiziert eine Zeichenfolge, die einen Elementnamen angibt. Eine Anwendung kann die Länge der Zeichenfolge abrufen, die einem Zeichenfolgen-Handle entspricht, und die Zeichenfolge in einen anwendungsdefinierten Puffer kopieren, indem sie die Funktion DdeQueryString 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 Zeichenfolgen-Handle kann nicht von einem Zeichenfolgen-Handle auf eine Zeichenfolge und zurück auf ein Zeichenfolgen-Handle zugeordnet werden. Obwohl zum Beispiel DdeQueryString eine Zeichenfolge aus einem Zeichenfolgen-Handle erstellt und dann DdeCreateStringHandle ein Zeichenfolgen-Handle 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 ! 

Um die Werte von zwei Zeichenfolgen-Handles zu vergleichen, verwenden Sie die Funktion DdeCmpStringHandles.

Eine Zeichenfolge, die an die DDE-Callback-Funktion einer Anwendung übergeben wurde, wird ungültig, wenn die Callback-Funktion zurückkehrt. Eine Anwendung kann ein Zeichenfolge-Handle zur Verwendung nach der Rückkehr der Callback-Funktion speichern, indem sie die Funktion DdeKeepStringHandle verwendet.

Wenn eine Anwendung DdeCreateStringHandle aufruft, trägt das System die angegebene Zeichenfolge in eine Zeichenfolgentabelle ein und erzeugt ein Handle, das es für den Zugriff auf die Zeichenfolge verwendet. Das System verwaltet außerdem einen Verwendungszähler 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 den Verwendungszähler, anstatt ein weiteres Vorkommen der Zeichenfolge hinzuzufügen. (Eine Anwendung kann den Verwendungszähler auch erhöhen, indem sie DdeKeepStringHandle verwendet). Wenn eine Anwendung die Funktion DdeFreeStringHandle aufruft, verringert das System den Verwendungszähler.

Eine Zeichenfolge wird aus der Tabelle entfernt, wenn ihr Verwendungszähler gleich Null ist. Da mehr als eine Anwendung die Zeichenfolge abrufen kann, darf eine Anwendung eine Zeichenfolge nicht häufiger freigeben, als sie die Zeichenfolge 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 verwehrt wird.

Die Funktionen für das Zeichenfolgenmanagement in DDEML basieren auf dem Atom Manager und unterliegen den gleichen Größenbeschränkungen wie Atoms.

DDEML und Threads

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

Alle DDEML-Funktionsaufrufe für Objekte, die zu einer DDEML-Instanz gehören, müssen von demselben Thread aus erfolgen, der DdeInitialize aufgerufen hat, um die Instanz zu erstellen. Wenn Sie eine DDEML-Funktion von einem anderen Thread aus aufrufen, wird die Funktion fehlschlagen. Sie können nicht von einem anderen Thread aus auf eine DDEML-Konversation zugreifen als von dem aus, der die Konversation alloziert hat.