Pegasus Mail for Windows DDE (Dynamic Data Exchange) Schnittstelle
Copyright (c) 1997-1999, David Harris, Alle Rechte vorbehalten.
------------------------------------------------------------------

Versionen:
* WinPMail v3.11: Schlsselwrter IDENTITY und VOLATILE zum Thema MESSAGE
                  hinzugefgt.
* WinPMail v3.12: Schlsselwort RICHTEXT zum Thema MESSAGE hinzugefgt
                  Schlsselwort STATUS zum Thema ENVIRONMENT hinzugefgt

Pegasus Mail v2.54 und spter bietet Untersttzung fr Windows DDE zur Kommunikation
zwischen Windows-Anwendungen. Dieses Dokument beschreibt die sogenannten Topics, die
von Pegasus Mail fr Windows untersttzt werden und die Schreibweise der Kommandos.
Es ist keine Einfhrung in DDE und setzt grundlegendes Verstndnis ber DDE und die 
Verwendung von DDE in Windows-Umgebungen (wie Microsoft WordBasic) voraus.

Eine der wichtigsten Vorteile von DDE ist die Tatsache, da DDE den transparenten
Datenaustausch zwischen 16-Bit und 32-Bit Anwendungen untersttzt: Sie knnen also
mit denselben Mechanismen auf die 16-Bit oder 32-Bit Version von WinPMail zugreifen,
ohne sich Gedanken ber die Unterschiede beider Versionen machen zu mssen.

Die DDE-Schnittstelle von Pegasus Mail wurde so konzipiert, da sie so einfach wie
mglich verwendbar ist. Sie basiert auf einfachen Zeichenketten fr die Kommandos.
Das ermglicht die Interaktion von Pegasus Mail in nahezu jeder denkbaren
Umgebung.



"Service"- und "Topic"-Namen
----------------------------

Innerhalb von DDE versteht man unter einem "Service-Namen" den Namen der Anwendung,
die DDE Verbindungen akzeptiert: wenn Sie sich mit einer DDE Diensteanwendung ver-
binden, geben Sie eine bestimmte Menge von Kommandos oder Operationen an. Diese
Kommandos werden als "Topic-Namen" oder auch "Themen" bezeichnet. Pegasus Mail 
verwendet den Service-Namen "WinPMail" und stellt die folgenden Topics (Themen) zur 
Verfgung:

   "System"        Das Standard DDE System Thema
   "Environment"   Akzeptiert DDE Anfragen (Transaktionen vom Typ XTYP_REQUEST)
                   und gibt Informationen ber die Umgebung der laufenden Kopie
                   von WinPMail zurck, wie z.B. Verzeichnisse und Benutzenamen
   "Message"       Akzeptiert das DDE Poke Kommando, um Nachrichten zu erzeugen und
                   zu senden. Ein DDE Client kann entweder Standard-Editor Fenster
                   erzeugen und manipulieren, indem die gewnschten Felder ausgefllt
                   werden, oder er kann Nachrichten ohne Fenster erzeugen.
   "TCP"           Bietet den Zugriff auf WinPMail's TCP/IP-basierte Maildienste
                   ber das DDE Poke Kommando.



Das Thema "Environment"
-----------------------

Das Thema "Environment" ermglicht es DDE Client Anwendungen, Informationen ber 
eine laufende Kopie von Pegasus Mail abzufragen. Um dieses Kommando zu verwenden,
senden Sie ein DDE Request Kommando (eine Transaktion vom Typ XTYP_REQUEST) mit dem 
Thema (Topic) "Environment" und dem gewnschten "Item-Parameter". Folgende Parameter
sind verwendbar:

   USER           - Gibt den Namen des Benutzers von WinPMail zurck
   HOMEBOX        - Gibt den kompletten Pfad zum Briefkastenverzeichnis des 
                    Benutzers zurck
   NEWBOX         - Gibt den kompletten Pfad zum Eingangsordner des Benutzers zurck
   MODE           - Gibt entweder "Standalone" oder "Network" zurck
   VERSION        - Gibt die Version von WinPMail zurck, ausgedrckt als 4-stellige
                    hexdezimale Zahl  ("0254" fr v2.54), gefolgt von einem 
                    Leerzeichen und entweder "16" oder "32" zur Identifizierung der
                    gerade laufenden Kopie von Pegasus Mail.  
   BASEDIR        - Das Verzeichnis, aus dem WinPMail gestartet wurde
   TCP            - Wenn WinPMail's TCP/IP Dienste verfgbar sind, gibt dieses Item
                    den Pfad zur verwendeten Datei WINSOCK.DLL zurck, anderenfalls
                    gibt es das einzelne Zeichen "N" zurck.
   NEWMAIL        - Gibt die Anzahl von Nachrichten im Eingangsordner des Benutzers
                    zurck.
   STATUS         - Gibt den Status der letzten Zustell-Operation zurck

