home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / E-MAIL / W32 / W32-255.EXE / WINPMDDE.TXT < prev    next >
Text File  |  1997-05-30  |  28KB  |  713 lines

  1. Pegasus Mail for Windows DDE (Dynamic Data Exchange) Interface
  2. Copyright (c) 1997, David Harris, All Rights Reserved.
  3. ----------------------------------------------------------------
  4.  
  5. Pegasus Mail v2.54 and later incorporates support for Windows DDE to allow
  6. interprocess communication. This document describes the topics supported by
  7. WinPMail and the syntax of the commands sent to them. It is not a tutorial
  8. on DDE, and assumes that you either understand how to use DDE, or are using
  9. an environment (such as Microsoft Word's WordBasic language) that
  10. simplifies the process of using DDE commands.
  11.  
  12. One of the most powerful features of DDE is that it allows transparent
  13. communication between 16-bit and 32-bit applications: so, by using DDE, you
  14. can communicate with either the 16- or the 32-bit version of WinPMail
  15. without having to be worried about the differences between the two.
  16.  
  17. Pegasus Mail's DDE interface has been designed to be as simple to use as
  18. possible, and depends on simple strings for commands. It should be possible
  19. to use DDE to interact with Pegasus Mail from almost any environment.
  20.  
  21.  
  22.  
  23. Service and Topic Names
  24. -----------------------
  25.  
  26. Under DDE, a "service name" is the name of an application that can accept
  27. DDE connections: when you connect to a service application, you specify a
  28. particular set of commands or operations in which you are interested - this
  29. set of commands is known as a "topic". Pegasus Mail uses the service name
  30. "WinPMail" and exports the following topics:
  31.  
  32.    "System"        The standard DDE system topic
  33.    "Environment"   Accepts DDE Requests (transactions of type XTYP_REQUEST)
  34.                    and returns information about the environment of the
  35.                    running copy of WinPMail, such as directories and
  36.                    usernames.
  37.    "Message"       Accepts DDE Poke commands to create and send e-mail
  38.                    messages. A DDE Client can either create and manipulate
  39.                    standard Pegasus Mail message editor windows, filling
  40.                    in whichever blanks are required, or it can create
  41.                    messages without a window.
  42.    "TCP"           Provides access via DDE Poke commands to WinPMail's
  43.                    TCP/IP-based mail services.
  44.  
  45.  
  46.  
  47. The "Environment" topic
  48. -----------------------
  49.  
  50. The "Environment" DDE topic allows client applications to obtain
  51. information about the running copy of Pegasus Mail. To use this command,
  52. send a DDE Request command (a transaction of type XTYP_REQUEST) the the
  53. "Environment" topic with the "item" parameter set to the environment item
  54. you wish to retrieve, selected from the following list:
  55.  
  56.    USER           - Returns the name of the user running WinPMail 
  57.    HOMEBOX        - Returns the full path to the user's home mail directory
  58.    NEWBOX         - Returns the full path to the user's new mail directory
  59.    MODE           - Returns either "Standalone" or "Network"
  60.    VERSION        - Returns the version of WinPMail, expressed as a four
  61.                     digit hexadecimal number ("0254" for v2.54) followed
  62.                     by a space and either "16" or "32" to indicate the
  63.                     version of WinPMail that is running.  
  64.    BASEDIR        - The directory from which WinPMail was run
  65.    TCP            - If WinPMail's TCP/IP services are available, returns
  66.                     the path to the WINSOCK.DLL in use, otherwise returns
  67.                     the single character "N".
  68.    NEWMAIL        - Returns the number of mail messages in the user's new
  69.                     mail folder.
  70.  
  71. -- Example: -----------------------------------
  72.  
  73.    In WordBasic (MS-Word 7) the following Macro opens a connection to
  74.    WinPMail, retrieves the current version, and displays it:
  75.  
  76.       Sub MAIN
  77.       channel = DDEInitiate("WinPMail", "Environment")
  78.       a$ = DDERequest$(channel, "version")
  79.       DDETerminate channel
  80.       MsgBox a$
  81.       End Sub
  82.  
  83.    A longer example in C is shown as Appendix A: in this document.
  84.  
  85.  
  86.  
  87. The "Message" topic
  88. -------------------
  89.  
  90. Client applications use the "Message" topic to create and send electronic
  91. mail messages using WinPMail. Once a connection has been established to the
  92. "Message" topic, the client Pokes data at WinPMail (using XTYP_POKE
  93. transactions). The string parameter in the Poke command should be set to
  94. "Message" - other values may be added in future. The data itself contains
  95. the commands and parameters.
  96.  
  97. The following commands can be Poked as data to WinPMail:
  98.  
  99.    New : <"Message"> or <"Window">
  100.       If the parameter is "Window", then WinPMail creates a standard
  101.       message editing window, and subsequent message commands will change
  102.       the controls and settings in that window. If the parameter is
  103.       "Message", then a data structure representing the message is
  104.       allocated internally and subsequent message commands will fill in the
  105.       fields within that structure.
  106.  
  107.    Defaults : Y
  108.       Tells WinPMail to apply the user's regular message setting default
  109.       values to the message. This command is only valid when the
  110.       "New: message" command has been sent - it has no effect on message
  111.       editing windows created using "New: window", since they always use
  112.       default values automatically.
  113.  
  114.    To : <address> [, <address> ...]
  115.       Fills in the "To" field for the message or window. The parameter may
  116.       be any address WinPMail would normally accept, and you may include
  117.       more than one address by separating them with commas. The same rules
  118.       apply to the Cc: and Bcc: fields.
  119.  
  120.    Cc : <address> [, <address> ...]
  121.       Fills in the "Cc:" (Carbon Copy) field for the message.
  122.  
  123.    Bcc : <address> [, <address> ...]
  124.       Fills in the "Bcc:" (Blind Carbon Copy) field for the message.
  125.  
  126.    Subject : <string>
  127.       Fills in the subject field of the message.
  128.  
  129.    Reply-to : <address>
  130.       Sets the optional reply address for the message.
  131.  
  132.    Copyself : <'Y'> or <'N'>
  133.       Selects whether or not a copy-to-self should be made of the message.
  134.  
  135.    Confirm-delivery : <'Y'> or <'N'>
  136.       Selects whether or not to request confirmation of delivery
  137.  
  138.    Confirm-reading : <'Y'> or <'N'>
  139.       Selects whether or not to request confirmation of reading
  140.  
  141.    Urgent : <'Y'> or <'N'>
  142.       Selects whether or not the message should be marked as "urgent"
  143.       
  144.    Encrypted : <encryptor-name><,><passphrase><,><flags>
  145.       Chooses an encryption method for the message. "Encryptor-name" is
  146.       the tagname of the encryptor you wish to use (use "PM-BUILTIN" to
  147.       select Pegasus Mail's built-in encryptor). You can find the tagname
  148.       for an encryptor in the "Form tagname" line of the encryptor's .FFF
  149.       file. "passphrase" is the password for the message. If it contains
  150.       a comma, then it must be quoted using " and ". "flags" is either
  151.       1 to encrypt the message, 2 to sign the message, or 3 to encrypt
  152.       and sign the message.
  153.  
  154.    Signature : <number>
  155.       Chooses the signature you wish to attach to the message. "number"
  156.       is 1 - 9, corresponding to the signature sets shown in WinPMail's
  157.       Tools | Signatures preferences page, or 0 to disable signatures.
  158.  
  159.    Mime : <'Y'> or <'N'>
  160.       Indicates whether or not MIME support should be turned on for
  161.       this message. MIME support affects the way attachments and
  162.       international characters are handled by WinPMail. We strongly
  163.       recommend that you turn MIME on wherever possible.
  164.  
  165.    Attach : <path><,><filename><,><attachment-type><,><encoding>
  166.       Attach a file to the message. "path" should be the full path
  167.       to the file - do not assume that the current directory in your
  168.       client application will be the same as the current directory in
  169.       Pegasus Mail. "filename" is the name Pegasus Mail should include
  170.       in the message as the real name of the file (you will typically
  171.       use this when you have to create a temporary file but want to
  172.       send it under the original file's name). If "filename" is "-",
  173.       WinPMail will automatically use the filename portion of "path".
  174.       "attachment-type" should be textual information describing the
  175.       attachment; it must not contain spaces. If you set this field to
  176.       a single dash ("-"), WinPMail will use its internal routines to
  177.       try to work out the most appropriate type information for the
  178.       file. "encoding" is used to select the type of encoding for the
  179.       attachment: we strongly recommend that you set this value to 0,
  180.       which will allow WinPMail to choose the most appropriate encoding
  181.       for you. Possible values are:
  182.          0 - Pegasus Mail decides.
  183.          1 - No encoding - the file is not altered (local mail only)
  184.          2 - ASCII encoding - the file is normalised to CR/LF line
  185.              endings and is not otherwise encoded in transit.
  186.          3 - UUencoding - the file is uuencoded
  187.          4 - BinHex - the file is transformed using the BinHex 4.0 method.
  188.          5 - MIME - the file is transformed using the MIME BASE64 method.
  189.  
  190.    File : <filename>
  191.       Indicates the name of a file containing the text WinPMail should
  192.       use as the body of the message. Note that this file is NOT an
  193.       attachment - it is expected to be plain text.
  194.  
  195.    Data : <String>
  196.       Adds "string" to the body of the message as a single line. Poke
  197.       this command repeatedly to build up a message line by line.
  198.       WinPMail automatically adds the CR/LF termination to each line.
  199.       Poking this command with no <string> parameter will print a blank
  200.       line in the message (but the ':' must still be present).
  201.  
  202.    Send
  203.       This command sends the message. Note that it has no parameters and
  204.       no ':'. It has no effect when "Window" was used as the parameter to
  205.       the "New:" command.
  206.  
  207.    Restore
  208.       This command brings WinPMail to the top and activates the Message
  209.       Editing Window created using the "New: Window" command. Note that it
  210.       has no parameters and no ':'. For messages created using the
  211.       "New: Message" command, this command will simply bring WinPMail to
  212.       the top without taking any other action.
  213.  
  214.  
  215. -- Example: -----------------------------------
  216.  
  217.    In WordBasic (MS-Word 7) the following Macro opens a connection to
  218.    WinPMail, and sends a message with no window.
  219.  
  220.       Sub MAIN
  221.       channel = DDEInitiate("WinPMail", "Message")
  222.       DDEPoke channel, "Message", "New: Message"
  223.       DDEPoke channel, "Message", "Defaults: Y"
  224.       DDEPoke channel, "Message", "To: David"
  225.       DDEPoke channel, "Message", "Subject: Test from Word"
  226.       DDEPoke channel, "Message", "Data: Hi there!"
  227.       DDEPoke channel, "Message", "Send"
  228.       DDETerminate channel
  229.       End Sub
  230.  
  231.  
  232.  
  233. The "TCP" topic
  234. ---------------
  235.  
  236. The commands in this topic allow clients to control Pegasus Mail's
  237. built-in TCP/IP-based mail protocols. Before using these commands, a
  238. client should usually use the "TCP" request to the "Environment" topic to
  239. determine whether or not TCP/IP services are enabled and available.
  240. Clients interact with this topic by Poking data at it in a similar manner
  241. to that used to access the "Message" topic. The following commands can be
  242. poked at this topic:
  243.  
  244.    Get
  245.       Tells Pegasus Mail to download mail using the current TCP/IP
  246.       settings defined for the program.
  247.  
  248.    Send
  249.       Tells Pegasus Mail to send any messages currently waiting in
  250.       the queue to be sent out.
  251.  
  252.    Both
  253.       Tells Pegasus Mail to check for new mail, then to send any messages
  254.       currently waiting in the queue, in that order.
  255.  
  256.    Restore
  257.       Brings Pegasus Mail to the front and gives it focus.
  258.  
  259.  
  260. -- Example: -----------------------------------
  261.  
  262.    In WordBasic (MS-Word 7) the following Macro opens a connection to
  263.    WinPMail, tells it to download new mail, then brings it to the front:
  264.  
  265.       Sub MAIN
  266.       channel = DDEInitiate("WinPMail", "TCP")
  267.       DDEPoke channel, "TCP", "Get"
  268.       DDEPoke channel, "TCP", "Restore"
  269.       DDETerminate channel
  270.       End Sub
  271.  
  272.  
  273.  
  274. Pegasus Mail and the Windows Registry
  275. -------------------------------------
  276.  
  277. Starting with v2.54, WinPMail updates the Windows registry with a certain
  278. amount of information each time it is run. DDE Client Applications can use
  279. this registry information to work out how to find a copy of Pegasus Mail to
  280. run if none is active, and what commandline is appropriate.
  281.  
  282. The 32-bit version of WinPMail creates the following keys:
  283.  
  284.    HKEY_CURRENT_USER\Software\Pegasus Mail\Version
  285.    HKEY_CURRENT_USER\Software\Pegasus Mail\BaseDir
  286.    HKEY_CURRENT_USER\Software\Pegasus Mail\Command
  287.  
  288. The "version" key contains the WinPMail version, expressed in exactly the
  289. same way as the return from the DDE "Environment" topic's "Version"
  290. request. The "BaseDir" key contains the directory where the WinPMail
  291. executable file is located, and the "command" key contains the full
  292. commandline that was used to invoke the most recently-run copy of Pegasus
  293. Mail.
  294.  
  295. Both the 16- and 32-bit versions of WinPMail create the following keys:
  296.  
  297.    HKEY_CLASSES_ROOT\Software\Pegasus Mail\Version
  298.    HKEY_CLASSES_ROOT\Software\Pegasus Mail\BaseDir
  299.    HKEY_CLASSES_ROOT\Software\Pegasus Mail\Command
  300.  
  301. These keys are formatted in exactly the same way as those shown above.
  302. 32-bit applications should always attempt to find the HKEY_CURRENT_USER
  303. keys before the HKEY_CLASSES_ROOT keys, since doing so ensures that
  304. multiple user configurations are respected under Windows 95 and NT.
  305.  
  306.  
  307.  
  308. Appendix A: Using DDE from C programs
  309. -------------------------------------
  310.  
  311. The source code shown here can be used as a model for interacting with
  312. any DDE-aware application. It presents a simple dialog with "Service",
  313. "Topic" and "Command" fields, request selector radio buttons that allow
  314. the user to select between XTYP_EXECUTE, XTYP_REQUEST and XTYP_POKE
  315. transactions, and three buttons - one to open/close a connection, a
  316. "quit" button, and a "Do it" button, that sends the command. If a
  317. connection is established using the "Open" button, then the "Do it"
  318. button will send the command to that connection, otherwise it will
  319. establish a connection, send the command, then close the connection.
  320.  
  321. This code was written for Borland C++ v4.52 and should be linked using
  322. Borland's BWCC.LIB or BWCC32.LIB in order to present the proper dialog
  323. appearance.
  324.  
  325.  
  326. --------------- DDECLI.C --------------------------------------------
  327. #include <windows.h>
  328. #include <windowsx.h>
  329. #include <stdlib.h>
  330. #include <string.h>
  331. #include <ddeml.h>
  332.  
  333. DWORD idInst = 0L;      // DDE instance identifier
  334. HINSTANCE hInstance;
  335. HCONV mconv;
  336. HSZ ghszServSrv;
  337. HSZ ghszServTop;
  338.  
  339. #pragma warn -par
  340. #pragma warn -use
  341.  
  342.  
  343. HDDEDATA EXPENTRY DDECallback (WORD wType,   // transaction type
  344.    WORD     wFmt,    // clipboard format
  345.    HCONV    hConv,   // handle of the conversation
  346.     HSZ      hsz1,    // handle of a string
  347.    HSZ      hsz2,    // handle of a string
  348.    HDDEDATA hData,   // handle of a global memory object
  349.    DWORD    dwData1, // transaction-specific data
  350.    DWORD    dwData2) // transaction-specific data
  351.    {
  352.    // Nothing need be done here...
  353.    return (HDDEDATA) NULL;
  354.    }
  355.  
  356.  
  357. BOOL SendShellCommand (DWORD idInst, char *service, char *topic, LPSTR lpCommand)
  358.    {
  359.    HSZ      hszServSrv;    // Service is "DDESERV"
  360.    HSZ      hszServTop;    // Topic is "MAIL"
  361.    HCONV    hconv;         // handle of conversation
  362.    int      nLen;          // length of command string
  363.    HDDEDATA hData;         // return value of DdeClientTransaction
  364.    DWORD    dwResult;      // result of transaction
  365.    BOOL     bResult=FALSE; // TRUE if this function is successful
  366.  
  367.    if (mconv == NULL)
  368.       {
  369.       // create string handle to service/topic
  370.       hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
  371.       hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);
  372.  
  373.       // attempt to start conversation with server app
  374.        hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
  375.       }
  376.    else
  377.       hconv = mconv;
  378.  
  379.    if (hconv != NULL)
  380.       {
  381.       // get length of the command string
  382.       nLen = lstrlen ((LPSTR) lpCommand);
  383.  
  384.       // send command to server app
  385.       hData = DdeClientTransaction (
  386.          (LPBYTE) lpCommand, // data to pass
  387.          nLen + 1,           // length of data
  388.          hconv,              // handle of conversation
  389.          NULL,               // handle of name-string
  390.          CF_TEXT,            // clipboard format
  391.          XTYP_EXECUTE,       // transaction type
  392.          20000,              // timeout duration
  393.          &dwResult);         // points to transaction result
  394.  
  395.       if (hData)
  396.          bResult = TRUE;
  397.  
  398.       if (mconv == NULL)
  399.          // end conversation
  400.          DdeDisconnect (hconv);
  401.       }
  402.  
  403.    if (mconv == NULL)
  404.       {
  405.       // free service/topic string handle
  406.       DdeFreeStringHandle(idInst, hszServSrv);
  407.       DdeFreeStringHandle(idInst, hszServTop);
  408.       }
  409.  
  410.    if (bResult == FALSE)
  411.       MessageBox (NULL, "SendShellCommand failed", "DDE Client", MB_OK);
  412.  
  413.    return bResult;
  414.    }
  415.  
  416.  
  417. BOOL SendPoke (DWORD idInst, char *service, char *topic, LPSTR lpCommand)
  418.    {
  419.    HSZ      hszServSrv;    // Service is "DDESERV"
  420.    HSZ      hszServTop;    // Topic is "MAIL"
  421.    HCONV    hconv;         // handle of conversation
  422.    int      nLen;          // length of command string
  423.    HDDEDATA hData;         // return value of DdeClientTransaction
  424.    DWORD    dwResult;      // result of transaction
  425.    BOOL     bResult=FALSE; // TRUE if this function is successful
  426.  
  427.    if (mconv == NULL)
  428.       {
  429.       // create string handle to service/topic
  430.       hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
  431.       hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);
  432.  
  433.       // attempt to start conversation with server app
  434.        hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
  435.       }
  436.    else
  437.       hconv = mconv;
  438.  
  439.    if (hconv != NULL)
  440.       {
  441.       // get length of the command string
  442.       nLen = lstrlen ((LPSTR) lpCommand);
  443.  
  444.       // send command to server app
  445.       hData = DdeClientTransaction (
  446.          (LPBYTE) lpCommand, // data to pass
  447.          nLen + 1,           // length of data
  448.          hconv,              // handle of conversation
  449.          hszServTop,         // handle of name-string
  450.          CF_TEXT,            // clipboard format
  451.          XTYP_POKE,          // transaction type
  452.          20000,              // timeout duration
  453.          &dwResult);         // points to transaction result
  454.  
  455.       if (hData)
  456.          bResult = TRUE;
  457.  
  458.       if (mconv == NULL)
  459.          // end conversation
  460.          DdeDisconnect (hconv);
  461.       }
  462.  
  463.    if (mconv == NULL)
  464.       {
  465.       // free service/topic string handle
  466.       DdeFreeStringHandle(idInst, hszServSrv);
  467.       DdeFreeStringHandle(idInst, hszServTop);
  468.       }
  469.  
  470.    if (bResult == FALSE)
  471.       MessageBox (NULL, "SendPoke failed", "DDE Client", MB_OK);
  472.  
  473.    return bResult;
  474.    }
  475.  
  476.  
  477. BOOL SendShellRequest (DWORD idInst, char *service, char *topic, char *cmd)
  478.    {
  479.    HSZ      hszServSrv;    // Service is "DDESERV"
  480.    HSZ      hszServTop;    // Topic is "MAIL"
  481.    HSZ      item;
  482.    HCONV    hconv;         // handle of conversation
  483.    int      nLen;          // length of command string
  484.    HDDEDATA hData;         // return value of DdeClientTransaction
  485.    DWORD    dwResult;      // result of transaction
  486.    BOOL     bResult=FALSE; // TRUE if this function is successful
  487.    char     *str;
  488.    DWORD    x;
  489.  
  490.    if (mconv == NULL)
  491.       {
  492.       // create string handle to service/topic
  493.       hszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
  494.       hszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);
  495.  
  496.       // attempt to start conversation with server app
  497.        hconv = DdeConnect (idInst, hszServSrv, hszServTop, NULL);
  498.       }
  499.    else
  500.       hconv = mconv;
  501.  
  502.    if (hconv != NULL)
  503.       {
  504.       // send command to server app
  505.       item = DdeCreateStringHandle (idInst, cmd, CP_WINANSI);
  506.       hData = DdeClientTransaction (
  507.          NULL,               // data to pass
  508.          0,                  // length of data
  509.          hconv,              // handle of conversation
  510.          item,               // handle of name-string
  511.          CF_TEXT,            // clipboard format
  512.          XTYP_REQUEST,       // transaction type
  513.          20000,              // timeout duration
  514.          &dwResult);         // points to transaction result
  515.  
  516.       if (hData)
  517.          {
  518.          if ((str = (char *) DdeAccessData (hData, &x)) != NULL)
  519.             {
  520.             strcpy (cmd, str);
  521.             bResult = TRUE;
  522.             DdeUnaccessData (hData);
  523.             }
  524.  
  525.          DdeFreeDataHandle (hData);
  526.          }
  527.  
  528.       DdeFreeStringHandle (idInst, item);
  529.  
  530.       if (mconv == NULL)
  531.          // end conversation
  532.          DdeDisconnect (hconv);
  533.       }
  534.  
  535.    if (mconv == NULL)
  536.       {
  537.       // free service/topic string handle
  538.       DdeFreeStringHandle (idInst, hszServSrv);
  539.       DdeFreeStringHandle (idInst, hszServTop);
  540.       }
  541.  
  542.    return bResult;
  543.    }
  544.  
  545.  
  546. int FAR PASCAL _export dummy_proc (HWND hDialog, UINT wMsg,
  547.    WPARAM wParam, LPARAM lParam)
  548.    {
  549.    BOOL fProcessed = TRUE;
  550.    DWORD dwResult;
  551.    RECT r;
  552.    HWND hControl;
  553.    char buffer [256], service [80], topic [80];
  554.  
  555.    switch (wMsg)
  556.       {
  557.       case WM_INITDIALOG :
  558.          CheckRadioButton (hDialog, 104, 106, 104);
  559.          break;
  560.  
  561.       case WM_SETFOCUS :
  562.          SetFocus (GetDlgItem (hDialog, 101));
  563.          break;
  564.  
  565.       case WM_COMMAND :
  566.          if (GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
  567.             {
  568.             EndDialog (hDialog, IDCANCEL);
  569.             break;
  570.             }
  571.  
  572.          if (GET_WM_COMMAND_ID(wParam, lParam) == 120)
  573.             {
  574.             if (mconv == NULL)
  575.                {
  576.                GetDlgItemText (hDialog, 101, service, sizeof (service));
  577.                GetDlgItemText (hDialog, 102, topic, sizeof (topic));
  578.                ghszServSrv = DdeCreateStringHandle (idInst, service, CP_WINANSI);
  579.                ghszServTop = DdeCreateStringHandle (idInst, topic, CP_WINANSI);
  580.  
  581.                // attempt to start conversation with server app
  582.                 mconv = DdeConnect (idInst, ghszServSrv, ghszServTop, NULL);
  583.                if (mconv == NULL)
  584.                   MessageBox (NULL, "Connection failed!", "DDE Client", 
  585.                      MB_OK | MB_ICONEXCLAMATION);
  586.                else
  587.                   SetDlgItemText (hDialog, 120, "Close");
  588.                }
  589.             else
  590.                {
  591.                DdeDisconnect (mconv);
  592.                mconv = NULL;
  593.                DdeFreeStringHandle (idInst, ghszServSrv);
  594.                DdeFreeStringHandle (idInst, ghszServTop);
  595.                SetDlgItemText (hDialog, 120, "Open");
  596.                }
  597.             break;
  598.             }
  599.  
  600.          if (GET_WM_COMMAND_ID(wParam, lParam) == IDOK)
  601.             {
  602.             GetDlgItemText (hDialog, 101, service, sizeof (service));
  603.             GetDlgItemText (hDialog, 102, topic, sizeof (topic));
  604.             GetDlgItemText (hDialog, 103, buffer, sizeof (buffer));
  605.             hControl = GetDlgItem (hDialog, 107);
  606.             if (IsDlgButtonChecked (hDialog, 105))   //  Request
  607.                {
  608.                if (SendShellRequest (idInst, service, topic, buffer))
  609.                   {
  610.                   Edit_ReplaceSel (hControl, "Request successful:\r\n   ");
  611.                   Edit_ReplaceSel (hControl, buffer);
  612.                   Edit_ReplaceSel (hControl, "\r\n");
  613.                   }
  614.                else
  615.                   Edit_ReplaceSel (hControl, "Request failed.\r\n");
  616.                }
  617.             else if (IsDlgButtonChecked (hDialog, 104))
  618.                {
  619.                if (SendShellCommand (idInst, service, topic, buffer))
  620.                   Edit_ReplaceSel (hControl, "Command successful.\r\n");
  621.                else
  622.                   Edit_ReplaceSel (hControl, "Command failed.\r\n");
  623.                }
  624.             else
  625.                {
  626.                if (SendPoke (idInst, service, topic, buffer))
  627.                   Edit_ReplaceSel (hControl, "Poke successful.\r\n");
  628.                else
  629.                   Edit_ReplaceSel (hControl, "Poke failed.\r\n");
  630.                Edit_SetSel (GetDlgItem (hDialog, 103), 0, 999);
  631.                }
  632.             }
  633.          break;
  634.  
  635.       default:
  636.          fProcessed = FALSE;
  637.          break;
  638.       }
  639.  
  640.    return fProcessed;
  641.    }
  642.  
  643.  
  644. int PASCAL WinMain (HINSTANCE __hInstance, HINSTANCE hPrevInstance,
  645.    LPSTR lpszCmdLine, int nCmdShow)
  646.    {
  647.    MSG msg;
  648.    HWND hWndFrame;
  649.    WNDCLASS wc;
  650.    FARPROC DDEProc, dlgProc;
  651.  
  652.    if (hPrevInstance != NULL)
  653.       return 0;
  654.  
  655.    hInstance = __hInstance;
  656.  
  657.    // get proc instance for our DDEML callback
  658.    DDEProc = MakeProcInstance ((FARPROC) DDECallback, hInstance);
  659.  
  660.    // register this app with the DDEML
  661.    if (DdeInitialize (&idInst,   // receives instance ID
  662.       (PFNCALLBACK) DDEProc,     // address of callback function
  663.       APPCMD_CLIENTONLY,         // this is a client app
  664.       0L))                       // reserved
  665.       {
  666. #ifndef __FLAT__        //  FreeProcInstance is obsolete under Win32
  667.       FreeProcInstance (DDEProc);
  668. #endif
  669.       return FALSE;
  670.       }
  671.  
  672.    dlgProc = MakeProcInstance ((FARPROC) dummy_proc, hInstance);
  673.    DialogBox (hInstance, "CLIENT", NULL, dlgProc);
  674.    DdeUninitialize (idInst);
  675.    return 0;
  676.    }
  677.  
  678. --------------- DDECLI.DEF ----------------------------------------
  679. NAME           DDECLI
  680. DESCRIPTION    'DDE Test Client'
  681. EXETYPE        WINDOWS
  682. DATA           MOVEABLE MULTIPLE PRELOAD
  683. CODE           MOVEABLE DISCARDABLE
  684. HEAPSIZE       27500
  685. STACKSIZE      16500
  686.  
  687. --------------- DDECLI.RC -----------------------------------------
  688.  
  689. CLIENT DIALOG 180, 121, 246, 168
  690. STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
  691. CLASS "bordlg"
  692. CAPTION "DDE Test Client"
  693. FONT 8, "MS Sans Serif"
  694. {
  695.  RTEXT "Service name:", -1, 15, 15, 60, 8
  696.  CONTROL "winpmail", 101, "EDIT", ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP, 83, 13, 102, 12
  697.  RTEXT "Topic name:", -1, 15, 30, 60, 8
  698.  CONTROL "message", 102, "EDIT", ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP, 83, 28, 102, 12
  699.  RTEXT "Command/request:", -1, 14, 45, 61, 8
  700.  EDITTEXT 103, 83, 43, 102, 12, ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP
  701.  RTEXT "Transaction type:", -1, 15, 65, 60, 8
  702.  CONTROL "Execute", 104, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 85, 64, 47, 10
  703.  CONTROL "Request", 105, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 133, 64, 43, 10
  704.  CONTROL "Poke", 106, "BorRadio", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 184, 64, 32, 10
  705.  LTEXT "Results / Diagnostics", -1, 12, 82, 78, 8
  706.  EDITTEXT 107, 10, 92, 228, 69, ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
  707.  DEFPUSHBUTTON "Do it", IDOK, 192, 12, 43, 14
  708.  PUSHBUTTON "Quit", IDCANCEL, 192, 42, 43, 14
  709.  CONTROL "", -1, "BorShade", BSS_GROUP | BSS_CAPTION | BSS_LEFT | WS_CHILD | WS_VISIBLE, -5, -7, 257, 180
  710.  PUSHBUTTON "Open", 120, 192, 27, 43, 14
  711. }
  712.  
  713.