5.6.1 Single Conversations

A client application requests a single conversation with a server by calling the DdeConnect function, specifying string handles that identify the strings specifying the service name of the server and the topic name of interest. The DDEML responds by sending the XTYP_CONNECT transaction to the DDE callback function of each server application that either has registered a service name that matches the one specified in the DdeConnect function or has turned service-name filtering off by calling the DdeNameService function. A server can also filter the XTYP_CONNECT transactions by specifying the CBF_FAIL_CONNECTIONS filter flag in the DdeInitialize function. During the XTYP_CONNECT transaction, the DDEML passes the service name and the topic name to the server. The server should examine the names and return TRUE if it supports the service/topic name pair or FALSE if it does not.

If no server returns TRUE from the XTYP_CONNECT transaction, the client receives NULL from the DdeConnect function and no conversation is established. If a server does return TRUE, a conversation is established and the client receives a conversation handle—a doubleword value that identifies the conversation. The client uses the handle in subsequent DDEML calls to obtain data from the server. The server receives the XTYP_CONNECT_CONFIRM transaction (unless the server specified the CBF_FAIL_CONFIRMS filter flag). This transaction passes the conversation handle to the server.

The following example requests a conversation on the System topic with a server that recognizes the service name MyServer. The hszServName and hszSysTopic parameters are previously created string handles.

HCONV hConv;
HWND hwndParent;
HSZ hszServName;
HSZ hszSysTopic;

hConv = DdeConnect(
    idInst,         /* instance identifier              */
    hszServName,    /* service-name string handle       */
    hszSysTopic,    /* System-topic string handle       */
    (PCONVCONTEXT) NULL); /* reserved--must be NULL     */

if (hConv == NULL) {
    MessageBox(hwndParent, "MyServer is unavailable.",
        (LPSTR) NULL, MB_OK);
    return FALSE;
}

The DdeConnect function in the preceding example causes the DDE callback function of the MyServer application to receive an XTYP_CONNECT transaction.

In the following example, the server responds to the XTYP_CONNECT transaction by comparing the topic-name string handle that the DDEML passed to the server with each element in the array of topic-name string handles that the server supports. If the server finds a match, it establishes the conversation.

#define CTOPICS 5

HSZ hsz1;                  /* string handle passed by DDEML  */
HSZ ahszTopics[CTOPICS];   /* array of supported topics      */
int i;                     /* loop counter                   */

.
. /* Use switch statement to examine transaction types. */
.

case XTYP_CONNECT:
    for (i = 0; i < CTOPICS; i++) {
        if (hsz1 == ahszTopics[i])
            return TRUE;   /* establish a conversation       */
    }

    return FALSE; /* topic not supported; deny conversation  */

.
. /* Process other transaction types. */
.

If the server returns TRUE in response to the XTYP_CONNECT transaction, the DDEML sends an XTYP_CONNECT_CONFIRM transaction to the server's DDE callback function. The server can obtain the handle for the conversation by processing this transaction.

A client can establish a wildcard conversation by specifying NULL for the service-name string handle, the topic-name string handle, or both in a call to the DdeConnect function. When at least one of the string handles is NULL, the DDEML sends the XTYP_WILDCONNECT transaction to the callback functions of all DDE applications (except those that filter the XTYP_WILDCONNECT transaction). Each server application should respond by returning a data handle that identifies a null-terminated array of HSZPAIR structures. If the server application has not called the DdeNameService function to register its service names and filtering is on, the server does not receive XTYP_WILDCONNECT transactions. For more information about data handles, see Section 5.7, “Data Management.”

The array should contain one structure for each service/topic name pair that matches the pair specified by the client. The DDEML selects one of the pairs to establish a conversation and returns to the client a handle that identifies the conversation. The DDEML sends the XTYP_CONNECT_CONFIRM transaction to the server (unless the server filters this transaction). The following example shows a typical server response to the XTYP_WILDCONNECT transaction:

#define CTOPICS 2

UINT type;
UINT fmt;
HSZPAIR ahp[(CTOPICS + 1)];
HSZ ahszTopicList[CTOPICS];
HSZ hszServ, hszTopic;
WORD i, j;

if (type == XTYP_WILDCONNECT) {

     /*
      * Scan the topic list, and create array of HSZPAIR
      * structures.
      */

    j = 0;
    for (i = 0; i < CTOPICS; i++) {
        if (hszTopic == (HSZ) NULL ||
                hszTopic == ahszTopicList[i]) {
            ahp[j].hszSvc = hszServ;
            ahp[j++].hszTopic = ahszTopicList[i];
        }
    }

    /*
     * End the list with an HSZPAIR structure that contains NULL
     * string handles as its members.
     */

    ahp[j].hszSvc = NULL;
    ahp[j++].hszTopic = NULL;

    /*
     * Return a handle to a global memory object containing the
     * HSZPAIR structures.
     */

    return DdeCreateDataHandle(
        idInst,          /* instance identifier     */
        &ahp,            /* points to HSZPAIR array */
        sizeof(HSZ) * j, /* length of the array     */
        0,               /* start at the beginning  */
        NULL,            /* no item-name string     */
        fmt,             /* return the same format  */
        0);              /* let the system own it   */
}

Either the client or the server can terminate a conversation at any time by calling the DdeDisconnect function. This causes the callback function of the partner in the conversation to receive the XTYP_DISCONNECT transaction (unless the partner specified the CBF_SKIP_DISCONNECTS filter flag). Typically, an application responds to the XTYP_DISCONNECT transaction by using the DdeQueryConvInfo function to obtain information about the conversation that terminated. After the callback function returns from processing the XTYP_DISCONNECT transaction, the conversation handle is no longer valid.

A client application that receives an XTYP_DISCONNECT transaction in its DDE callback function can attempt to reestablish the conversation by calling the DdeReconnect function. The client must call DdeReconnect from within its DDE callback function.