-- Beispiel: -----------------------------------

   In WordBasic (MS-Word 7) ffnet das folgende Makro eine Verbindung zu WinPMail,
   ermittelt die aktuelle Version und zeigt diese an:

      Sub MAIN
      channel = DDEInitiate("WinPMail", "Environment")
      a$ = DDERequest$(channel, "version")
      DDETerminate channel
      MsgBox a$
      End Sub

   Ein ausfhrlicheres Beispiel in C ist im Anhang A zu finden.



Das Thema "Message"
-------------------

Client Anwendungen verwenden das Thema "Message", um mit Pegasus Mail elektronische
Nachrichten zu erzeugen und zu versenden. Sobald eine Verbindung zu Pegasus Mail
ber das Thema "Message" aufgebaut wurde, kann die Client-Anwendung Daten an 
WinPMail bergeben (ber sogenannte XTYP_POKE Transaktionen). Der Zeichenketten-
parameter innerhalb des Kommandos POKE sollte auf "Message" gesetzt werden, andere
Werte sind fr zuknftige Erweiterungen reserviert. Die Daten selbst enthalten die
Kommandos und Parameter.

Die folgenden Kommandos knnen an Pegasus Mail bergeben werden:

   New : <"Message"> oder <"Window">
      Wenn der Parameter "Window" verwendet wird, erzeugt WinPMail ein Standard
      Fenster zur Erstellung von Nachrichten, alle folgenden Kommandos ndern dann
      Optionen und Einstellungen in diesem Fenster. Wenn der Parameter "Message"
      verwendet wird, werden die erforderlichen Datenstrukturen zur Erstellung einer
      Nachricht intern erzeugt, weitere Kommandos haben dann Einflu auf diese
      internen Datenstrukturen.

   Defaults : Y
      Weist WinPMail an, die Standard-Werte des Benutzers fr Nachrichten zu 
      verwenden. Dieses Kommando ist nur gltig, wenn das Kommando "New: message"
      gesendet wurde - es hat keinen Auswirkung bei Verwendung des Kommandos 
      "New: windows", da in diesem Fall automatisch die Standard-Werte verwendet 
      werden.

   To : <address> [, <address> ...]
      Fllt das Feld "An" der Nachrichten mit der im Parameter bergebenen Adresse. 
      Die Adresse darf jede von WinPMail normalerweise akzeptierte Adresse sein und
      darf mehrere Adressen - jeweils mit Komma getrennt - enthalten. Die gleichen
      Regeln gelten auch fr die Felder Cc: und Bcc:

   Cc : <address> [, <address> ...]
      Fllt das Feld "Cc:" (Durchschlag) fr die Nachricht.

   Bcc : <address> [, <address> ...]
      Fllt das Feld "Bcc:" (Verdeckte Kopie) fr die Nachricht.

   Subject : <string>
      Fllt das Feld "Betreff:" fr die Nachricht.

   Reply-to : <address>
      Spezifiziert die optionale Antwortadresse fr die Nachricht.

   Copyself : <'Y'> oder <'N'>
      Legt fest, ob eine Ausgangskopie von der Nachricht erstellt werden soll.

   Confirm-delivery : <'Y'> oder <'N'>
      Legt fest, ob eine Empfangsbesttigung angefordert werden soll.

   Confirm-reading : <'Y'> oder <'N'>
      Legt fest, ob eine Lesebesttigung angefordert werden soll.

   Urgent : <'Y'> oder <'N'>
      Legt fest, ob die Nachricht als "Dringend" spezifiziert werden soll.
      
   Encrypted : <encryptor-name><,><passphrase><,><flags>
      Whlt eine Verschlsselungsmethode fr die Nachricht aus. "Encryptor-name" ist
      der Name des zu verwendenden Verschlsselungsmoduls (zur Auswahl des 
      eingebauten Verschlsselungsmoduls verwenden Sie "PM-BUILTIN"). Den Namen des
      Verschlsselungsmoduls finden Sie in der entsprechenden *.FFF (bzw. *.FDE) 
      Datei des Verschlsselungsmoduls in der Zeile "Form tagname". "passphrase"
      ist das Pawort fr die Nachricht. Wenn das Pawort ein Komma enthlt, mu es
      in Anfhrungszeichen geschrieben werden. "flags" ist entweder 1, um die Nach-
      richt zu verschlsseln oder 2, um die Nachricht zu signieren bzw. 3, um die
      Nachricht zu verschlsseln und zu signieren.

   Signature : <number>
      Whlt die gewnschte Signatur fr die Nachricht aus. "number" ist 1 - 9,
      bezogen auf die entsprechenden in Pegasus Mail verfgbaren Signaturstze
      (siehe unter Extras | Einstellungen | Signaturen) oder 0 (keine Signatur).

   Mime : <'Y'> oder <'N'>
      Legt fest, on MIME-Untersttzung fr diese Nachricht verwendet werden soll.
      MIME-Untersttzung beeinflut die Art, wie Anhnge und internationale Zeichen-
      stze von WinPMail behandelt werden. Wir empfehlen Ihnend dringend, MIME 
      wenn mglich immer einzuschalten.

   Attach : <path><,><filename><,><attachment-type><,><encoding>
      Hngt eine Datei an die Nachricht an. "path" sollte der vollstndige Pfad zur
      Datei sein - gehen Sie nicht davon aus, da das aktuelle Verzeichnis in Ihrer
      Client Anwendung auch das aktuelle Verzeichnis von Pegasus Mail ist. 
      "filename" ist der Dateiname, den Pegasus Mail in die Nachricht als realen
      Namen einfgen soll (diese Option verwenden Sie normalerweise dann, wenn
      Sie eine temporre Datei angelegt haben, diese aber mit einem anderen Datei-
      namen versenden wollen). Wenn "filename" als "-" angegeben wird, extrahiert
      WinPMail automatisch den Dateinamen aus dem Parameter "path".
      "attachment-type" sollte den Typ des Anhanges beschreiben; es darf keine Leer-
      zeichen enthalten. Wenn Sie diese Option auf einen einzelnen Strich setzen 
      ("-"), verwendet WinPMail seine internen Routinen, um den geeignetsten Typ fr
      den Anhang zu ermitteln. "encoding" whlt den Kodierungstyp fr den Anhang 
      aus: Wir empfehlen Ihnen dringend, diesen Wert auf 0 (Null) zu setzen, damit
      WinPMail den passenden Kodierungstyp selbst auswhlen kann. Mgliche Werte 
      sind:
         0 - Pegasus Mail entscheidet.
         1 - Keine Kodierung - die Datei wird nicht verndert (nur bei lokaler Mail)
         2 - ASCII Kodierung - die Datei wird mit CR/LF Zeichen am Zeilenende
             "normalisiert" und wird nicht weiter kodiert.
         3 - UU-kodiert - die Datei wird "uu-kodiert"
         4 - BinHex - die Datei wird mit der BinHex 4.0 Methode kodiert.
         5 - MIME - die Datei wird mit Hilfe der MIME BASE64 Methode kodiert.

   File : <filename>
      Spezifiert den Namen einer Textdatei, dessen Inhalt als Nachrichtentext ein-
      gefgt werden soll. Beachten Sie, da diese Datei keinen Anhang darstellt - 
      die Datei sollte unbedingt eine reine Textdatei sein.

   Data : <String>
      Fgt die Zeichenkette "string" in den Nachrichtentext als eine einzelne Zeile
      ein. Verwenden Sie dieses Kommando wiederholt, um den Nachrichtentext Zeile 
      fr Zeile einzufgen. WinPMail fgt automatisch einen Zeilenumbruch (CR/LF)
      zu jeder Zeile hinzu. Wenn Sie dieses Kommando ohne Zeichenkettenparameter
      verwenden, wird eine leere Zeile in den Nachrichtentext geschrieben (aber das
      ':' mu in diesem Fall trotzdem mit angegeben werden).

   Identity : <identity_name>
      Legt die Identitt fr die Nachricht fest. Fr weitere Informationen ber
      Identitten sehen Sie in der Pegasus Mail Hilfe-Datei nach. Sie knnen jeden
      gltigen Namen einer Identitt als Parameter fr dieses Kommando verwenden.
      Der Standard-Wert ist die aktuelle Identitt des Benutzers.

   Volatile : <'Y'> oder <'N'>         (Standard ist 'Y')
      (Nur von Bedeutung, wenn WinPMail's interner SMTP Mailer verwendet wird).
      Wenn dieses Feld auf "Y" gesetzt wird, schreibt Pegasus Mail die Nachricht 
      sofort in die endgltige Form in der Warteschlangenverwaltung (diese Nachricht
      kann dann nicht mehr editiert werden). Wenn Sie die Nachricht spter noch
      weiterbearbeiten wollen, setzen Sie diese Option auf "N". Wenn Ihre Nachricht
      Anhnge hat, die Sie nach dem Versenden der Nachricht lschen wollen, mssen 
      Sie diese Option auf "N" setzen.

   Richtext : <'Y'> oder <'N'>         (Standard ist 'N')
      Schaltet die Option "Rich Text" fr die Nachricht ein oder aus.

   Send
      Dieses Kommando sendet die Nachricht. Beachten Sie, da hier keine Parameter
      angegeben werden und das Zeichen ':' ebenfalls nicht angegeben werden darf.
      Das Kommando hat keine Auswirkung, wenn der Parameter "Window" fr das 
      Kommando "New:" verwendet wurde.

   Restore
      Dieses Kommando setzt den Eingabefokus auf Pegasus Mail und aktiviert das
      Nachrichtenfenster, welches zuvor mit dem Kommando "New: Window" erzeugt 
      wurde. Beachten Sie, da hier keine Parameter angegeben werden und das Zeichen
      ':' ebenfalls nicht angegeben werden darf. Fr Nachrichten, die mit dem
      Kommando "New: Message" erzeugt wurden, setzt dieses Kommando den Eingabefokus
      auf Pegasus Mail, ohne jede weitere Aktion.



-- Beispiel: -----------------------------------

   In WordBasic (MS-Word 7) ffnet das folgende Makro eine Verbindung zu
   WinPMail und sendet eine Nachricht ohne Nachrichtenfenster.

      Sub MAIN
      channel = DDEInitiate("WinPMail", "Message")
      DDEPoke channel, "Message", "New: Message"
      DDEPoke channel, "Message", "Defaults: Y"
      DDEPoke channel, "Message", "To: David"
      DDEPoke channel, "Message", "Subject: Test from Word"
      DDEPoke channel, "Message", "Data: Hi there!"
      DDEPoke channel, "Message", "Send"
      DDETerminate channel
      End Sub



Das Thema "TCP"
---------------

Die Kommandos dieses Themas erlauben es Client-Anwendungen, Pegasus Mail's 
eingebaute TCP/IP basierte Email-Protokolle zu verwenden. Bevor Sie diese Kommandos
verwenden, sollte eine Client-Anwendung normalerweise mit einem "TCP" Request 
abfragen, ob die TCP/IP Dienste berhaupt eingeschaltet sind und zur Verfgung 
stehen. Client-Anwendungen schicken hier analog zum Kommando "Message" Daten an 
WinPMail. Die folgenden Kommandos sind verwendbar:

   Get
      Weist Pegasus Mail an, Nachrichten mit den aktuellen TCP/IP Einstellungen
      abzurufen.

   Send
      Weist Pegasus Mail an, alle augenblicklich wartenden Nachrichten aus der
      Warteschlange zu versenden.

   Both
      Weist Pegasus Mail an, erst Nachrichten abzurufen und danach wartende 
      Nachrichten aus der Warteschlange zu versenden, genau in dieser Reihenfolge.

   Restore
      Dieses Kommando bringt Pegasus Mail in den Vordergrund und setzt den Eingabe-
      fokus auf Pegasus Mail.


-- Beispiel: -----------------------------------

   In WordBasic (MS-Word 7) ffnet das folgende Makro eine Verbindung zu
   WinPMail, initiiert den Abruf von Nachrichten und schaltet WinPMail in den
   Vordergrund:

      Sub MAIN
      channel = DDEInitiate("WinPMail", "TCP")
      DDEPoke channel, "TCP", "Get"
      DDEPoke channel, "TCP", "Restore"
      DDETerminate channel
      End Sub



Pegasus Mail und die Windows Registrierdatenbank (Registry)
-----------------------------------------------------------

Ab WinPMail v2.54 aktualisiert WinPMail die Windows Registrierdatenbank mit 
bestimmten Informationen, wenn es gestartet wird. DDE Client Anwendungen knnen 
diese Informationen verwenden, um herauszufinden, wo Pegasus Mail installiert ist,
um eine Kopie von Pegasus Mail zu starten (wenn derzeit keine Kopie gestartet ist)
und die passenden Kommandozeilenparameter zu ermitteln.

Die 32-Bit Version von WinPMail erzeugt die folgenden Schlssel:

   HKEY_CURRENT_USER\Software\Pegasus Mail\Version
   HKEY_CURRENT_USER\Software\Pegasus Mail\BaseDir
   HKEY_CURRENT_USER\Software\Pegasus Mail\Command

Der Schlssel "Version" enthlt die Version von WinPMail - im gleichen Format wie 
beim Thema "Environment", Topic "Version". Der Schlssel "BaseDir" enthlt das
Verzeichnis, indem die ausfhrbaren Dateien von Pegasus Mail zu finden sind und der
Schssel "Command" enthlt die komplette Kommandozeile, die beim letzten Aufruf von
Pegasus Mail verwendet wurde.

Sowohl die 16-Bit als auch die 32-Bit Version von WinPMail erzeugen die folgenden
Schlssel:

   HKEY_CLASSES_ROOT\Software\Pegasus Mail\Version
   HKEY_CLASSES_ROOT\Software\Pegasus Mail\BaseDir
   HKEY_CLASSES_ROOT\Software\Pegasus Mail\Command

Diese Schlssel sind genau wie oben beschrieben formatiert. 32-Bit Anwendungen 
sollten immer zuerst die Schlssel unter HKEY_CURRENT_USER auslesen, bevor die
Anwendungen versuchen, die Schlssel unter HKEY_CLASSES_ROOT abzufragen, um 
evtl. vorhandene Konfigurationen mehrerer Anwender unter Windows 95/98/NT zu 
bercksichtigen.



Anhang A: DDE von C Programmen aus verwenden
--------------------------------------------

Der folgende Quelltext kann als Modell fr die Interaktion mit jeder DDE-fhigen
Anwendung verwendet werden. Er bietet einen einfachen Dialog mit den Feldern 
"Service", "Topic" und "Kommando", Auswahloptionen fr das "Request"-Kommando
(erlaubt die Auswahl zwischen XTYP_EXECUTE, XTYP_REQUEST und XTYP_POKE
Transaktionen) und drei Schaltflchen - eine zum ffnen/Schlieen einer Verbindung,
eine Schaltflche "Quit" zur Beendigung des Programms und eine Schaltflche "Do it"
zur Ausfhrung des Kommandos (wenn noch keine Verbindung besteht, wird diese auto-
matisch hergestellt, das Kommando wird gesendet und die Verbindung wird geschlossen).

Dieses Programm wurde in Borland C++ v4.52 geschrieben und verwendet Borland's
BWCC.LIB oder BWCC32.LIB zur korrekten Darstellung des Dialogs.

<< Die Kommentare innerhalb des Quelltextes wurden im englischen Original belassen, 
Anm. des bersetzers.>>

--------------- DDECLI.C --------------------------------------------
#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <string.h>
#include <ddeml.h>

DWORD idInst = 0L;      // DDE instance identifier
HINSTANCE hInstance;
HCONV mconv;
HSZ ghszServSrv;
HSZ ghszServTop;

#pragma warn -par
#pragma warn -use


HDDEDATA EXPENTRY DDECallback (WORD wType,   // transaction type
   WORD     wFmt,    // clipboard format
   HCONV    hConv,   // handle of the conversation
	HSZ      hsz1,    // handle of a string
   HSZ      hsz2,    // handle of a string
   HDDEDATA hData,   // handle of a global memory object
   DWORD    dwData1, // transaction-specific data
   DWORD    dwData2) // transaction-specific data
   {
   // Nothing need be done here...
   return (HDDEDATA) NULL;
   }


BOOL SendShellCommand (DWORD idInst, char *service, char *topic, LPSTR lpCommand)
   {
   HSZ      hszServSrv;    // Service is "DDESERV"
   HSZ      hszServTop;    // Topic is "MAIL"
   HCONV    hconv;         // handle of conversation
   int      nLen;          // length of command string
   HDDEDATA hData;         // return value of DdeClientTransaction
   DWORD    dwResult;      // result of transaction
   BOOL     bResult=FALSE; // TRUE if this function is successful

   if (mconv == NULL)
      {
      // create string handle to service/topic
      hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
      hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);

      // attempt to start conversation with server app
	   hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
      }
   else
      hconv = mconv;

   if (hconv != NULL)
      {
      // get length of the command string
      nLen = lstrlen ((LPSTR) lpCommand);

      // send command to server app
      hData = DdeClientTransaction (
         (LPBYTE) lpCommand, // data to pass
         nLen + 1,           // length of data
         hconv,              // handle of conversation
         NULL,               // handle of name-string
         CF_TEXT,            // clipboard format
         XTYP_EXECUTE,       // transaction type
         20000,              // timeout duration
         &dwResult);         // points to transaction result

      if (hData)
         bResult = TRUE;

      if (mconv == NULL)
         // end conversation
         DdeDisconnect (hconv);
      }

   if (mconv == NULL)
      {
      // free service/topic string handle
      DdeFreeStringHandle(idInst, hszServSrv);
      DdeFreeStringHandle(idInst, hszServTop);
      }

   if (bResult == FALSE)
      MessageBox (NULL, "SendShellCommand failed", "DDE Client", MB_OK);

   return bResult;
   }


