Udostępnij przez


Zarządzanie konwersacjami

Konwersacja między klientem a serwerem jest zawsze ustanawiana na żądanie klienta. Po nawiązaniu konwersacji każdy partner otrzymuje dojście identyfikujące konwersację. Partnerzy używają tego uchwytu w innych funkcjach dynamicznej biblioteki zarządzania exchange danych (DDEML) do wysyłania transakcji i zarządzania konwersacją. Klient może zażądać konwersacji z jednym serwerem lub zażądać wielu konwersacji z co najmniej jednym serwerem.

W poniższych tematach opisano sposób, w jaki aplikacja ustanawia nowe konwersacje i pobiera informacje o istniejących konwersacjach.

Pojedyncze konwersacje

Aplikacja kliencka żąda jednej konwersacji z serwerem przez wywołanie funkcji DdeConnect i określenie dojść ciągów identyfikujących ciągi zawierające nazwę usługi aplikacji serwera i nazwę tematu konwersacji. DDEML odpowiada, wysyłając transakcję XTYP_CONNECT do funkcji wywołania zwrotnego dynamicznej wymiany danych (DDE) każdej aplikacji serwera, która zarejestrowała nazwę usługi zgodną z nazwą określoną w DdeConnect lub wyłączyła filtrowanie nazw usług przez wywołanie DdeNameService. Serwer może również filtrować transakcje XTYP_CONNECT, określając flagę filtru CBF_FAIL_CONNECTIONS w funkcji DdeInitialize. Podczas transakcji XTYP_CONNECT DDEML przekazuje nazwę usługi i nazwę tematu do serwera. Serwer musi sprawdzić nazwy i zwrócić true, jeśli obsługuje parę nazw usługi i nazwy tematu lub FALSE, jeśli nie.

Jeśli żaden serwer nie odpowie pozytywnie na żądanie klienta w celu nawiązania połączenia, klient otrzyma NULL z DdeConnect i nie zostanie nawiązana żadna konwersacja. Jeśli serwer zwraca true, zostanie nawiązana konwersacja, a klient otrzyma dojście do konwersacji — wartość DWORD identyfikującą konwersację. Klient używa dojścia w kolejnych wywołaniach DDEML w celu uzyskania danych z serwera. Serwer odbiera transakcję XTYP_CONNECT_CONFIRM (chyba że serwer określił flagę filtru CBF_SKIP_CONNECT_CONFIRMS). Ta transakcja przekazuje do serwera obsługę konwersacji.

Poniższy przykład żąda konwersacji w temacie System z serwerem, który rozpoznaje nazwę usługi MyServer. Parametry hszServName i hszSysTopic są wcześniej tworzone dojścia ciągów.

HCONV hConv;         // conversation handle 
HWND hwndParent;     // parent window handle 
HSZ hszServName;     // service name string handle 
HSZ hszSysTopic;     // System topic string handle 
 
hConv = DdeConnect( 
    idInst,               // instance identifier 
    hszServName,          // service name string handle 
    hszSysTopic,          // System topic string handle 
    (PCONVCONTEXT) NULL); // use default context 
 
if (hConv == NULL) 
{ 
    MessageBox(hwndParent, "MyServer is unavailable.", 
        (LPSTR) NULL, MB_OK); 
    return FALSE; 
} 

W poprzednim przykładzie DdeConnect powoduje, że funkcja wywołania zwrotnego DDE aplikacji MyServer odbiera transakcję XTYP_CONNECT.

W poniższym przykładzie serwer odpowiada na transakcję XTYP_CONNECT, porównując ciąg nazwy tematu do obsługi DDEML przekazany do serwera z każdym elementem w tablicy ciągów nazw tematu obsługuje serwer obsługuje. Jeśli serwer znajdzie dopasowanie, ustanawia konwersację.

#define CTOPICS 5 
 
HSZ hsz1;                  // string handle passed by DDEML 
HSZ ahszTopics[CTOPICS];   // array of supported topics 
int i;                     // loop counter 
 
// Use a switch statement to examine transaction types. 
// Here is the connect case.
 
    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. 

Jeśli serwer zwraca true w odpowiedzi na transakcję XTYP_CONNECT, DDEML wysyła transakcję XTYP_CONNECT_CONFIRM do funkcji wywołania zwrotnego DDE serwera. Serwer może uzyskać dojście do konwersacji, przetwarzając tę transakcję.

