737 lines
28 KiB
Plaintext
737 lines
28 KiB
Plaintext
Pegasus Mail for Windows DDE (Dynamic Data Exchange) Interface
|
|
Copyright (c) 1997-1999, David Harris, All Rights Reserved.
|
|
----------------------------------------------------------------
|
|
|
|
Revision history:
|
|
* WinPMail v3.11: added IDENTITY and VOLATILE keywords to MESSAGE topic.
|
|
* WinPMail v3.12: added RICHTEXT keyword to MESSAGE topic, and STATUS
|
|
keyword to ENVIRONMENT topic
|
|
|
|
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.
|
|
STATUS - Returns the status of the last mail delivery operation
|
|
|
|
-- 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).
|
|
|
|
Identity : <identity_name>
|
|
Sets the identity Pegasus Mail should use when processing this
|
|
message. For more information on Identities, see the Pegasus Mail
|
|
help file. You can specify any valid identity name as the parameter
|
|
to this command. The default is the user's current identity.
|
|
|
|
Volatile : <'Y'> or <'N'> (Default is 'Y')
|
|
(Only meaningful when using Pegasus Mail's built-in SMTP mailer).
|
|
Setting this flag to 'Y' tells Pegasus Mail that the message should
|
|
be written straight into Final Form in the queue when it is sent.
|
|
If you want your message to be reloadable from Pegasus Mail's
|
|
"Review queued mail" option, you should set this to 'N'. If your
|
|
message contains attachments that you plan to delete once the
|
|
message has been sent, you must not set this field to 'N'.
|
|
|
|
Richtext : <'Y'> or <'N'> (Default is 'N')
|
|
Set the "rich text" flag in the message.
|
|
|
|
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
|
|
}
|
|
|