BOOL SendPoke (DWORD idInst, char *service, char *topic, LPSTR lpCommand)
   {
   HSZ      hszServSrv;    // Service is "DDESERV"
   HSZ      hszServTop;    // Topic is "MAIL"
   HCONV    hconv;         // handle of conversation
   int      nLen;          // length of command string
   HDDEDATA hData;         // return value of DdeClientTransaction
   DWORD    dwResult;      // result of transaction
   BOOL     bResult=FALSE; // TRUE if this function is successful

   if (mconv == NULL)
      {
      // create string handle to service/topic
      hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
      hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);

      // attempt to start conversation with server app
	   hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
      }
   else
      hconv = mconv;

   if (hconv != NULL)
      {
      // get length of the command string
      nLen = lstrlen ((LPSTR) lpCommand);

      // send command to server app
      hData = DdeClientTransaction (
         (LPBYTE) lpCommand, // data to pass
         nLen + 1,           // length of data
         hconv,              // handle of conversation
         hszServTop,         // handle of name-string
         CF_TEXT,            // clipboard format
         XTYP_POKE,          // transaction type
         20000,              // timeout duration
         &dwResult);         // points to transaction result

      if (hData)
         bResult = TRUE;

      if (mconv == NULL)
         // end conversation
         DdeDisconnect (hconv);
      }

   if (mconv == NULL)
      {
      // free service/topic string handle
      DdeFreeStringHandle(idInst, hszServSrv);
      DdeFreeStringHandle(idInst, hszServTop);
      }

   if (bResult == FALSE)
      MessageBox (NULL, "SendPoke failed", "DDE Client", MB_OK);

   return bResult;
   }


