다음을 통해 공유


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

[!참고]

온라인 설명서의을 처음 포함 되었습니다 때문 다음 기술 참고 업데이트 되지 않았습니다.따라서 일부 절차 및 항목 오래 되었거나 잘못 된 수 있습니다.최신 정보는 온라인 설명서 색인에서 관심 있는 주제에 대해 검색 하는 것이 좋습니다.

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

이중 인터페이스

OLE 자동화를 구현할 수 있지만 IDispatch 인터페이스나 VTBL 인터페이스를 (모두 포함)는 이중 인터페이스를 좋습니다 모든 OLE 자동화 개체를 노출에 대 한 이중 인터페이스를 구현 합니다.이중 인터페이스를 통해 상당한 장점을 IDispatch-인터페이스 또는 VTBL 전용:

  • VTBL 인터페이스를 통해 컴파일 타임 이나 런타임에 통해 바인딩이 장소 걸릴 수 있습니다 IDispatch.

  • VTBL 인터페이스를 사용할 수 있는 OLE 자동화 컨트롤러에서 향상 된 성능을 얻을 수 있습니다.

  • 사용 하는 기존 OLE 자동화 컨트롤러는 IDispatch 인터페이스는 계속 작동 합니다.

  • VTBL 인터페이스는 C++에서 호출할 수 쉽습니다.

  • 이중 인터페이스 호환성 Visual Basic 개체 지원 기능을 위해 필요합니다.

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

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

먼저 ODL 파일 서버 개체에 대 한 이중 인터페이스 정의를 수정 합니다.이중 인터페이스를 정의 하는 인터페이스 문을 대신 사용 해야는 DISPINTERFACE Visual C++ 마법사가 생성 하는 문입니다.기존 작업을 제거 하는 대신 DISPINTERFACE 문을 새 인터페이스 문을 추가 합니다.유지 함으로써는 DISPINTERFACE 양식을 수 있습니다 계속 클래스 마법사를 사용 하 여 속성 및 메서드를 개체에 추가할 수 있지만 문의 인터페이스에 해당 하는 속성과 메서드를 추가 해야 합니다.

이중 인터페이스는 인터페이스 문이 있어야는 OLEAUTOMATION듀얼 특성 및 인터페이스 해야 파생 될에서 IDispatch.사용할 수 있는 GUIDGEN 샘플을 만들려면는 IID 이중 인터페이스에 대 한:

[ uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000), // IID_IDualAClick
   oleautomation,
   dual
]
interface IDualAClick : IDispatch
  {
  };

인터페이스 문이 있으면 메서드 및 속성에 대 한 엔트리를 추가 시작 합니다.메서드 및 속성 접근자 함수에서 이중 인터페이스를 반환 하는 매개 변수 목록을 다시 정렬 하려면 필요한 이중 인터페이스의 경우는 HRESULT 반환 값은 특성 매개 변수로 전달 하 고 [retval,out].속성의 경우에 모두 읽기를 추가 하려면 한다는 점에 유의 하십시오 (propget) 및 쓰기 (propput) 동일한 id 가진 함수에 액세스 합니다.예를 들면 다음과 같습니다.

[propput, id(1)] HRESULT text([in] BSTR newText);
[propget, id(1)] HRESULT text([out, retval] BSTR* retval);

메서드 및 속성을 정의한 후, coclass 문의 interface 문의 대 한 참조를 추가 해야 합니다.예를 들면 다음과 같습니다.

[ uuid(4B115281-32F0-11cf-AC85-444553540000) ]
coclass Document
{
   dispinterface IAClick;
   [default] interface IDualAClick;
};

