22.4.5 Terminating a Conversation

Either the client or the server can issue a WM_DDE_TERMINATE message to terminate a conversation at any time. Similarly, both the client and server applications should be prepared to receive this message at any time. An application must terminate all of its conversations before shutting down.

The application terminating the conversation sends a WM_DDE_TERMINATE message, as follows:

PostMessage(hwndServerDDE, WM_DDE_TERMINATE, hwndClientDDE, 0L);

This informs the other application that the sending application will send no further messages and that the recipient can close its window. The recipient is expected in all cases to send a WM_DDE_TERMINATE message promptly in response. It is not permissible to send a negative, busy, or positive WM_DDE_ACK message.

After an application has sent the WM_DDE_TERMINATE message to the partner in a DDE conversation, it must not respond to any messages from that partner, since the partner might already have destroyed the window to which the response would be sent.

When an application is about to terminate, it should end all active DDE conversations before completing processing of the WM_DESTROY message. Your application should include timeout logic to allow for the possibility that one of its DDE partners is unable to respond to the WM_DDE_TERMINATE message. The following example shows how a server application terminates all DDE conversations:

void TerminateConversations(hwndServerDDE)
HWND  hwndServerDDE;
{
    HWND  hwndClientDDE;
    LONG  lTimeOut;
    MSG   msg;

    /* Terminate each active conversation.*/

    hwndClientDDE = NULL;
    while (hwndClientDDE = GetNextLink(hwndClientDDE)) {
        SendTerminate(hwndServerDDE, hwndClientDDE);
    }

    /* Wait for all conversations to terminate; wait for timeout. */

    lTimeOut = GetTickCount() + (LONG) nAckTimeOut;
    while (PeekMessage(&msg, NULL, WM_DDE_FIRST, WM_DDE_LAST,
            PM_REMOVE)) {
        DispatchMessage (&msg);
        if (msg.message == WM_DDE_TERMINATE) {
            if (!AtLeastOneLinkActive())
            break;
        }
        if (GetTickCount() > lTimeOut)
            break;
    }
    return;
}