BOOL SendShellRequest (DWORD idInst, char *service, char *topic, char *cmd)
   {
   HSZ      hszServSrv;    // Service is "DDESERV"
   HSZ      hszServTop;    // Topic is "MAIL"
   HSZ      item;
   HCONV    hconv;         // handle of conversation
   int      nLen;          // length of command string
   HDDEDATA hData;         // return value of DdeClientTransaction
   DWORD    dwResult;      // result of transaction
   BOOL     bResult=FALSE; // TRUE if this function is successful
   char     *str;
   DWORD    x;

   if (mconv == NULL)
      {
      // create string handle to service/topic
      hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
      hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);

      // attempt to start conversation with server app
	   hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
      }
   else
      hconv = mconv;

   if (hconv != NULL)
      {
      // send command to server app
      item = DdeCreateStringHandle (idInst, cmd, CP_WINANSI);
      hData = DdeClientTransaction (
         NULL,               // data to pass
         0,                  // length of data
         hconv,              // handle of conversation
         item,               // handle of name-string
         CF_TEXT,            // clipboard format
         XTYP_REQUEST,       // transaction type
         20000,              // timeout duration
         &dwResult);         // points to transaction result

      if (hData)
         {
         if ((str = (char *) DdeAccessData (hData, &x)) != NULL)
            {
            strcpy (cmd, str);
            bResult = TRUE;
            DdeUnaccessData (hData);
            }

         DdeFreeDataHandle (hData);
         }

      DdeFreeStringHandle (idInst, item);

      if (mconv == NULL)
         // end conversation
         DdeDisconnect (hconv);
      }

   if (mconv == NULL)
      {
      // free service/topic string handle
      DdeFreeStringHandle (idInst, hszServSrv);
      DdeFreeStringHandle (idInst, hszServTop);
      }

   return bResult;
   }


