대화 관리

클라이언트와 서버 간의 대화는 항상 클라이언트의 요청에 따라 설정됩니다. 대화가 설정되면 각 파트너는 대화를 식별하는 핸들을 받습니다. 파트너는 다른 DDEML(동적 데이터 교환 관리 라이브러리) 함수에서 이 핸들을 사용하여 트랜잭션을 보내고 대화를 관리합니다. 클라이언트는 단일 서버와의 대화를 요청하거나 하나 이상의 서버와 여러 대화를 요청할 수 있습니다.

다음 topics 애플리케이션이 새 대화를 설정하고 기존 대화에 대한 정보를 가져오는 방법을 설명합니다.

단일 대화

클라이언트 애플리케이션은 DdeConnect 함수를 호출하고 서버 애플리케이션의 서비스 이름과 대화의 토픽 이름을 포함하는 문자열을 식별하는 문자열 핸들을 지정하여 서버와의 단일 대화를 요청합니다. DDEML은 DdeConnect에 지정된 서비스 이름과 일치하는 서비스 이름을 등록했거나 DdeNameService를 호출하여 서비스 이름 필터링을 해제한 각 서버 애플리케이션의 DDE(동적 데이터 교환) 콜백 함수로 XTYP_CONNECT 트랜잭션을 전송하여 응답합니다. 서버는 DdeInitialize 함수에서 CBF_FAIL_CONNECTIONS 필터 플래그를 지정하여 XTYP_CONNECT 트랜잭션을 필터링할 수도 있습니다. XTYP_CONNECT 트랜잭션 중에 DDEML은 서비스 이름과 토픽 이름을 서버에 전달합니다. 서버는 이름을 검사하고 서비스 이름 및 토픽 이름 쌍을 지원하는 경우 TRUE 를 반환하거나 그렇지 않은 경우 FALSE 를 반환해야 합니다.

클라이언트의 연결 요청에 긍정적으로 응답하는 서버가 없으면 클라이언트는 DdeConnect에서 NULL을 수신하고 대화가 설정되지 않습니다. 서버가 TRUE를 반환하면 대화가 설정되고 클라이언트는 대화를 식별하는 DWORD 값인 대화 핸들을 받습니다. 클라이언트는 후속 DDEML 호출에서 핸들을 사용하여 서버에서 데이터를 가져옵니다. 서버가 CBF_SKIP_CONNECT_CONFIRMS 필터 플래그를 지정하지 않는 한 서버는 XTYP_CONNECT_CONFIRM 트랜잭션을 받습니다. 이 트랜잭션은 대화 핸들을 서버에 전달합니다.

다음 예제에서는 서비스 이름 MyServer를 인식하는 서버를 사용하여 시스템 토픽에 대한 대화를 요청합니다. hszServNamehszSysTopic 매개 변수는 이전에 만든 문자열 핸들입니다.

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

앞의 예제에서 DdeConnect 는 MyServer 애플리케이션의 DDE 콜백 함수가 XTYP_CONNECT 트랜잭션을 받도록 합니다.

다음 예제에서 서버는 서버가 지원하는 토픽 이름 문자열의 배열에 있는 각 요소와 서버에 전달된 DDEML 핸들 토픽 이름 문자열 핸들을 비교하여 XTYP_CONNECT 트랜잭션에 응답합니다. 서버에서 일치하는 항목을 찾으면 대화가 설정됩니다.

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

서버가 XTYP_CONNECT 트랜잭션에 대한 응답으로 TRUE를 반환하는 경우 DDEML은 XTYP_CONNECT_CONFIRM 트랜잭션을 서버의 DDE 콜백 함수로 보냅니다. 서버는 이 트랜잭션을 처리하여 대화에 대한 핸들을 가져올 수 있습니다.

클라이언트는 DdeConnect 호출에서 서비스 이름 문자열 핸들, 토픽 이름 문자열 핸들 또는 둘 다에 대해 NULL을 지정하여 와일드카드 대화를 설정할 수 있습니다. 문자열 핸들 중 하나 이상이 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 필터 플래그를 지정하지 않은 경우). 일반적으로 애플리케이션은 DdeQueryConvInfo 함수를 사용하여 종료된 대화에 대한 정보를 얻어 XTYP_DISCONNECT 트랜잭션에 응답합니다. 콜백 함수가 XTYP_DISCONNECT 트랜잭션 처리에서 반환되면 대화 핸들이 더 이상 유효하지 않습니다.

