TN065: OLE 자동화 서버에 이중 인터페이스 지원

이 노트에서는 MFC 기반 OLE 자동화 서버 응용 프로그램에 이중 인터페이스 지원을 추가 하는 방법을 설명 합니다. ACDUAL 샘플에서는 이중 인터페이스 지원, 그리고이 노트에 예제 코드는 ACDUAL에서 가져온. 등이 노트에 설명 된 매크로 DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , 그리고 IMPLEMENT_DUAL_ERRORINFO ACDUAL 샘플의 일부 이며 MFCDUAL에서 찾을 수 있습니다.H。

듀얼 인터페이스

OLE 자동화를 사용 하면 IDispatch 인터페이스, VTBL 인터페이스 또는 (둘 다를 포함) 하는 이중 인터페이스를 구현할 수 있습니다, 비록 모든 노출 된 OLE 자동화 개체에 대해 이중 인터페이스를 구현 하는 것이 좋습니다. 이중 인터페이스는 IDispatch에 비해 상당한 이점을-전용 또는 VTBL 전용 인터페이스:

CCmdTarget 기반 클래스에 이중 인터페이스 지원을 추가

이중 인터페이스는 정말 그냥 IDispatch에서 파생 된 사용자 지정 인터페이스입니다. CCmdTarget에 이중 인터페이스 지원을 구현 하는 가장 간단한 방법은-기반된 클래스는 정상적인 디스패치 인터페이스 MFC Classwizard를 사용 하 여 클래스에 다음 나중에 사용자 지정 인터페이스를 추가할 첫 번째 구현입니다. 대부분의 경우,에 사용자 지정 인터페이스 구현에서 단순히 MFC IDispatch 구현을 위임 됩니다.

첫째, 개체에 대해 이중 인터페이스를 정의 하 여 서버에 대 한 ODL 파일을 수정 합니다. 이중 인터페이스를 정의 하려면 대신 인터페이스 문을 사용 합니다 DISPINTERFACE Visual c + + 마법사 생성 하는 문. 기존의 제거 하는 대신 DISPINTERFACE 문, 새로운 인터페이스 문을 추가 합니다. 유지는 DISPINTERFACE 양식, Classwizard를 사용 하 여 개체, 속성 및 메서드 추가를 계속할 수 있습니다 하지만 인터페이스 문을 해당 속성 및 메서드를 추가 해야 합니다。

이중 인터페이스에 대 한 인터페이스 문을 OLEAUTOMATION 및 듀얼 특성을가지고 있어야 합니다 그리고 인터페이스는 IDispatch에서 파생 되어야 합니다. 사용할 수 있는 듀얼 인터페이스의 IID 를 만들려고 GUIDGEN 샘플

[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), / / IID_IDualAClick
 nbsp; oleautomation,
 ? 듀얼
]
IDualAClick 인터페이스: IDispatch
  {
  }(&N)

일단 당신이 장소에서 인터페이스 문을 메서드 및 속성에 대 한 항목 추가 시작 합니다. 이중 인터페이스에 대 한 메서드 및 속성 접근자 함수 듀얼 인터페이스에서 HRESULT 를 반환 하 고 특성 매개 변수로 반환 값을 전달할 매개 변수 목록을 다시 정렬 해야 [retval,out] . 속성 모두 읽기를 추가 하려면 필요 것 이다 ( propget ) 및 쓰기 ( propput ) 동일한 id 가진 함수에 액세스 합니다. 예를 들어:

[propput, id(1)] HRESULT (텍스트 [] BSTR newText);
[propget, id(1)] HRESULT 텍스트 ([out, retval] BSTR * retval)

속성과 메서드를 정의한 후에 coclass 문에 인터페이스 문에 대 한 참조를 추가 해야 합니다. 예를 들어:

[uuid(4B115281-32F0-11cf-AC85-444553540000)]
coclass 문서
{
 nbsp; dispinterface IAClick;
 ? [기본값] 인터페이스 IDualAClick;
}(&N)