int FAR PASCAL _export dummy_proc (HWND hDialog, UINT wMsg,
   WPARAM wParam, LPARAM lParam)
   {
   BOOL fProcessed = TRUE;
   DWORD dwResult;
   RECT r;
   HWND hControl;
   char buffer [256], service [80], topic [80];

   switch (wMsg)
      {
      case WM_INITDIALOG :
         CheckRadioButton (hDialog, 104, 106, 104);
         break;

      case WM_SETFOCUS :
         SetFocus (GetDlgItem (hDialog, 101));
         break;

      case WM_COMMAND :
         if (GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
            {
            EndDialog (hDialog, IDCANCEL);
            break;
            }

         if (GET_WM_COMMAND_ID(wParam, lParam) == 120)
            {
            if (mconv == NULL)
               {
               GetDlgItemText (hDialog, 101, service, sizeof (service));
               GetDlgItemText (hDialog, 102, topic, sizeof (topic));
               ghszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
               ghszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);

               // attempt to start conversation with server app
	            mconv = DdeConnect (idInst, ghszServSrv, ghszServTop, NULL);
               if (mconv == NULL)
                  MessageBox (NULL, "Connection failed!", "DDE Client", 
                     MB_OK | MB_ICONEXCLAMATION);
               else
                  SetDlgItemText (hDialog, 120, "Close");
               }
            else
               {
               DdeDisconnect (mconv);
               mconv = NULL;
               DdeFreeStringHandle (idInst, ghszServSrv);
               DdeFreeStringHandle (idInst, ghszServTop);
               SetDlgItemText (hDialog, 120, "Open");
               }
            break;
            }

         if (GET_WM_COMMAND_ID(wParam, lParam) == IDOK)
            {
            GetDlgItemText (hDialog, 101, service, sizeof (service));
            GetDlgItemText (hDialog, 102, topic, sizeof (topic));
            GetDlgItemText (hDialog, 103, buffer, sizeof (buffer));
            hControl = GetDlgItem (hDialog, 107);
            if (IsDlgButtonChecked (hDialog, 105))   //  Request
               {
               if (SendShellRequest (idInst, service, topic, buffer))
                  {
                  Edit_ReplaceSel (hControl, "Request successful:\r\n   ");
                  Edit_ReplaceSel (hControl, buffer);
                  Edit_ReplaceSel (hControl, "\r\n");
                  }
               else
                  Edit_ReplaceSel (hControl, "Request failed.\r\n");
               }
            else if (IsDlgButtonChecked (hDialog, 104))
               {
               if (SendShellCommand (idInst, service, topic, buffer))
                  Edit_ReplaceSel (hControl, "Command successful.\r\n");
               else
                  Edit_ReplaceSel (hControl, "Command failed.\r\n");
               }
            else
               {
               if (SendPoke (idInst, service, topic, buffer))
                  Edit_ReplaceSel (hControl, "Poke successful.\r\n");
               else
                  Edit_ReplaceSel (hControl, "Poke failed.\r\n");
               Edit_SetSel (GetDlgItem (hDialog, 103), 0, 999);
               }
            }
         break;

      default:
         fProcessed = FALSE;
         break;
      }

   return fProcessed;
   }