DDE 콜백 함수에서 XTYP_DISCONNECT 트랜잭션을 수신하는 클라이언트 애플리케이션은 DdeReconnect 함수를 호출하여 대화를 다시 설정하려고 시도할 수 있습니다. 클라이언트는 DDE 콜백 함수 내에서 DdeReconnect 를 호출해야 합니다.

여러 대화

클라이언트 애플리케이션은 DdeConnectList 함수를 사용하여 시스템에서 관심 있는 서버를 사용할 수 있는지 여부를 확인할 수 있습니다. 클라이언트는 DdeConnectList를 호출할 때 서비스 이름 및 토픽 이름을 지정하여 DDEML이 XTYP_WILDCONNECT 트랜잭션을 서비스 이름과 일치하는 모든 서버의 DDE 콜백 함수로 브로드캐스트합니다(트랜잭션을 필터링하는 서버 제외). 서버의 콜백 함수는 HSZPAIR 구조체의 null로 종료된 배열을 식별하는 데이터 핸들을 반환해야 합니다. 배열에는 클라이언트에서 지정한 쌍과 일치하는 각 서비스 이름 및 토픽 이름 쌍에 대해 하나의 구조가 포함되어야 합니다. DDEML은 서버로 채워진 각 HSZPAIR 구조체에 대한 대화를 설정하고 대화 목록 핸들을 클라이언트에 반환합니다. 서버가 이 트랜잭션을 필터링하지 않는 한 서버는 XTYP_CONNECT 트랜잭션을 통해 대화 핸들을 받습니다.

클라이언트는 DdeConnectList를 호출할 때 서비스 이름, 토픽 이름 또는 둘 다에 대해 NULL을 지정할 수 있습니다. 서비스 이름이 NULL이면 지정된 토픽 이름을 지원하는 시스템의 모든 서버가 응답합니다. 동일한 서버의 여러 인스턴스를 포함하여 각 응답 서버와 대화가 설정됩니다. 토픽 이름이 NULL인 경우 서비스 이름과 일치하는 각 서버에서 인식되는 각 토픽에 대해 대화가 설정됩니다.

클라이언트는 DdeQueryNextServerDdeQueryConvInfo 함수를 사용하여 DdeConnectList에 응답하는 서버를 식별할 수 있습니다. DdeQueryNextServer 는 대화 목록에서 다음 대화 핸들을 반환하고 DdeQueryConvInfo 는 대화에 대한 정보로 CONVINFO 구조를 채웁니다. 클라이언트는 필요한 대화 핸들을 유지하고 나머지를 대화 목록에서 삭제할 수 있습니다.

다음 예제에서는 DdeConnectList 를 사용하여 시스템 토픽을 지원하는 모든 서버와 대화를 설정한 다음 DdeQueryNextServerDdeQueryConvInfo 함수를 사용하여 서버의 서비스 이름 문자열 핸들을 가져오고 버퍼에 저장합니다.

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 함수를 호출하여 대화 목록의 모든 대화를 종료할 수 있습니다. 두 함수 모두 DDEML이 각 파트너의 DDE 콜백 함수에 XTYP_DISCONNECT 트랜잭션을 보내도록 합니다. DdeDisconnectList 는 목록의 각 대화 핸들에 대해 XTYP_DISCONNECT 트랜잭션을 보냅니다.

클라이언트는 DdeConnectList에 기존 대화 목록 핸들을 전달하여 대화 목록의 대화 핸들 목록을 검색할 수 있습니다. 열거형 프로세스는 목록에서 종료된 대화의 핸들을 제거하고 지정된 서비스 이름 및 토픽 이름에 맞는 중복 제거되지 않은 대화가 추가됩니다.

DdeConnectList가 기존 대화 목록 핸들을 지정하는 경우 함수는 새 대화의 핸들과 기존 목록의 핸들을 포함하는 새 대화 목록을 만듭니다.

중복 대화가 있는 경우 DdeConnectList 는 대화 목록에서 중복 대화 핸들을 방지하려고 시도합니다. 중복 대화는 동일한 서비스 이름 및 토픽 이름에 동일한 서버가 있는 두 번째 대화입니다. 이러한 두 대화에는 다른 핸들이 있지만 동일한 대화를 식별합니다.