Establishing a Network DDE Conversation
Establishing a conversation between a client application and a server application on different computers is similar to establishing a conversation between a client and server on the same computer. The difference is that the client specifies a computer and a DDE share, rather than an application and a topic.
The first step is for the server to register with the DDEML by calling the DdeInitialize function. This call requires a pointer to the application-defined DDE callback function DdeCallback. The server also registers the service name that the DDE server supports by calling the DdeNameService function.
DWORD g_idInst;
BOOL MyDdeShareInit( LPTSTR lpszServer, PFNCALLBACK DdeCallback )
{
HSZ hszService;
char ServerBuf[MAX_COMPUTERNAME_LENGTH+8];
// Register the server application.
if( DdeInitialize(
&g_idInst,
(PFNCALLBACK) DdeCallback,
APPCLASS_STANDARD | CBF_FAIL_SELFCONNECTIONS |
CBF_FAIL_REQUESTS | CBF_FAIL_EXECUTES,
0L
) != DMLERR_NO_ERROR )
return FALSE;
// Check if "\\server" or just "server" is specified.
if( lpszServer[0] == '\\' )
wsprintf( ServerBuf, "%s\\NDDE$", lpszServer );
else wsprintf( ServerBuf, "\\\\%s\\NDDE$", lpszServer );
// Register the service names.
hszService = DdeCreateStringHandle( g_idInst, ServerBuf, 0 );
DdeNameService(
g_idInst,
hszService,
0,
DNS_REGISTER
);
DdeFreeStringHandle( g_idInst, hszService );
return TRUE;
}
The following example shows how you could call the MyConnect function to initialize DDEML for the server application on computer ServerA:
// Application-supplied callback function.
HDDEDATA CALLBACK DdeCallback( UINT iType, UINT iFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2 )
{
switch( iType )
{
case XTYP_CONNECT:
// Validate topic for connection.
...
return (HDDEDATA) TRUE;
...
default:
return (HDDEDATA) 0;
}
}
MyDdeShareInit( "ServerA", DdeCallback );
As with any DDE conversation, the client and server applications must cooperate to establish a conversation. For network DDE, the client must have the computer name and the share name. The client then uses the DdeConnect function to establish a network DDE conversation.
HCONV g_hConv;
BOOL MyConnect( LPSTR lpszServer, LPTSTR lpszTopic )
{
HSZ hszServer, hszTopic;
char ServerBuf[MAX_COMPUTERNAME_LENGTH+8];
// Register the client application.
if( DdeInitialize(
&g_idInst,
(PFNCALLBACK) DdeCallback,
APPCLASS_STANDARD | CBF_FAIL_SELFCONNECTIONS |
CBF_FAIL_REQUESTS | CBF_FAIL_EXECUTES,
0L
) != DMLERR_NO_ERROR )
return FALSE;
// Check if "\\server" or just "server" is specified.
if( lpszServer[0] == '\\' )
wsprintf( ServerBuf, "%s\\NDDE$", lpszServer );
else wsprintf( ServerBuf, "\\\\%s\\NDDE$", lpszServer );
hszServer = DdeCreateStringHandle(g_idInst, ServerBuf, 0);
hszTopic = DdeCreateStringHandle(g_idInst, lpszTopic, 0);
if( (g_hConv = DdeConnect(g_idInst,
hszServer,
hszTopic,
NULL )
) == 0 )
return FALSE;
DdeFreeStringHandle( g_idInst, hszServer );
DdeFreeStringHandle( g_idInst, hszTopic );
return TRUE;
}
The following example shows how you could call this function to connect to the DDE share MyDdeShare$ on computer ServerA:
// Application-supplied callback function.
HDDEDATA CALLBACK DdeCallback( UINT iType, UINT iFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2 )
{
switch( iType )
{
...
default:
return (HDDEDATA) 0;
}
}
MyConnect( "ServerA", "MyDdeShare$" );