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

자동화와 이중 인터페이스

by 곰네Zip 2014. 11. 12.

1. 자동화

  - VB나 ASP같은 스크립트기반 언어에서는 COM객체의 인터페이스에 직접 접근할 수 없다. 하지만 자동화를 통해 COM객체를 사용할 수 있다. 자동화를 통하면 마샬링을 위한 프록시/스텁 구현도 필요가 없다. 하지만, 자동화의 단점은 수행속도, 사용가능한 데이터형의 제한이 있다. 이를 위해 MS에서는 자동화와 기존의 커스텀 인터페이스를 모두 지원하는 이중 인터페이스를 제안함.

 

2. IDispatch인터페이스

  - IUnknown에서 파생됨. GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, Invoke등의 4개의 메소드가 있다.

  - 다음 VB의 예

 dim obj As Object

 set obj = CreateObject(ProgID)

 obj.Prop = propVal

 obj.Method

    > VB의 CreateObject를 하면, COM라이브러리의 CLSIDFromProgID함수를 이용하여 CLSID를 가져온 후, CoCreateInstance를 호출해 자동화 객체를 생성한 후에, IDispatch인터페이스를 받아와서 obj에 저장.

    1) GetIDsOfNames : 매개변수에 지정되는 메소드나 속성이름에 대응하는 DISPID를 반환. DISPID는 메소드나 속성을 구별하는 ID.

     프로토타입 

 HRESULT STDMETHODCALLTYPE GetIDsOfNames(

      REFIID riid,                          // ID_NULL

      LPOLESTR *rsgzNames,       // 메소드, 속성명

      UINT cNames,                      // 개수

      LCID lcid,                            // 로케일 정보

      DISPID *rgDispId);                // 반환된 DISPID값

       - cNames는 거의1. (보통 한번에 하나의 속성, 메소드에 대한 DISPID를 구한다.)

 

    2) Invoke : 위에서 구해온 DISPID를 가지고, 이 함수를 호출하여, DISPID에 대응하는 함수를 호출.

      프로토타입

 HRESULT STDMETHODCALLTYPE Invoke(

     DISPID dispIdMember,            // DISPIP

     REFIID riid,                            // ID_NULL

     LCID lcid,                              // 로케일 정보

     WORD wFlags,                       // 플래그

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

     VARIANT *pVarResult,            // 리턴된 결과

     EXCEPTINFO *pExcepInfo,      // 예외상황 정보

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

       - 플래그 : Invoke에서는 해당 호출이 메소드인지(DISPATHCH_METHOD), 속성을 저장하는 함수인지(DISPATCH_PROPERTYPUT), 속성을 읽는 함수인지(DISPATCH_PROPERTYGET), 레퍼런스로 속성을 저장하는 함수인지 (DISPATCH_PROPERTYPUTREF)를 지정하는데 사용한다.

 

      - DISPPARAM : 내부에 호출되는 함수에 전달하여 줄, 매개변수 저장됨

 typedef struct tagDISPPARAMS{

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

    DISPID* rgdispidNamedArgs;  // 이름을 가지는 매개변수의 DISPID배열

    UINT cArgs;                          // 매개변수 갯수

    UINT cNamedArgs;                 // 이름을 가지는 매개변수의 갯수

 } DISPPARAMS;

 

      - 에러정보 구하기 : 에러 정보는 아래 구조체에 담겨서 반환된다.

 typedef struct tagEXCEPTINFO{

    WORD wCode;               //에러코드

    WORD wReserved;

    BSTR bstrSource;           // 예외발생소스

    BSTR bstrDescription;      // 예외 설명

    BSTR bstrHelpFile;          // 도움말 경로

    DWORD dwContextHelp;   // 도움말 컨텍스트

    ULONG pvReserved;

    ULONG pfnDeferredFillin;  //구조체를 채울 함수

    SCODE scode;                // 리턴값

 } EXCEPTINFO;

         > 위 구조체를 Invoke의 인자로 넘겨주면된다. 아니면 IErrorInfo 인터페이스를 받아와서 처리해도 됨.

 

3. late binding vs early binding

     - 자동화 컨트롤러가 자동화객체의 속성이나 메소드와 결합하는 시간이 런타임(late)인지, 컴파일타임(early)인지에 따라 구분됨. late binding이 더 느리나, 동적으로 자동화객체의 기능을 결정할 수 있다.

       -> 각 속성과 메소드에 대응하는 DISPID는 고정되고 이것은 형식 라이브러리에 저장된다. 컴파일 타임에 이를 읽어오면 GetIDsOfNames를 호출하지 않아도 된다. -> 더 빠르다. 이것은 ID binding으로 early binding의 한 종류

 

4. VARIANT 데이터형

  - VARIANT구조체는 다른 데이터형을 가지는 큰 공용체로 구성되어있다.

  - VariantChangeType() : VARIANT인스턴스의 데이터를 다른데이터로 바꿀때 사용

 

5. BSTR데이터형

  - wide char문자열 포인터. 제일 앞에 문자수가 들어간다. 그래서 SysAllocString()으로 BSTR을 할당해 주어야 정상적으로 사용가능하다. 그리고, BSTR할당 후에는 SysFreeString()으로 해제하여 줄 것.

 

6. SAFEARRAY데이터형

  - 배열 범위에 대한 정보를 가지고 있음 

 typedef struct tagSAFEARRAY{

    USHORT cDims;        //배열의 차원 수

    USHORT fFeatures;   // 플래그

    ULONG cbElements;  // 배열 요소의 갯수

    ULONG cLocks;        // lock 카운트

    PVOID pvData;          // 배열의 데이터 포인터

    SAFEARRAYBOUND rgsabound[1]; //각 배열 차원 바운드

 } SAFEARRAY;

 

 typedef struct tagSAFEARRAYBOUND{

    ULONG cElements;   // 배열 요소 수

    LONG lLbound;        // 배열 하위 바운드

 } SAFEARRAYBOUND;

 

 

반응형

댓글