Pegasus Mail for Windows DDE (Dynamic Data Exchange) Interface
Copyright (c) 1997, David Harris, All Rights Reserved.
----------------------------------------------------------------

Pegasus Mail v2.54 and later incorporates support for Windows DDE to allow
interprocess communication. This document describes the topics supported by
WinPMail and the syntax of the commands sent to them. It is not a tutorial
on DDE, and assumes that you either understand how to use DDE, or are using
an environment (such as Microsoft Word's WordBasic language) that
simplifies the process of using DDE commands.

One of the most powerful features of DDE is that it allows transparent
communication between 16-bit and 32-bit applications: so, by using DDE, you
can communicate with either the 16- or the 32-bit version of WinPMail
without having to be worried about the differences between the two.

Pegasus Mail's DDE interface has been designed to be as simple to use as
possible, and depends on simple strings for commands. It should be possible
to use DDE to interact with Pegasus Mail from almost any environment.



Service and Topic Names
-----------------------

Under DDE, a "service name" is the name of an application that can accept
DDE connections: when you connect to a service application, you specify a
particular set of commands or operations in which you are interested - this
set of commands is known as a "topic". Pegasus Mail uses the service name
"WinPMail" and exports the following topics:

   "System"        The standard DDE system topic
   "Environment"   Accepts DDE Requests (transactions of type XTYP_REQUEST)
                   and returns information about the environment of the
                   running copy of WinPMail, such as directories and
                   usernames.
   "Message"       Accepts DDE Poke commands to create and send e-mail
                   messages. A DDE Client can either create and manipulate
                   standard Pegasus Mail message editor windows, filling
                   in whichever blanks are required, or it can create
                   messages without a window.
   "TCP"           Provides access via DDE Poke commands to WinPMail's
                   TCP/IP-based mail services.



The "Environment" topic
-----------------------

The "Environment" DDE topic allows client applications to obtain
information about the running copy of Pegasus Mail. To use this command,
send a DDE Request command (a transaction of type XTYP_REQUEST) the the
"Environment" topic with the "item" parameter set to the environment item
you wish to retrieve, selected from the following list:

   USER           - Returns the name of the user running WinPMail 
   HOMEBOX        - Returns the full path to the user's home mail directory
   NEWBOX         - Returns the full path to the user's new mail directory
   MODE           - Returns either "Standalone" or "Network"
   VERSION        - Returns the version of WinPMail, expressed as a four
                    digit hexadecimal number ("0254" for v2.54) followed
                    by a space and either "16" or "32" to indicate the
                    version of WinPMail that is running.  
   BASEDIR        - The directory from which WinPMail was run
   TCP            - If WinPMail's TCP/IP services are available, returns
                    the path to the WINSOCK.DLL in use, otherwise returns
                    the single character "N".
   NEWMAIL        - Returns the number of mail messages in the user's new
                    mail folder.

-- Example: -----------------------------------

   In WordBasic (MS-Word 7) the following Macro opens a connection to
   WinPMail, retrieves the current version, and displays it:

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

   A longer example in C is shown as Appendix A: in this document.



The "Message" topic
-------------------

Client applications use the "Message" topic to create and send electronic
mail messages using WinPMail. Once a connection has been established to the
"Message" topic, the client Pokes data at WinPMail (using XTYP_POKE
transactions). The string parameter in the Poke command should be set to
"Message" - other values may be added in future. The data itself contains
the commands and parameters.

The following commands can be Poked as data to WinPMail:

   New : <"Message"> or <"Window">
      If the parameter is "Window", then WinPMail creates a standard
      message editing window, and subsequent message commands will change
      the controls and settings in that window. If the parameter is
      "Message", then a data structure representing the message is
      allocated internally and subsequent message commands will fill in the
      fields within that structure.

   Defaults : Y
      Tells WinPMail to apply the user's regular message setting default
      values to the message. This command is only valid when the
      "New: message" command has been sent - it has no effect on message
      editing windows created using "New: window", since they always use
      default values automatically.

   To : <address> [, <address> ...]
      Fills in the "To" field for the message or window. The parameter may
      be any address WinPMail would normally accept, and you may include
      more than one address by separating them with commas. The same rules
      apply to the Cc: and Bcc: fields.

   Cc : <address> [, <address> ...]
      Fills in the "Cc:" (Carbon Copy) field for the message.

   Bcc : <address> [, <address> ...]
      Fills in the "Bcc:" (Blind Carbon Copy) field for the message.

   Subject : <string>
      Fills in the subject field of the message.

   Reply-to : <address>
      Sets the optional reply address for the message.

   Copyself : <'Y'> or <'N'>
      Selects whether or not a copy-to-self should be made of the message.

   Confirm-delivery : <'Y'> or <'N'>
      Selects whether or not to request confirmation of delivery

   Confirm-reading : <'Y'> or <'N'>
      Selects whether or not to request confirmation of reading

   Urgent : <'Y'> or <'N'>
      Selects whether or not the message should be marked as "urgent"
      
   Encrypted : <encryptor-name><,><passphrase><,><flags>
      Chooses an encryption method for the message. "Encryptor-name" is
      the tagname of the encryptor you wish to use (use "PM-BUILTIN" to
      select Pegasus Mail's built-in encryptor). You can find the tagname
      for an encryptor in the "Form tagname" line of the encryptor's .FFF
      file. "passphrase" is the password for the message. If it contains
      a comma, then it must be quoted using " and ". "flags" is either
      1 to encrypt the message, 2 to sign the message, or 3 to encrypt
      and sign the message.

   Signature : <number>
      Chooses the signature you wish to attach to the message. "number"
      is 1 - 9, corresponding to the signature sets shown in WinPMail's
      Tools | Signatures preferences page, or 0 to disable signatures.

   Mime : <'Y'> or <'N'>
      Indicates whether or not MIME support should be turned on for
      this message. MIME support affects the way attachments and
      international characters are handled by WinPMail. We strongly
      recommend that you turn MIME on wherever possible.

   Attach : <path><,><filename><,><attachment-type><,><encoding>
      Attach a file to the message. "path" should be the full path
      to the file - do not assume that the current directory in your
      client application will be the same as the current directory in
      Pegasus Mail. "filename" is the name Pegasus Mail should include
      in the message as the real name of the file (you will typically
      use this when you have to create a temporary file but want to
      send it under the original file's name). If "filename" is "-",
      WinPMail will automatically use the filename portion of "path".
      "attachment-type" should be textual information describing the
      attachment; it must not contain spaces. If you set this field to
      a single dash ("-"), WinPMail will use its internal routines to
      try to work out the most appropriate type information for the
      file. "encoding" is used to select the type of encoding for the
      attachment: we strongly recommend that you set this value to 0,
      which will allow WinPMail to choose the most appropriate encoding
      for you. Possible values are:
         0 - Pegasus Mail decides.
         1 - No encoding - the file is not altered (local mail only)
         2 - ASCII encoding - the file is normalised to CR/LF line
             endings and is not otherwise encoded in transit.
         3 - UUencoding - the file is uuencoded
         4 - BinHex - the file is transformed using the BinHex 4.0 method.
         5 - MIME - the file is transformed using the MIME BASE64 method.

   File : <filename>
      Indicates the name of a file containing the text WinPMail should
      use as the body of the message. Note that this file is NOT an
      attachment - it is expected to be plain text.

   Data : <String>
      Adds "string" to the body of the message as a single line. Poke
      this command repeatedly to build up a message line by line.
      WinPMail automatically adds the CR/LF termination to each line.
      Poking this command with no <string> parameter will print a blank
      line in the message (but the ':' must still be present).

   Send
      This command sends the message. Note that it has no parameters and
      no ':'. It has no effect when "Window" was used as the parameter to
      the "New:" command.

   Restore
      This command brings WinPMail to the top and activates the Message
      Editing Window created using the "New: Window" command. Note that it
      has no parameters and no ':'. For messages created using the
      "New: Message" command, this command will simply bring WinPMail to
      the top without taking any other action.


-- Example: -----------------------------------

   In WordBasic (MS-Word 7) the following Macro opens a connection to
   WinPMail, and sends a message with no window.

      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



The "TCP" topic
---------------

The commands in this topic allow clients to control Pegasus Mail's
built-in TCP/IP-based mail protocols. Before using these commands, a
client should usually use the "TCP" request to the "Environment" topic to
determine whether or not TCP/IP services are enabled and available.
Clients interact with this topic by Poking data at it in a similar manner
to that used to access the "Message" topic. The following commands can be
poked at this topic:

   Get
      Tells Pegasus Mail to download mail using the current TCP/IP
      settings defined for the program.

   Send
      Tells Pegasus Mail to send any messages currently waiting in
      the queue to be sent out.

   Both
      Tells Pegasus Mail to check for new mail, then to send any messages
      currently waiting in the queue, in that order.

   Restore
      Brings Pegasus Mail to the front and gives it focus.


-- Example: -----------------------------------

   In WordBasic (MS-Word 7) the following Macro opens a connection to
   WinPMail, tells it to download new mail, then brings it to the front:

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



Pegasus Mail and the Windows Registry
-------------------------------------

Starting with v2.54, WinPMail updates the Windows registry with a certain
amount of information each time it is run. DDE Client Applications can use
this registry information to work out how to find a copy of Pegasus Mail to
run if none is active, and what commandline is appropriate.

The 32-bit version of WinPMail creates the following keys:

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

The "version" key contains the WinPMail version, expressed in exactly the
same way as the return from the DDE "Environment" topic's "Version"
request. The "BaseDir" key contains the directory where the WinPMail
executable file is located, and the "command" key contains the full
commandline that was used to invoke the most recently-run copy of Pegasus
Mail.

Both the 16- and 32-bit versions of WinPMail create the following keys:

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

These keys are formatted in exactly the same way as those shown above.
32-bit applications should always attempt to find the HKEY_CURRENT_USER
keys before the HKEY_CLASSES_ROOT keys, since doing so ensures that
multiple user configurations are respected under Windows 95 and NT.



Appendix A: Using DDE from C programs
-------------------------------------

The source code shown here can be used as a model for interacting with
any DDE-aware application. It presents a simple dialog with "Service",
"Topic" and "Command" fields, request selector radio buttons that allow
the user to select between XTYP_EXECUTE, XTYP_REQUEST and XTYP_POKE
transactions, and three buttons - one to open/close a connection, a
"quit" button, and a "Do it" button, that sends the command. If a
connection is established using the "Open" button, then the "Do it"
button will send the command to that connection, otherwise it will
establish a connection, send the command, then close the connection.

This code was written for Borland C++ v4.52 and should be linked using
Borland's BWCC.LIB or BWCC32.LIB in order to present the proper dialog
appearance.


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