int PASCAL WinMain (HINSTANCE __hInstance, HINSTANCE hPrevInstance,
   LPSTR lpszCmdLine, int nCmdShow)
   {
   MSG msg;
   HWND hWndFrame;
   WNDCLASS wc;
   FARPROC DDEProc, dlgProc;

   if (hPrevInstance != NULL)
      return 0;

   hInstance = __hInstance;

   // get proc instance for our DDEML callback
   DDEProc = MakeProcInstance ((FARPROC) DDECallback, hInstance);

   // register this app with the DDEML
   if (DdeInitialize (&idInst,   // receives instance ID
      (PFNCALLBACK) DDEProc,     // address of callback function
      APPCMD_CLIENTONLY,         // this is a client app
      0L))                       // reserved
      {
#ifndef __FLAT__        //  FreeProcInstance is obsolete under Win32
      FreeProcInstance (DDEProc);
#endif
      return FALSE;
      }

   dlgProc = MakeProcInstance ((FARPROC) dummy_proc, hInstance);
   DialogBox (hInstance, "CLIENT", NULL, dlgProc);
   DdeUninitialize (idInst);
   return 0;
   }

--------------- DDECLI.DEF ----------------------------------------
NAME           DDECLI
DESCRIPTION    'DDE Test Client'
EXETYPE        WINDOWS
DATA           MOVEABLE MULTIPLE PRELOAD
CODE           MOVEABLE DISCARDABLE
HEAPSIZE       27500
STACKSIZE      16500

