====== 주요 개념 ======
===== COM 종류 =====
인프로세스 서버 : 다른 프로세스에서 생성&실행되는 서버
* DLL의 형태로 로딩되는 함수를 export 해야한다.
아웃오브프로세스 : 별도의 프로세스가 생성되어 실행되는 서버
* 로컬과 리모트로 분류된다.
===== 인터페이스 정의 =====
I로 시작되며, IUnknown 에서 상속되어야 한다.
IUnkonwn에 정의되는 기본 메소드
* QueryInterface
* AddRef
* Release
언어독립성을 유지하기 위해서 상속만을 지원한다. 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;
비교기능
* 연산자 ==, IsEqualGUID, IsEqualIID, IsEqualCLSID
구조체이기 때문에 파라미터로 오갈 때에는 레퍼런스 형식으로 사용된다.
* REFIID (== const IID&)
* COM에 관련 함수의 파라미터는 위의 디파인을 사용한다.
===== GUID 변환 =====
StringFromGUID2 : GUID를 스트링의 형식으로 변경하는 함수
==== ProgID ====
CLSID의 별명 (alias)
128비트의 코드 형태는 기억하기 어려우므로 문자열 식별자를 제공
* 형식
<컴포넌트 or 라이브러리명>.<객체명>.<버젼>
// 예
Excel.Application.10
hkey_classes_root 내부의 각 항목들이 COM의 ProgID 들
==== ProgID 변환 ====
ProgID로부터 CLSID를 구한다.
* 사용함수
HRESULT CLSIDFromProgID( LPOLESTR /*ProgID 문자열*/, LPCLSID /*리턴된 CLSID*/ );
====== COM 사용 ======
메모 : COM API 함수는 "Co"로 시작된다.
===== 등록,해제 =====
// 등록
regsvr32 COMServerName.dll
// 해제
regsvr32 /u COMServerName.dll
===== 리턴값 =====
정상 : S_OK (== 0x0L)
에러 : 0x80000000L (== 마이너스 얼마 얼마)
===== 초기화/종료 =====
COM 사용 개시 : CoInitializeEx( NULL, /*dwCoInit*/ ), 첫번째 값은 예약값으로 현재는 널.
* CoInitialize() : DCOM 이전에 사용되던 초기화 함수. 현재는 미사용.
===== COM 객체 인스턴스 생성 - CoCreateInstance =====
**CoCreateInstance( CLSID, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnk )** 로 **CLSID와 IID**를 넘겨서 인터페이스 포인터를 구한다.
| CLSCTX_ALL | clsid를 검색할 장소 지정 |
| IID_IUnknown | 예제로사용된 IID. 사용시에는 얻으려는 인터페이스 아이디 (IID)를 넣는다. |
| pUnk | 리턴된 인터페이스 포인터 |
- 내부에서는 CoGetClassObject()를 (책에 의하면) 호출하여 COM 객체(클래스객체)를 구한다고 함, 설명하기 위한 예인지는 잘 모르겠지만.
- 얻어낸 클래스 객체로부터 사용하려는 인터페이스 인스턴스를 생성
==== 함수 호출관계 빨리 보기 ====
- CoCreateInstance()
- IClassFactory 인터페이스 변수 준비
- CoGetclassObject()
- 레지스트리로부터 COM 객체의 경로명과 파일명을 구한다.
- CoLoadLibrary()로 COM 객체를 로딩
- GetProcAddress() : "DllGetClassObject" 함수 포인터 얻기
- DllGetClassObject()로 COM 객체와 대응되는 클래스팩토리 COM 객체를 얻어 리턴
- 리턴된 클래스팩토리 COM 객체의 CreateInstance()를 호출
- 작업 종료
===== COM 객체 인스턴스 생성 - CoGetClassObject =====
CoCreateInstance()에 의해 호출되는 CoGetClassObject()가 하는일
HRESULT CoGetClassObject(
__in REFCLSID rclsid,
__in DWORD dwClsContext,
__in_opt COSERVERINFO pServerInfo,
__in REFIID riid,
__out LPVOID *ppv
);
==== 기본 ====
- CLSID 에 해당되는 클래스 객체(by CLSID)를 찾아, 해당 객체의 IID_IClassFactory 인터페이스를 얻는다.
- 2번째 파라미터 (dwClsContext)
* CLSCTX_ALL : InProcServer32 > LocalServer32 에서 순서대로 객체 검색
* CLSCTX_LOCAL_SERVER : LocalServer32에서 검색
==== CLSID에 해당되는 DLL(또는 다른파일) 얻기 ====
- HKEY_CLASSES_ROOT\CLSID에서
- CLSID 와 같은 키의 **InProcServer32**/**LocalServer32**(OutOfProcess style)에서 COM객체의 경로를 획득
==== 실제 DLL(또는 다른파일) 로딩하기 ====
객체 위치(경로)를 구했으면,
* 인-프로세스 : CoLoadLibrary()로 해당 DLL 객체를 로딩
* 아웃오브프로세스 : ? 아직 모름
==== 로딩된 DLL로부터 클래스 객체 얻기 ====
- 로딩된 DLL로 부터 GetProcAddress()를 사용해서 **DllGetClassObject()의 함수포인터**를 구해온다.
- DllGetClassObject()의 3번째 파라미터에 최종 클래스 오브젝트 (여기서는 해당 COM 객체의 IID_IClassFactory 인터페이스)를 리턴 받고
- 함수를 종료한다.
// 의미전달용 코드
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()를 호출 한뒤,
- 내부에서 CoGetClassObject()가 실행되어 IID_IClassFactory 인터페이스를 구했다면,
- IID_IClassFactory 인터페이스를 사용해서
- riid (실제로 얻으려는 인터페이스 GUID)에 해당되는 인터페이스를 만든다. (인스턴스를 생성한다.)
(IClassFactory*)pClassFactory->CreateInstance( NULL, riid, ppv );
- **최종 값은 ppv에 있으므로, 해당 값을 넘겨주는 것**으로 CoGetClassObject() 함수 역할은 종료된다.