본문 바로가기
Programming/Tips(C++,C#)

Chapter 19. ATL 자동화 구현

by 곰네Zip 2014. 10. 28.

1. 자동화 객체란?

  1) 자동화의 장, 단점

   - 스크립트 언어를 사용하는 클라이언트 어플리케이션에서 COM객체를 사용하려면 자동화가 지원되야함

   - 아웃오브프로세스의 경우 COM객체는 마샬링을 수행하는 proxy/stub DLL이 필요하다. 자동화를 사용

    하여 마샬링코드 작성과 proxy/stub DLL을 클라이언트에 분배할 필요가 없음.

   - 단점 : 실행속도가 느리다. 직접적인 COM인터페이스로의 접근이 아니라 Invoke()를 이용한 간접 접근

                -> MS에서는 이중 인터페이스 지원을 권장. (직접호출 및 자동화 지원)

 

  2) 자동화 구현을 위한 조건

    - 자동화 구현을 위해 형식 라이브러리와 IDispatchImple에 인터페이스 관련 정보가 포함되어야 함

    - ATL에서는 IDispatchImple에서 파생되는 COM객체를 생성한다. IDispatchImple은 IDispatch의 기본

      부분을 구현해줌. 개발자는 구현하는 메소드나 속성만 구현하면 된다.

    - DispatchImpl템플릿을 선언한 경우, IDL파일에서는 반드시 dual키워드를 입력하고 인터페이스를

     IDispatch에서 파생해야 하고, dispID를 추가. 

 [ object,  uuid( UUID ), dual, helpstring("String"), pointer_default(unique) ]

 interface IMyClass : IDispatch {

    [propput, id(1), helpstring("HELPSTRING")] HRESULT func([in] param1 ... );

 };

      또한, 다음과 같은 COM MAP을 제공 

 BEGIN_COM_MAP(CMyClass)

      COM_INTERFACE_ENTRY(IMyClass)

      COM_INTERFACE_ENTRY(IDispatch)

 END_COM_MAP()

     COM_INTERFACE_ENTRY(IDispatch)는 표준 디스패치 인터페이스를 통해 자동화 객체에 접근할 때 사

   용하는 인터페이스를 정의함

 

2. 디스패치 인터페이스

 - 디스패치 인터페이스는 IUnknown로부터 파생된다.

   IUnknown인터페이스 멤버에 추가하여 GetTypeInfoCount(), GetTypeInfo(), GetIDsOfNames(), Invoke()

   4개의 멤버함수를 포함한다.

 1) IDispatch::GetIDsOfNames()

   자동화 객체가 제공하는 메소드 또는 속성에 접근할 때, 이 함수를 호출하여 해당 메소드나 속성의 이름에

  해당하는 dispID값 구한다. 

 HRESULT GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames,

                                    unsigned int cNames, LCID lcid, DISPID FAR* rgDispId);

   riid는 예약어로서 IID_NULL을 입력. 두번째 매개변수인 rgszNames는 구하려는 속성, 메소드 명을 배열

 형태로입력. 세번째에는 사용된 배열의 개수, 네번째는 로케일정보, 마지막변수는 dispID를 반환

   아래는 일반적인 호출 방법 

 szName = L"MyFunc";

 m_pDisp->GetIDsOfNames(IID_NULL, &szNAme,1 LOCALE_SYSTEM_DEFAULT, &m_dispID);

 

 2) IDispatch::Invoke()

  원형 

 HRESULT STDMETHODCALLTYPE Invoke(

   DISPID dispIdMember,                // DISP ID

   REFIID riid,                                // IDD_NULL

   LCID lcid,                                  // 로케일 정보

   WORD wFlag,                            // flag

   DISPPARAMS *pDispParams,      // 매개변수 정보

   VARIANT *pVarResult,                // 리턴된 결과

   EXCEPTINFO *pExcepInfo,         // 예외사항 정보

   UINT *puArgErr                         // 에러 매개변수 인덱스

);

 함수 호출 예 

 m_pDisp->Invoke(m_dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,

                         &m_dispparams, &m_retVal, NULL, NULL);

   i) DISPID : 자동화 컨트롤러가 호출하기 원하는 함수의 DISP ID값

   ii) REFIID : 향후 사용을 위해 예약. 현재는 IID_NULL

   iii) LCID : 로케일 정보

   iv) FLAG : dispID에 대한 플래그. 각각 다음과 같다

      DISPATCH_METHOD : 멤버 함수를 메소드로서 호출

      DISPATCH_PROPERTYGET : 속성 또는 데이터 멤버를 읽는 함수

      DISPATCH_PROPERTYPUT : 속성 또는 데이터 멤버를 저장하는 함수

      DISPATCH_PROPERTYPUTREF : 값보다는 레퍼런스 정보를 부여해, 속성 혹은 데이터멤버를 저장

   v) DISPPARAMS : Invoke사용시 메소드 또는 속성에 대응하는 인수들은 DISPPARAMS구조체에 의해 전

     달된다. 이 구조체는 Variant인수 배열에 대응하는 포인터와 DISPID의 배열에 대응하는 포인터로 구성 

 typedef FARSTRUCT tagDISPPARAMS(

    VARIANTARG FAR* rgvarg;            //매개변수 배열

    DISPID FAR* rgdispidNameArgs;    //명명된 인수의 디스패치 ID

    unsigned int cArgs;                      //매개변수의 개수

    unsigned int cNamedArgs;            // 명명된 매개변수의 개수

} DISPPARAMS;

   vi) VARIANT *pVarResult

     Invoke()함수에 의해 실행된 메소드나 Get속성의 결과를 저장하는 VARIANT포인터. 결과값 리턴이 없거

    나 PUT속성에는 NULL값을 지정

   vii) EXCEPINFO

     Invoke()에 의해 실행된 메소드나 속성이 예외 상황을 만났을 때, 해당 예외 상황에 대한 정보가 저장되

    는 구조체의 포인터

   viii) UINT *puArgErr

     rgvarg에 포함된 첫 번째 매개 변수에 에러가 발생하였을 경우에 발생한다.

 

 3) 에러 정보 처리

  만약 Invoke()를 사용할 수 없을 경우 어떻게 추가적인 에러 정보를 받을 수 있을까? (Invoke()의 경우 에러 정보를 EXCEPINFO구조체를 통해 많은 정보값을 받아올 수 있다.)

  - IErrorInfo( Get..으로 시작하는 함수들의 집합)와 ICreateErrorInfo( Set.. 으로 시작하는 함수들의 집합)

 

출처 - COM Bible

반응형

댓글