ODL 파일을 업데이트 한 후에 개체 클래스에 이중 인터페이스의 구현 클래스를 정의 하 고 해당 엔트리를 MFC에서 확인 MFC 인터페이스 매핑 메커니즘 사용 QueryInterface 메커니즘입니다.하나의 항목이 필요는 INTERFACE_PART 인터페이스는 ODL 문에 각 항목과 항목의 디스패치 인터페이스에 대 한 블록입니다.각 ODL 항목과 의 propput 특성이 필요한 이라는 함수 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 FAR* retval);
  STDMETHOD(put_x)(THIS_ short newX);
  STDMETHOD(get_x)(THIS_ short FAR* retval);
  STDMETHOD(put_y)(THIS_ short newY);
  STDMETHOD(get_y)(THIS_ short FAR* retval);
  STDMETHOD(put_Position)(THIS_ IDualAutoClickPoint FAR* newPosition);
  STDMETHOD(get_Position)(THIS_ IDualAutoClickPoint FAR* FAR* retval);
  STDMETHOD(RefreshWindow)(THIS);
  STDMETHOD(SetAllProps)(THIS_ short x, short y, BSTR text);
  STDMETHOD(ShowWindow)(THIS);
END_DUAL_INTERFACE_PART(DualAClick)

MFC의 이중 인터페이스 연결을 QueryInterface 메커니즘을 추가 된 INTERFACE_PART 인터페이스 맵에 항목:

BEGIN_INTERFACE_MAP(CAutoClickDoc, CDocument)
  INTERFACE_PART(CAutoClickDoc, DIID_IAClick, Dispatch)
  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)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   // MFC automatically converts from Unicode BSTR to 
   // Ansi CString, if necessary...
   pThis->m_str = newText;
   return NOERROR;
}
STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   // MFC automatically converts from Ansi CString to 
   // Unicode BSTR, if necessary...
   pThis->m_str.SetSysString(retval);
   return NOERROR;
}

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

이중 인터페이스 포인터 전달 되지를 호출 하는 경우에 특히 간단 CCmdTarget::FromIDispatch.FromIDispatchMFC에만 IDispatch 포인터입니다.이 문제를 해결 하는 한 가지 방법은 것의 원래 쿼리 IDispatch 포인터를 MFC에서 집합과 해당 포인터가 필요한 함수에 전달 합니다.예를 들면 다음과 같습니다.

STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position(
      IDualAutoClickPoint FAR* newPosition)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDisp = NULL;
   newPosition->QueryInterface(IID_IDispatch, (LPVOID*)&lpDisp);
   pThis->SetPosition(lpDisp);
   lpDisp->Release();
   return NOERROR;
}

이중 인터페이스 메서드를 통해에 대 한 포인터를 전달 하기 전에 하면 MFC에서 변환 해야 할 수도 있습니다 IDispatch 이중 인터페이스 포인터에 대 한 포인터입니다.예를 들면 다음과 같습니다.

STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position(
      IDualAutoClickPoint FAR* FAR* retval)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDisp;
   lpDisp = pThis->GetPosition();
   lpDisp->QueryInterface(IID_IDualAutoClickPoint, (LPVOID*)retval);
   return NOERROR;
}

응용 프로그램의 형식 라이브러리를 등록합니다.

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

등록 하는 응용 프로그램이 실행 될 때마다 응용 프로그램의 형식 라이브러리 스탠드만:

  • AFXCTL를 포함 합니다.H는 표준에서 헤더 파일을 STDAFX 포함 되어 있습니다.H의 정의 액세스 하는 AfxOleRegisterTypeLib 함수.

  • 응용 프로그램의 InitInstance 작동 하 고 호출을 찾을 COleObjectFactory::UpdateRegistryAll.이 호출을 다음 호출을 추가 AfxOleRegisterTypeLib, 지정 하는 LIBID 형식 라이브러리에서 형식 라이브러리의 이름과 함께 해당:

    // When a server application is launched stand-alone, it is a good idea
    // to update the system registry in case it has been damaged.
    m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
    COleObjectFactory::UpdateRegistryAll();
    // DUAL_SUPPORT_START
    // Make sure the type library is registered or dual interface won't work.
    AfxOleRegisterTypeLib(AfxGetInstanceHandle(), LIBID_ACDual, _T("AutoClik.TLB"));
    // DUAL_SUPPORT_END
    

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

프로젝트의 빌드 설정을 수정할 수 있도록 포함 하는 헤더 파일 UUID 정의 하 여 생성할 형식 라이브러리를 다시 빌드해야 때마다:

  1. 빌드 메뉴를 클릭 설정, 다음 ODL 파일을 선택 하는 각 구성 파일 목록에서.

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