ODL 파일을 업데이트 하는 일단 개체 클래스에서 이중 인터페이스의 구현 클래스를 정의 하 고 MFC의 QueryInterface 메커니즘에 해당 항목을 확인 하려면 MFC의 인터페이스 맵 메커니즘을 사용 합니다. 한 항목에 필요 합니다 INTERFACE_PART ODL, 인터페이스 문에서 각 항목을 더하기를 디스패치 인터페이스에 대 한 항목에 대 한 블록. Propput 특성을 가진 각 ODL 항목 라는 함수가 필요 put_propertyname . Propget 특성을 가진 각 항목 필요 라는 함수get_propertyname。

이중 인터페이스의 구현 클래스를 정의 하려면 추가 DUAL_INTERFACE_PART 개체 클래스 정의에 블록. 예를 들어:

BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)
  STDMETHOD(put_text) (THIS_ BSTR newText);
  STDMETHOD(get_text) (THIS_ BSTR 멀리 * retval);
  STDMETHOD(put_x) (THIS_ 짧은 newX);
  STDMETHOD(get_x) (THIS_ 짧은 멀리 * retval);
  STDMETHOD(put_y) (THIS_ 짧은 newY);
  STDMETHOD(get_y) (THIS_ 짧은 멀리 * retval);
  STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint 멀리 * newPosition);
  STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint 멀리 * 훨씬 * retval);
  STDMETHOD(RefreshWindow)(THIS);
  STDMETHOD(SetAllProps) (THIS_ 짧은 x, 짧은 y, BSTR 텍스트);
  STDMETHOD(ShowWindow)(THIS);
END_DUAL_INTERFACE_PART(DualAClick)

Mfc의 이중 인터페이스를 연결 하려면 QueryInterface 메커니즘 추가 INTERFACE_PART 인터페이스 맵 항목

BEGIN_INTERFACE_MAP (CAutoClickDoc, CDocument)
  INTERFACE_PART (CAutoClickDoc, DIID_IAClick, 파견)
  INTERFACE_PART (CAutoClickDoc, IID_IDualAClick, DualAClick)
END_INTERFACE_MAP()

다음으로, 인터페이스의 구현을 작성 해야 합니다. 대부분의 경우, 기존 MFC IDispatch 구현에 위임할 수 있게 됩니다. 예를 들어:

STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::AddRef()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::Release()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalRelease();
}
STDMETHODIMP CAutoClickDoc::XDualAClick::QueryInterface(
             REFIID iid, LPVOID* ppvObj)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfoCount(
            UINT FAR* pctinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfoCount(pctinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfo(
          UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetIDsOfNames(
       REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
       LCID lcid, DISPID FAR* rgdispid) 
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames, 
                                    lcid, rgdispid);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::Invoke(
    DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
    DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
    EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->Invoke(dispidMember, riid, lcid,
                             wFlags, pdispparams, pvarResult,
                             pexcepinfo, puArgErr);
}

개체의 메서드 및 속성 접근자 함수에 대해 구현을 작성 해야 합니다. 메서드 및 속성 함수 마법사를 사용 하 여 생성 하는 방법에 다시 일반적으로 위임할 수 있습니다. 그러나, 변수에 직접 액세스 속성을 설정 하는 경우에 get/put 변수의 값으로는 코드를 작성 해야 합니다. 예를 들어:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
 ? / / MFC 유니코드 BSTR를에서 자동으로 변환 / / Ansi CString, 필요한 경우...
 ? pThis-> m_str newText; =
 ? 반환 NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
 ? METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
 ? / / MFC 자동으로 Ansi Cstring에서 변환 / / 유니코드 BSTR, 필요한 경우...
 ? pThis-> m_str.SetSysString(retval);
 ? 반환 NOERROR;
}

이중 인터페이스 포인터 전달

이중 인터페이스 포인터 전달 CCmdTarget::FromIDispatch를 호출 해야 하는 경우에 특히 만들기란 쉽지 않습니다. FromIDispatch 는 MFC의 IDispatch 포인터 에서만 작동합니다. 이 문제를 해결 하는 방법 중 하나는 원래 IDispatch 포인터 집합 MFC에 의해 위로 그것 필요로 하는 함수 포인터를 전달에 대 한 쿼리. 예를 들어

 STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position (
 nbsp;??? IDualAutoClickPoint 극동 * newPosition)
{
 ? METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
 ? LPDISPATCH lpDisp = NULL;
 ? newPosition-> QueryInterface (IID_IDispatch, (LPVOID *) & lpDisp);
 ? pThis-> SetPosition(lpDisp);
 ? lpDisp-> Release();
 ? 반환 NOERROR;
}

이중 인터페이스 메서드를 통해 다시 포인터를 전달 하기 전에 듀얼 인터페이스 포인터를 MFC IDispatch 포인터에서 변환 해야 합니다. 예를 들어:

STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position (
 nbsp;??? IDualAutoClickPoint 극동 * 훨씬 * retval)
{
 ? METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
 ? LPDISPATCH lpDisp;
 ? lpDisp = pThis-> GetPosition();
 ? lpDisp-> QueryInterface (IID_IDualAutoClickPoint, (LPVOID *) retval);
 ? 반환 NOERROR;
}

응용 프로그램의 형식 라이브러리 등록

AppWizard OLE 자동화 서버 응용 프로그램의 형식 라이브러리를 시스템에 등록 하는 코드를 생성 하지 않습니다. 형식 라이브러리를 등록 하는 다른 방법 그러나 그것은 그것 업데이트는 OLE 형식 정보 즉, 독립 실행형 응용 프로그램이 실행 될 때마다 때 형식 라이브러리를 등록 하는 응용 프로그램을 편리 하 게。

독립 실행형 응용 프로그램이 실행 될 때마다 응용 프로그램의 형식 라이브러리를 등록 하려면:

형식 라이브러리 변경 내용에 맞게 프로젝트 빌드 설정 수정

수정 프로젝트의 빌드 설정을 UUID 정의가 포함 된 헤더 파일에 의해 생성 되는 MkTypLib 형식 라이브러리를 다시 작성 하는 때마다

  1. 빌드 메뉴에서 설정을 클릭 ODL 파일에서 각 구성에 대 한 파일 목록。

  2. OLE 형식 탭을 클릭 하 고 출력 헤더 파일 이름 필드에 파일 이름을 지정 합니다. 사용 되지 않는 이미 프로젝트에 의해 이후 MkTypLib 모든 기존 파일을 덮어씁니다 파일 이름을 사용 합니다. 빌드 설정 대화 상자를 닫으려면 확인을 클릭합니다。

MkTypLib 생성 된 헤더 파일의 UUID 정의 프로젝트에 추가 하려면:

  1. MkTypLib 생성을 포함 귀하의 표준 헤더 파일에 헤더 파일, STDAFX 포함 되어 있습니다.H。

  2. INITIIDS 새 파일을 만듭니다.CPP, 귀하의 프로젝트에 추가 합니다. 이 파일에서 포함 OLE2 후 MkTypLib 생성 된 헤더 파일을 포함 합니다.H 및 INITGUID입니다.H:
    / / initIIDs.c: 듀얼 인터페이스에 대 한 Iid를 정의
    / /이 미리 컴파일된 헤더와 함께 내장 되지 해야 합니다.
      # include lt;ole2.h >
      # include <initguid.h>
      # include "acdual.h"
    
  3. 빌드 메뉴에서 설정을 클릭 한 다음 INITIIDS를 선택 합니다.각 구성에 대 한 파일 목록에서 CPP。

  4. 카테고리 "미리 컴파일된 헤더" 고 미리 선택 합니다 "사용 하지 않는 컴파일된 헤더" 라디오 단추, c + + 탭을 클릭 합니다. 빌드 설정 대화 상자를 닫으려면 확인을 클릭합니다。

형식 라이브러리에서 올바른 개체 클래스 이름 지정

Visual c + +와 함께 제공 올바르게 마법사 구현 클래스 이름을 사용 하 여 OLE 할까요 클래스에 대 한 서버의 ODL 파일에서 coclass를 지정 합니다. 이 작동 하는 동안 구현 클래스 이름은 아마 개체의 사용자가 사용 하려면 클래스 이름이입니다. 올바른 이름을 지정 하려면 ODL 파일을 열고 하 고 찾은 각 coclass 문에 구현 클래스 이름을 올바른 외부 이름으로 바꿉니다。

Note는 coclass 문을 변경 하는 때 CLSIDs MkTypLib 생성 된 헤더 파일에서 변수 이름을 따라 변경 됩니다. 새 변수 이름을 사용 하는 코드를 업데이 트 해야。

예외 및 자동화 오류 인터페이스 처리

자동화 개체의 메서드 및 속성 접근자 함수는 예외를 throw 될 수 있습니다. 만약 그렇다면, 이중 인터페이스 구현에서 처리 하 고 컨트롤러 IErrorInfoOLE 자동화 오류 처리 인터페이스를 통해 예외에 대 한 정보를 전달 해야 합니다. 이 인터페이스는 IDispatch 와 VTBL 인터페이스를 통해 상세한, 상황별 오류 정보를 제공합니다. 오류 처리기를 사용할 수 있는지를 나타내려면 ISupportErrorInfo 인터페이스를 구현 해야 합니다.

오류 처리 메커니즘을 설명 하는 표준 디스패치 지원을 구현 하는 데 사용 하는 ClassWizard 생성 함수 예외를 throw 하는 가정 합니다. IDispatch::Invoke 의 MFC의 구현은 일반적으로 이러한 예외를 포착 하 고 Invoke 호출을 통해 반환 되는 변환 하는 EXCEPTINFO 구조체입니다. 그러나 VTBL 인터페이스를 사용 하는 경우 있습니다 해당 예외를 catch 하는 작업을 담당 합니다. 보호 하는 이중 인터페이스 방법의 예

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, DualAClick)
 ? TRY_DUAL(IID_IDualAClick)
 ? {
 ???? / / MFC 유니코드 BSTR를에서 자동으로 변환 / / Ansi CString, 필요한 경우...
 ???? pThis-> m_str newText; =
 ???? 반환 NOERROR;
 ? }
 ? CATCH_ALL_DUAL
}