Klient może ustanowić konwersację z symbolami wieloznacznymi, określając null dla dojścia ciągu nazwy usługi, dojścia ciągu nazwy tematu lub w wywołaniu DdeConnect. Jeśli co najmniej jeden z dojść ciągu jest null, DDEML wysyła transakcję XTYP_WILDCONNECT do funkcji wywołania zwrotnego wszystkich aplikacji DDE (z wyjątkiem tych, które filtrują transakcję XTYP_WILDCONNECT). Każda aplikacja serwera powinna odpowiedzieć, zwracając uchwyt danych, który identyfikuje tablicę HSZPAIR o wartości null. Jeśli aplikacja serwera nie wywoła DdeNameService do zarejestrowania nazw usług i jeśli filtrowanie jest włączone, serwer nie odbiera XTYP_WILDCONNECT transakcji. Aby uzyskać więcej informacji na temat dojść do danych, zobacz Data Management.

Tablica musi zawierać jedną strukturę dla każdej pary nazwy usługi i nazwy tematu zgodnej z parą określoną przez klienta. DDEML wybiera jedną z par, aby ustanowić konwersację i powróci do klienta uchwyt, który identyfikuje konwersację. DDEML wysyła transakcję XTYP_CONNECT_CONFIRM do serwera (chyba że serwer filtruje tę transakcję). W poniższym przykładzie przedstawiono typową odpowiedź serwera na transakcję XTYP_WILDCONNECT.

#define CTOPICS 2 
 
UINT uType; 
HSZPAIR ahszp[(CTOPICS + 1)]; 
HSZ ahszTopicList[CTOPICS]; 
HSZ hszServ, hszTopic; 
WORD i, j; 
 
if (uType == XTYP_WILDCONNECT) 
{ 
    // Scan the topic list and create an array of HSZPAIR structures. 
 
    j = 0; 
    for (i = 0; i < CTOPICS; i++) 
    { 
        if (hszTopic == (HSZ) NULL || 
                hszTopic == ahszTopicList[i]) 
        { 
            ahszp[j].hszSvc = hszServ; 
            ahszp[j++].hszTopic = ahszTopicList[i]; 
        } 
    } 
 
    // End the list with an HSZPAIR structure that contains NULL 
    // string handles as its members. 
 
    ahszp[j].hszSvc = NULL; 
    ahszp[j++].hszTopic = NULL; 
 
    // Return a handle to a global memory object containing the 
    // HSZPAIR structures. 
 
    return DdeCreateDataHandle( 
        idInst,          // instance identifier 
        (LPBYTE) &ahszp, // pointer to HSZPAIR array 
        sizeof(HSZ) * j, // length of the array 
        0,               // start at the beginning 
        (HSZ) NULL,      // no item name string 
        0,               // return the same format 
        0);              // let the system own it 
} 

Klient lub serwer może zakończyć konwersację w dowolnym momencie, wywołując funkcję DdeDisconnect. Ta funkcja powoduje, że funkcja wywołania zwrotnego partnera w konwersacji odbiera transakcję XTYP_DISCONNECT (chyba że partner określił flagę filtru CBF_SKIP_DISCONNECTS). Zazwyczaj aplikacja reaguje na transakcję XTYP_DISCONNECT przy użyciu funkcji DdeQueryConvInfo w celu uzyskania informacji o konwersacji zakończonej. Po powrocie funkcji wywołania zwrotnego z przetwarzania transakcji XTYP_DISCONNECT obsługa konwersacji nie jest już prawidłowa.

Aplikacja kliencka, która odbiera transakcję XTYP_DISCONNECT w funkcji wywołania zwrotnego DDE, może spróbować ponownie opublikować konwersację, wywołując funkcję DdeReconnect. Klient musi wywołać DdeReconnect z poziomu funkcji wywołania zwrotnego DDE.

Wiele konwersacji

Aplikacja kliencka może użyć funkcji DdeConnectList, aby określić, czy jakiekolwiek interesujące serwery są dostępne w systemie. Klient określa nazwę usługi i nazwę tematu podczas wywoływania DdeConnectList, powodując, że DDEML emitować transakcję XTYP_WILDCONNECT do funkcji wywołania zwrotnego DDE wszystkich serwerów, które pasują do nazwy usługi (z wyjątkiem tych, które filtrują transakcję). Funkcja wywołania zwrotnego serwera powinna zwrócić uchwyt danych, który identyfikuje tablicę HSZPAIR o wartości null. Tablica powinna zawierać jedną strukturę dla każdej nazwy usługi i pary nazw tematów, która jest zgodna z parą określoną przez klienta. DDEML ustanawia konwersację dla każdej HSZPAIR struktury wypełnionej przez serwer i zwraca do klienta obsługę listy konwersacji. Serwer odbiera obsługę konwersacji za pomocą transakcji XTYP_CONNECT (chyba że serwer filtruje tę transakcję).

