목차

주요 개념

COM 종류

인프로세스 서버 : 다른 프로세스에서 생성&실행되는 서버

아웃오브프로세스 : 별도의 프로세스가 생성되어 실행되는 서버

인터페이스 정의

I로 시작되며, IUnknown 에서 상속되어야 한다.

IUnkonwn에 정의되는 기본 메소드

언어독립성을 유지하기 위해서 상속만을 지원한다. polymorphism은 지원하지 않는 정책

GUID (Global Unique IDentifer)

OSF가 제공하는 GUID를 차용

128비트 (16바이트)의 구조체

모든 COM 객체와 해당되는 COM 내부의 인터페이스는 독립적인 GUID를 갖는다.

UUID 라고도 부른다.

CLSID : COM 객체의 GUID

IID : 인터페이스의 GUID

GUID 제어

guiddef.h 에 구조체가 선언되어 있다.

typedef struct _GUID {
    unsigned long Data1, Data2, Data3;
    unsigned char Data4[ 8 ];
} GUID;

비교기능

구조체이기 때문에 파라미터로 오갈 때에는 레퍼런스 형식으로 사용된다.

GUID 변환

StringFromGUID2 : GUID를 스트링의 형식으로 변경하는 함수

ProgID

CLSID의 별명 (alias)

128비트의 코드 형태는 기억하기 어려우므로 문자열 식별자를 제공

hkey_classes_root 내부의 각 항목들이 COM의 ProgID 들

ProgID 변환

ProgID로부터 CLSID를 구한다.

COM 사용

메모 : COM API 함수는 “Co”로 시작된다.

등록,해제

// 등록
regsvr32 COMServerName.dll
// 해제
regsvr32 /u COMServerName.dll

리턴값

정상 : S_OK (== 0x0L)

에러 : 0x80000000L (== 마이너스 얼마 얼마)

초기화/종료

COM 사용 개시 : CoInitializeEx( NULL, /*dwCoInit*/ ), 첫번째 값은 예약값으로 현재는 널.

COM 객체 인스턴스 생성 - CoCreateInstance

CoCreateInstance( CLSID, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnk )CLSID와 IID를 넘겨서 인터페이스 포인터를 구한다.

CLSCTX_ALL clsid를 검색할 장소 지정
IID_IUnknown 예제로사용된 IID. 사용시에는 얻으려는 인터페이스 아이디 (IID)를 넣는다.
pUnk 리턴된 인터페이스 포인터
  1. 내부에서는 CoGetClassObject()를 (책에 의하면) 호출하여 COM 객체(클래스객체)를 구한다고 함, 설명하기 위한 예인지는 잘 모르겠지만.
  2. 얻어낸 클래스 객체로부터 사용하려는 인터페이스 인스턴스를 생성

함수 호출관계 빨리 보기

  1. CoCreateInstance()
    1. IClassFactory 인터페이스 변수 준비
    2. CoGetclassObject()
      1. 레지스트리로부터 COM 객체의 경로명과 파일명을 구한다.
      2. CoLoadLibrary()로 COM 객체를 로딩
      3. GetProcAddress() : “DllGetClassObject” 함수 포인터 얻기
      4. DllGetClassObject()로 COM 객체와 대응되는 클래스팩토리 COM 객체를 얻어 리턴
    3. 리턴된 클래스팩토리 COM 객체의 CreateInstance()를 호출
    4. 작업 종료

COM 객체 인스턴스 생성 - CoGetClassObject

CoCreateInstance()에 의해 호출되는 CoGetClassObject()가 하는일

HRESULT CoGetClassObject(
  __in      REFCLSID rclsid,
  __in      DWORD dwClsContext,
  __in_opt  COSERVERINFO pServerInfo,
  __in      REFIID riid,
  __out     LPVOID *ppv
);

기본

  1. CLSID 에 해당되는 클래스 객체(by CLSID)를 찾아, 해당 객체의 IID_IClassFactory 인터페이스를 얻는다.
  2. 2번째 파라미터 (dwClsContext)
    • CLSCTX_ALL : InProcServer32 > LocalServer32 에서 순서대로 객체 검색
    • CLSCTX_LOCAL_SERVER : LocalServer32에서 검색

CLSID에 해당되는 DLL(또는 다른파일) 얻기

  1. HKEY_CLASSES_ROOT\CLSID에서
  2. CLSID 와 같은 키의 InProcServer32/LocalServer32(OutOfProcess style)에서 COM객체의 경로를 획득

실제 DLL(또는 다른파일) 로딩하기

객체 위치(경로)를 구했으면,

로딩된 DLL로부터 클래스 객체 얻기

  1. 로딩된 DLL로 부터 GetProcAddress()를 사용해서 DllGetClassObject()의 함수포인터를 구해온다.
  2. DllGetClassObject()의 3번째 파라미터에 최종 클래스 오브젝트 (여기서는 해당 COM 객체의 IID_IClassFactory 인터페이스)를 리턴 받고
  3. 함수를 종료한다.
// 의미전달용 코드
DllGetClassObject( CLSID, IID, (out)ppv );

COM 객체 인스턴스 생성 - 인터페이스(인스턴스) 생성

HRESULT CoGetClassObject(
  __in      REFCLSID rclsid,
  __in      DWORD dwClsContext,
  __in_opt  COSERVERINFO pServerInfo,
  __in      REFIID riid,
  __out     LPVOID *ppv
);

CoCreateInstance()를 호출 한뒤,

  1. 내부에서 CoGetClassObject()가 실행되어 IID_IClassFactory 인터페이스를 구했다면,
  2. IID_IClassFactory 인터페이스를 사용해서
  3. riid (실제로 얻으려는 인터페이스 GUID)에 해당되는 인터페이스를 만든다. (인스턴스를 생성한다.)
    (IClassFactory*)pClassFactory->CreateInstance( NULL, riid, ppv );
  4. 최종 값은 ppv에 있으므로, 해당 값을 넘겨주는 것으로 CoGetClassObject() 함수 역할은 종료된다.