--------------- DDECLI.RC -----------------------------------------

CLIENT DIALOG 180, 121, 246, 168
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CLASS "bordlg"
CAPTION "DDE Test Client"
FONT 8, "MS Sans Serif"
{
 RTEXT "Service name:", -1, 15, 15, 60, 8
 CONTROL "winpmail", 101, "EDIT", ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP, 83, 13, 102, 12
 RTEXT "Topic name:", -1, 15, 30, 60, 8
 CONTROL "message", 102, "EDIT", ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP, 83, 28, 102, 12
 RTEXT "Command/request:", -1, 14, 45, 61, 8
 EDITTEXT 103, 83, 43, 102, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP
 RTEXT "Transaction type:", -1, 15, 65, 60, 8
 CONTROL "Execute", 104, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 85, 64, 47, 10
 CONTROL "Request", 105, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 133, 64, 43, 10
 CONTROL "Poke", 106, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 184, 64, 32, 10
 LTEXT "Results / Diagnostics", -1, 12, 82, 78, 8
 EDITTEXT 107, 10, 92, 228, 69, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 DEFPUSHBUTTON "Do it", IDOK, 192, 12, 43, 14
 PUSHBUTTON "Quit", IDCANCEL, 192, 42, 43, 14
 CONTROL "", -1, "BorShade", BSS_GROUP | BSS_CAPTION | BSS_LEFT | WS_CHILD | WS_VISIBLE, -5, -7, 257, 180
 PUSHBUTTON "Open", 120, 192, 27, 43, 14
}