Klient może określić null dla nazwy usługi, nazwy tematu lub obu, gdy wywołuje DdeConnectList. Jeśli nazwa usługi ma wartość null, wszystkie serwery w systemie, które obsługują określoną nazwę tematu, odpowiadają. Konwersacja jest ustanawiana z każdym serwerem odpowiadającym, w tym z wieloma wystąpieniami tego samego serwera. Jeśli nazwa tematu jest null, konwersacja jest ustanawiana w każdym temacie rozpoznawanym przez każdy serwer, który jest zgodny z nazwą usługi.

Klient może użyć funkcji DdeQueryNextServer i DdeQueryConvInfo, aby zidentyfikować serwery, które reagują na DdeConnectList. DdeQueryNextServer zwraca następny uchwyt konwersacji na liście konwersacji, a DdeQueryConvInfo wypełnia strukturęCONVINFOz informacjami o konwersacji. Klient może zachować obsługę konwersacji, których potrzebuje, i odrzucić resztę z listy konwersacji.

W poniższym przykładzie użyto DdeConnectList do nawiązywania rozmów ze wszystkimi serwerami obsługującymi temat System, a następnie używa DdeQueryNextServer i funkcji DdeQueryConvInfo w celu uzyskania obsługi ciągów nazw usług serwerów i przechowywania ich w buforze.

HCONVLIST hconvList; // conversation list 
DWORD idInst;        // instance identifier 
HSZ hszSystem;       // System topic 
HCONV hconv = NULL;  // conversation handle 
CONVINFO ci;         // holds conversation data 
UINT cConv = 0;      // count of conv. handles 
HSZ *pHsz, *aHsz;    // point to string handles 
 
// Connect to all servers that support the System topic. 
 
hconvList = DdeConnectList(idInst, NULL, hszSystem, NULL, NULL); 
 
// Count the number of handles in the conversation list. 
 
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL) 
    cConv++; 
 
// Allocate a buffer for the string handles. 
 
hconv = NULL; 
aHsz = (HSZ *) LocalAlloc(LMEM_FIXED, cConv * sizeof(HSZ)); 
 
// Copy the string handles to the buffer. 
 
pHsz = aHsz; 
while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL) 
{ 
    DdeQueryConvInfo(hconv, QID_SYNC, (PCONVINFO) &ci); 
    DdeKeepStringHandle(idInst, ci.hszSvcPartner); 
    *pHsz++ = ci.hszSvcPartner; 
} 
 
// Use the handles; converse with the servers. 
 
// Free the memory and terminate the conversations. 
 
LocalFree((HANDLE) aHsz); 
DdeDisconnectList(hconvList); 

Aplikacja może zakończyć indywidualną konwersację na liście konwersacji, wywołując funkcjęDdeDisconnect. Aplikacja może zakończyć wszystkie konwersacje na liście konwersacji, wywołując funkcję DdeDisconnectList. Obie funkcje powodują, że DDEML wysyła transakcje XTYP_DISCONNECT do funkcji wywołania zwrotnego DDE każdego partnera. DdeDisconnectList wysyła transakcję XTYP_DISCONNECT dla każdego dojścia konwersacji na liście.

Klient może pobrać listę dojść konwersacji na liście konwersacji, przekazując istniejący uchwyt listy konwersacji, aby DdeConnectList. Proces wyliczania usuwa dojścia zakończonych konwersacji z listy, a nieduplikowane konwersacje pasujące do określonej nazwy usługi i nazwy tematu są dodawane.

Jeśli DdeConnectList określa istniejący uchwyt listy konwersacji, funkcja tworzy nową listę konwersacji zawierającą dojścia wszelkich nowych konwersacji i dojść z istniejącej listy.

Jeśli istnieją zduplikowane konwersacje, DdeConnectList próbuje zapobiec zduplikowaniu dojść konwersacji na liście konwersacji. Zduplikowana konwersacja to druga konwersacja z tym samym serwerem o tej samej nazwie usługi i nazwie tematu. Dwie takie konwersacje miałyby różne uchwyty, ale zidentyfikowałyby tę samą konwersację.