CATCH_ALL_DUAL예외가 발생 하는 경우 올바른 오류 코드를 반환 처리 합니다. CATCH_ALL_DUAL는 MFC 예외 ICreateErrorInfo 인터페이스를 사용 하 여 OLE 자동화 오류 처리 정보로 변환 합니다. (예를 들어 CATCH_ALL_DUAL 매크로 MFCDUAL 파일에 있습니다.H는 ACDUAL 샘플. 예외를 처리 호출 하는 함수를 DualHandleException , MFCDUAL 파일에 있습니다.CPP입니다.) CATCH_ALL_DUAL오류 코드가 발생 한 예외 형식에 따라 반환 결정

OLE 자동화 오류 처리기를 사용 하는 것을 나타내려면 또한 ISupportErrorInfo 인터페이스를 구현 해야。

첫째, 코드 ISupportErrorInfo 를 지 원하는 표시 자동화 클래스 정의를 추가합니다。

둘째, ISupportErrorInfo 구현 클래스를 MFC의 QueryInterface 메커니즘 연관 자동화 클래스의 인터페이스 지도에 코드를 추가 합니다. INTERFACE_PART문을 일치 ISupportErrorInfo 에 대해 정의 하는 클래스。

ISupportErrorInfo 를 지원 하기 위해 정의 하는 클래스를 구현 하는 마지막으로,。

(합니다 이러한 세 단계를 수행 하는 데 세 가지 매크로 포함 하는 ACDUAL 샘플 DECLARE_DUAL_ERRORINFO , DUAL_ERRORINFO_PART , 및 IMPLEMENT_DUAL_ERRORINFO , 모든 MFCDUAL에 포함 된.H.)

다음 예제에서는 ISupportErrorInfo를 지원 하기 위해 정의 하는 클래스를 구현 합니다. CAutoClickDoc자동화 클래스의 이름입니다 및 IID_IDualAClick OLE 자동화 오류 개체를 통해 보고 된 오류 소스 인터페이스에 대 한 IID:

STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() {
 nbsp; METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) 반환 pThis-> ExternalAddRef(); 
} STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::Release() {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) 반환 pThis-> ExternalRelease(); 
} STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::QueryInterface (REFIID iid, LPVOID * ppvObj) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) 반환 pThis-> ExternalQueryInterface (& iid, ppvObj); 
} STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) 반환 (iid IID_IDualAClick =)? S_OK: S_FALSE를 반환; 
}

기술 노트 번호로 |nbsp; 카테고리별 기술 노트(&N)

Index