2010년 10월 11일 월요일

VS2008에서 ActiveX COM DLL 사용방법

Visual Studio 2008에서 ActiveX COM(Component Object Model) DLL(Dynamic Link Library)을 사용하는 방법을 알아보자.
COM은 일반적인 컨트롤(control)과는 다르게 움직인다. 통상적인 컨트롤은 핸들(HWND: handle)을 얻어 메시지(SendMessage, GetMessage: message)를 이용해 반응을 한다. 이와는 다르게 COM이 움직이는 기반은 포인터(pointer)이다[1]. COM 생성시에 포인터를 받고 COM과 통신을 할 때도 함수포인터(function pointer)를 이용한다. COM 속에 있는 클래스(class)와 인터페이스(interface: virtual function table)는 각자 고유한 ID(identifier)가 있다. COM 객체를 생성하려면 이 고유한 ID를 얻어서 생성해야 한다. 클래스 ID는 CLSID(CLaSs ID)라 부르고 인터페이스 ID는 UUID(Universally Unique ID)라 한다. 또한, COM을 사용하기 전에 반드시 컴퓨터에 등록을 해야 한다. 아래에 in-process sever(server와 client가 같은 컴퓨터에 있다.) 관점으로 설명한다.

- 먼저 "C:\WINDOWS\system32" 폴더에 DLL을 복사한다.
- 명령어 "regsvr32 test.dll"을 이용해 등록한다. "실행"이나 "명령 프롬프트"를 이용하면 명령어를 OS에 입력할 수 있다.
- 등록이 성공하면 test.dll의 DllRegisterServer 성공이란 창이 뜬다.
- 등록을 해제하고 싶으면 "regsvr32 /u test.dll"를 사용하면 된다.
- "regedit"을 이용하면 등록한 COM이 레지스트리(registry)상의 "HKEY_CLASSES_ROOT/CLSID" 아래에 존재하는 것을 확인할 수 있다.

COM 등록이 완료되면 아래 절차에 따르 COM 객체를 생성하면 된다.

1. COM 헤더 파일 생성 및 선언
#import "C:/WINDOWS/system32/test.dll" no_namespace
ActiveX COM은 통상적인 헤더 파일(header file)을 사용하지 않고 위의 구문을 이용해 함수들 정의가 담긴 헤더 파일을 자동생성한다. 이렇게 생성된 포인터를 COM smart pointer라고 한다. 위 구문은 통상적인 헤더 파일을 선언한 것과 동일한 효과를 가지므로 필요한 곳에 헤더 파일 대신에 사용하면 된다.

2. COM 라이브러리 초기화

COM을 제어하는 함수들은 대부분 Co...로 시작하는 것을 기억하자. COM 라이브러리를 초기화하려면 아래 두 함수 중에서 하나를 쓰면 된다.
새로 만든 프로젝트라면 새로운 code인 CoInitializeEx 함수를 써야 한다.
   ::CoInitialize(NULL);   // 옛날 code
혹은
   ::CoInitializeEx(NULL, COINIT_MULTITHREADED);   // 새로운 code
프로그램 시작점(예를 들면 InitInstance 함수 혹은 클래스 생성자(class constructor))에서 한 번만 선언한다.(기억할 것: 쓰레드(thread)당 하나씩 생성) 프로그램이 끝날 때(예를 들면 ExitInstance 함수 혹은 클래스 파괴자(class destructor))는 아래를 반드시 호출해야 한다.
   CoUninitialize();

3. COM ID 얻기

COM ID를 얻으려면 아래 code를 사용한다.
   HRESULT nResult;
   CLSID TestID;
   nResult = ::CLSIDFromProgID(OLESTR("test.SmartClass.1"), &TestID);
   if (nResult != S_OK) return FALSE;
위 code를 실행하려면 ProgID(program ID)를 알아야 한다. ProgID는 "regedit"을 이용해 "test.dll"(예를 든 ActiveX COM DLL 이름)을 검색하면 레지스트리에서 ProgID 정보를 찾을 수 있다. ProgID의 형식은 "라이브러리명.객체명.버전"이다. 버전은 생략할 수 있다.

4. COM 인스턴스(instance) 생성

COM smart pointer가 _SmartClass로 선언되었기 때문에(ProgID의 객체명에 '_'를 붙여 컴파일러가 자동생성한다.) 아래 code를 실행하면 된다.
   _SmartClass *ptr;
    nResult = ::CoCreateInstance(TestID, NULL, CLSCTX_INPROC_SERVER, __uuidof(_SmartClass), (LPVOID *) &ptr);

5. COM 사용

VS2008에 있는 "정의로 이동" 기능(_SmarClass 위치로 가서 마우스의 오른쪽을 클릭)을 사용하면 임시로 생성된 TLH(Type Library Header)를 볼 수 있다.

6. COM 라이브러리 해제

위에서도 설명했듯이 해당 쓰레드에서 COM 사용이 끝나면 반드시 아래 code를 호출해야 한다.
   CoUninitialize();
이런 복잡한 과정(COM 사용법 중에서는 가장 쉬운 방법)을 거쳐서 써야하는 COM이 왜 아직까지 살아남아 있을까? 왜냐하면 COM은 플랫폼(platform)에 독립적으로 설계되기 때문에 굉장히 다양한 곳에서 code 변경없이 사용할 수 있기 때문이다.

[참고문헌]
[1] J. Glatt, "COM in plain C," CodeProject, March 2006.

댓글 없음 :

댓글 쓰기

욕설이나 스팸글은 삭제될 수 있습니다. [전파거북이]는 선플운동의 아름다운 인터넷을 지지합니다.