Поделиться через


Управление беседами

Беседа между клиентом и сервером всегда устанавливается по запросу клиента. При установке беседы каждый партнер получает дескриптор, определяющий беседу. Партнеры используют этот дескриптор в других функциях библиотеки управления динамическими данными (DDEML) для отправки транзакций и управления беседой. Клиент может запросить беседу с одним сервером или запросить несколько бесед с одним или несколькими серверами.

В следующих разделах описывается, как приложение устанавливает новые беседы и получает сведения о существующих беседах.

Одиночные беседы

Клиентское приложение запрашивает одну беседу с сервером, вызывая функцию Dde Подключение и указывая дескриптор строки, определяющие строки, содержащие имя службы серверного приложения и имя раздела для беседы. DDEML отвечает, отправив транзакцию XTYP_CONNECT в функцию обратного вызова Dynamic Data Exchange (DDE) каждого серверного приложения, которое либо зарегистрировало имя службы, соответствующее одному из указанных в Dde Подключение или отключив фильтрацию имени службы путем вызова DdeNameService. Сервер также может фильтровать XTYP_CONNECT транзакции, указав флаг фильтра CBF_FAIL_CONNECTIONS в функции DdeInitialize . Во время транзакции XTYP_CONNECT DDEML передает имя службы и имя раздела серверу. Сервер должен проверять имена и возвращать значение TRUE , если он поддерживает пару имен службы и раздела или FALSE , если он не указан.

Если сервер не отвечает положительно на запрос клиента на подключение, клиент получает значение NULL от Dde Подключение и не устанавливается беседа. Если сервер возвращает значение TRUE, устанавливается беседа, а клиент получает дескриптор беседы — значение DWORD , определяющее беседу. Клиент использует дескриптор в последующих вызовах DDEML для получения данных с сервера. Сервер получает транзакцию XTYP_CONNECT_CONFIRM (если сервер не указал флаг фильтра CBF_SKIP_CONNECT_CONFIRMS). Эта транзакция передает дескриптор беседы серверу.

В следующем примере запрашивается беседа в системном разделе с сервером, который распознает имя службы MyServer. Ранее созданные дескрипторы строковых дескрипторов hszServName и hszSysTopic .

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; 
} 

В предыдущем примере Dde Подключение вызывает функцию обратного вызова DDE приложения MyServer для получения транзакции XTYP_CONNECT.

В следующем примере сервер отвечает на XTYP_CONNECT транзакцию, сравнивая строку имени раздела, обрабатывая DDEML, переданную серверу с каждым элементом в массиве строк имени раздела, обрабатывает сервер. Если сервер находит совпадение, он устанавливает беседу.

#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. 

Если сервер возвращает значение TRUE в ответ на транзакцию XTYP_CONNECT, DDEML отправляет XTYP_CONNECT_CONFIRM транзакцию в функцию обратного вызова DDE сервера. Сервер может получить дескриптор беседы, обработав эту транзакцию.

Клиент может установить дикую карта беседу, указав ЗНАЧЕНИЕ NULL для дескриптора строки имени службы, дескриптора строки имени раздела или обоих в вызове Dde Подключение. Если хотя бы один из дескрипторов строки имеет значение NULL, DDEML отправляет транзакцию XTYP_WILDCONNECT функции обратного вызова всех приложений DDE (за исключением тех, которые фильтруют транзакцию XTYP_WILDCONNECT). Каждое серверное приложение должно реагировать, возвращая дескриптор данных, определяющий массив структур HSZPAIR , завершающих значение NULL. Если серверное приложение не вызывает DdeNameService для регистрации имен служб и если фильтрация включена, сервер не получает XTYP_WILDCONNECT транзакций. Дополнительные сведения об дескрипторах данных см. в Управление данными.

Массив должен содержать одну структуру для каждой пары имени службы и имени раздела, которая соответствует паре, указанной клиентом. DDEML выбирает одну из пар, чтобы установить беседу и вернуть клиенту дескриптор, который идентифицирует беседу. DDEML отправляет транзакцию XTYP_CONNECT_CONFIRM на сервер (если сервер не фильтрует эту транзакцию). В следующем примере показан типичный ответ сервера на транзакцию 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 
} 