추가 하는 UUID 프로젝트 하 여 생성 된 헤더 파일에서 정의 합니다.

  1. 여 생성 포함를 표준 헤더 파일 STDAFX 헤더 파일을 포함 합니다.H.

  2. INITIIDS 새 파일을 만듭니다.CPP를 프로젝트에 추가 합니다.이 파일에서 OLE2 포함 한 후 하 여 생성 된 헤더 파일을 포함 합니다.H 및 INITGUID입니다.H:

    // initIIDs.c: defines IIDs for dual interfaces
    // This must not be built with precompiled header.
      #include <ole2.h>
      #include <initguid.h>
      #include "acdual.h"
    
  3. 빌드 메뉴에서 클릭 설정, 다음 INITIIDS를 선택 합니다.CPP 파일 목록 각 구성에 대 한입니다.

  4. 클릭은 C++ 탭에서 범주를 클릭 합니다. 미리 컴파일된 헤더, 선택은 미리 컴파일된 헤더 사용 안 함 라디오 단추.확인을 눌러 닫습니다는 빌드 설정 대화 상자.

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

구현 클래스 이름을 함께 Visual C++를 정확 하 게 선적 된 마법사를 사용 하 서버의 ODL 파일 OLE 생성 가능 클래스에는 coclass를 지정 합니다.이 해결 하는 동안 구현 클래스 이름을 사용 하는 사용자 개체의 클래스 이름을 아닐.올바른 이름을 지정 하려면 ODL 파일을 열고 각 coclass 문에 찾아 구현 클래스 이름이 올바른 외부 이름으로 바꿉니다.

참고 coclass 문에 바꾼 경우 변수 이름을 CLSIDs 하 여 생성 된 헤더 파일에서 적절 하 게 변경 됩니다.새 변수 이름을 사용 하도록 코드를 업데이트 해야 합니다.

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

자동화 개체의 메서드 및 속성 접근자 함수 예외를 throw 할 수 있습니다.따라서 이중 인터페이스 구현에서 처리 해야 하며 컨트롤러 인터페이스 OLE 자동화 오류 처리를 통해 예외 정보를 다시 전달 하는 경우 IErrorInfo.이 인터페이스를 제공 하 여 모두를 통해 자세 하 고 상황에 맞는 오류 정보에 대 한 IDispatch 및 VTBL 인터페이스.오류 처리기를 사용할 수 있습니다, 구현 해야 나타내려면는 ISupportErrorInfo 인터페이스입니다.

오류 처리 메커니즘을 설명 하기 위해 표준 디스패치 지원을 구현 하는 데 사용 하는 클래스 마법사에서 생성 된 함수에서 예외를 throw 한다고 가정 합니다.MFC의 구현 IDispatch::Invoke 일반적으로 이러한 예외를 catch 하 고 통해 반환 되는 EXCEPTINFO 구조 변환의 Invoke 를 호출 합니다.그러나 VTBL 인터페이스를 사용 하는 경우는 직접 예외에 대 한 책임이 있습니다.이중 인터페이스 메서드 보호의 예:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   TRY_DUAL(IID_IDualAClick)
   {
      // MFC automatically converts from Unicode BSTR to 
      // Ansi CString, if necessary...
      pThis->m_str = newText;
      return NOERROR;
   }
   CATCH_ALL_DUAL
}

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

  • COleDispatchException -이 경우 HRESULT 다음 코드를 사용 하 여 생성 됩니다.

    hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 
                               (e->m_wCode + 0x200));
    

    HRESULT 특정 예외를 발생 시킨 인터페이스.오류 코드는 시스템에 정의 된 모든 충돌을 피하기 위해 0x200 오프셋 HRESULT표준 OLE 인터페이스에 대 한 s.

  • CMemoryException -이 경우 E_OUTOFMEMORY 이 반환 됩니다.

  • 여기서는 다른 예외- E_UNEXPECTED 이 반환 됩니다.

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 되는 IID OLE 자동화 오류 개체를 통해 보고 되는 오류 소스인 인터페이스:

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

참고 항목

기타 리소스

번호 기술 정보

범주별 기술 노트