Platform SDK: Interprocess Communications |
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$" );