Клиент или сервер в любое время могут завершить беседу, вызвав функцию DdeDisconnect. Эта функция приводит к тому, что функция обратного вызова партнера в беседе получает транзакцию XTYP_DISCONNECT (если партнер не указал флаг фильтра CBF_SKIP_DISCONNECTS). Как правило, приложение реагирует на транзакцию XTYP_DISCONNECT с помощью функции DdeQueryConvInfo для получения сведений о беседе, завершившемся. После возврата функции обратного вызова из обработки транзакции XTYP_DISCONNECT дескриптор беседы больше недействителен.

Клиентское приложение, получающее транзакцию XTYP_DISCONNECT в функции обратного вызова DDE, может попытаться восстановить беседу, вызвав функцию DdeReconnect. Клиент должен вызвать DdeReconnect из функции обратного вызова DDE.

Несколько бесед

Клиентское приложение может использовать функцию Dde Подключение List, чтобы определить, доступны ли в системе какие-либо серверы. Клиент указывает имя службы и имя раздела при вызове Dde Подключение List, что приводит к передаче DDEML транзакции XTYP_WILDCONNECT функции обратного вызова DDE всех серверов, которые соответствуют имени службы (за исключением тех, которые фильтруют транзакцию). Функция обратного вызова сервера должна возвращать дескриптор данных, определяющий массив структур HSZPAIR , завершающий значение NULL. Массив должен содержать одну структуру для каждой пары имени службы и имени раздела, которая соответствует паре, указанной клиентом. DDEML устанавливает беседу для каждой структуры HSZPAIR , заполненной сервером, и возвращает дескриптор списка бесед клиенту. Сервер получает дескриптор беседы через транзакцию XTYP_CONNECT (если сервер не фильтрует эту транзакцию).

Клиент может указать ЗНАЧЕНИЕ NULL для имени службы, имени раздела или обоих при вызове Dde Подключение List. Если имя службы равно NULL, все серверы в системе, поддерживающие указанное имя раздела, отвечают. Беседа устанавливается с каждым сервером ответа, включая несколько экземпляров одного сервера. Если имя раздела равно NULL, беседа устанавливается на каждом разделе, распознаваемом каждым сервером, который соответствует имени службы.

Клиент может использовать функции DdeQueryNextServer и DdeQueryConvInfo для идентификации серверов, реагирующих на Dde Подключение List. DdeQueryNextServer возвращает следующий дескриптор беседы в списке бесед, а DdeQueryConvInfo заполняет структуру CONVINFO сведениями о беседе. Клиент может сохранить дескриптора беседы, необходимые ему и не карта остальные из списка бесед.

В следующем примере используется Dde Подключение List для создания бесед со всеми серверами, поддерживающими системный раздел, а затем используются функции DdeQueryNextServer и DdeQueryConvInfo для получения дескрипторов строк имени службы серверов и хранения их в буфере.

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

Приложение может завершить отдельную беседу в списке бесед, вызвав функцию DdeDisconnect. Приложение может завершить все беседы в списке бесед, вызвав функцию DdeDisconnectList. Обе функции вызывают отправку XTYP_DISCONNECT транзакций DDEML в функцию обратного вызова DDE каждого партнера. DdeDisconnectList отправляет транзакцию XTYP_DISCONNECT для каждого дескриптора беседы в списке.

Клиент может получить список дескрипторов бесед в списке бесед, передав существующий дескриптор списка бесед в Dde Подключение List. Процесс перечисления удаляет дескриптор завершенных бесед из списка и неуплицированные беседы, которые соответствуют указанному имени службы и имени раздела.

Если Dde Подключение List указывает существующий дескриптор списка бесед, функция создает новый список бесед, содержащий дескриптор любых новых бесед и дескриптор из существующего списка.

Если существуют повторяющиеся беседы, Dde Подключение List пытается предотвратить повторяющиеся дескрипторы бесед в списке бесед. Повторяющийся диалог — это вторая беседа с тем же сервером с тем же именем службы и именем раздела. Два таких диалога будут иметь разные дескрипторы, но они будут определять один и тот же разговор.