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$" );