본문 바로가기

[ Windows Program ]/ActiveX / COM

[COM] 31. ATL의 개요 (1) - 프로젝트와 객체의 생성

순수한(?) C++ 언어를 이용한 COM과 VC++의 COM.

이제 ATL(Active Template Library)입니다.

이는 '작고 빠르고 확장성을 갖는 COM 컴포넌트를 쉽게(!) 구현 할 수 있게 한다'....라고 합니다.

 

'작다'는 특징은 템플릿이기 때문에 실제 인스턴스가 만들어지기 전까지는 코드가 생성되지 않기 때문에 작을 수 있고,

'쉽게' 구현 할 수 있다는 것은, 필수 인터페이스(IUnknown, IClassFactory)에 대한 코드가 구현되어 있기 때문에 편리합니다.

 

'빠르고 확장성'이 있다는 것은...아마도, 설계를 잘 했나보군요. 하핫~

 

ATL이 어떻게 이런 장점을 제공하는지는 예제를 통해 어느 정도 확인 할 수 있겠습니다.

예제를 만들 때 눈 여겨 봐야 할 점은 ATL을 사용 할 때와 사용하지 않을 때, 들어가는 수고와 만들어진 결과입니다.

그래야, 앞에서 힘들게 만들었던 것들이 얼마나 쉽게 만들어지는지 알 수 있을 것입니다.

 

-------------------------------------------------------------------------

 

ATL 프로젝트 만들기

 

1. 프로젝트를 만듭니다. Visual C++/ ATL의 ATL 프로젝트를 선택합니다. 이름은 HelloServer로 하였습니다.

 

2. 프로젝트 옵션은 기본적으로 아래와 같이 선택 됩니다. 아래 옵션을 그대로 사용합니다. 책에서는 '특성사용'이라는 옵션이 체크 해제 되어 있는 것을 확인해야 한다고 되어 있는데 VS2005인 것 같습니다. VS2008에는 나오지 않네요. 이 옵션은 애트리뷰트와 관련되는 옵션이라고 합니다. 옵션이 없으니 다른 사용 방법이 마련되어 있나 봅니다. 패스~

 

3. 만들어진 프로젝트는 다음과 같습니다. 두 개의 프로젝트가 만들어지는데, 아래 보이는 HelloServerPS는 ProxyStub용 프로젝트입니다. def 파일, idl 파일 등 앞에서 배운 파일들이 자동으로 생성되어 있습니다.

 

4. DEF 파일의 내용은 아래와 같습니다. EXPORT 함수들을 정의하고 있네요. 아..처음 보는 Install이라는 함수도 있군요. 일단 이렇게 만들어진다는 것을 확인하고 넘어 갑니다.

 ; HelloServer.def : 모듈 매개 변수를 선언합니다.

 

LIBRARY      "HelloServer.DLL"

 

EXPORTS
   DllCanUnloadNow  PRIVATE
   DllGetClassObject PRIVATE
   DllRegisterServer PRIVATE
   DllUnregisterServer PRIVATE
   DllInstall  PRIVATE

 

5. IDL 파일도 한번 보죠. 낯 익은 코드군요. VC++ COM에서 형식 라이브러리와 관련해서 IDL에 작성해야 한다던 코드도 만들어져있군요. 정확한 내용은 모르겠지만, 왠지 낯익은 것들을 자동으로 만들어주니 편리 할 것 같은 느낌이 듭니다.

 // HelloServer.idl : HelloServer의 IDL 소스입니다.
//

 

// 이 파일은 MIDL 도구에 의해 처리되어
// 형식 라이브러리(HelloServer.tlb) 및 마샬링 코드가 생성됩니다.

 

import "oaidl.idl";
import "ocidl.idl";

 

[
    uuid(5B76AF09-0671-4B19-BE72-C9083C765FA9),
    version(1.0),
    helpstring("HelloServer 1.0 형식 라이브러리")
]
library HelloServerLib
{
    importlib("stdole2.tlb");
};

 

6. 그리고, 중요한 파일인데, ReadMe.txt라는 파일이 있습니다. 읽어 보라니 한번 보죠. 여기에는 생성 된 파일들에 대한 설명이 들어 있습니다. 공부할 때 많은 도움이 되겠군요.

 

그 외에, *.rgs라는 레지스트리 스크립트 파일도 있구요.

 

7. 가장 중요한 소스를 잠시 소개를 하면...

 

헤더에 다음과 같이 모듈을 선언하고 있습니다.

// dllmain.h : 모듈클래스의선언입니다.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

class CHelloServerModule : public CAtlDllModuleT< CHelloServerModule >

{

public :

        DECLARE_LIBID(LIBID_HelloServerLib)

        DECLARE_REGISTRY_APPID_RESOURCEID(IDR_HELLOSERVER, "{670982C1-2287-471A-A19B-A6481A5086CC}")

};

 

extern class CHelloServerModule _AtlModule;

 

우리가 만들 모듈을 템플릿으로 해서 클래스를 정의하고, 이를 전역으로 쓸 수 있도록 _AtlModule로 선언하였습니다.

 

cpp코드를 보면 더 재밌는(?) 사실이 있습니다.

코드가 길어 전부를 적을 수는 없고 몇개만 적어 보겠습니다.

 

...

// DLLOLE에의해언로드될수있는지결정하는데사용됩니다.

STDAPI DllCanUnloadNow(void)

{

    return _AtlModule.DllCanUnloadNow();

}

 

 

// 클래스팩터리를반환하여요청된형식의개체를만듭니다.

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)

{

    return _AtlModule.DllGetClassObject(rclsid, riid, ppv);

}

 

...

 

보시는 것 처럼 우리가 만들 COM의 모든 기능은 앞에서 ATL 템플릿으로 만든 객체로 처리를 하고 있습니다.

다시 말해, 우리는 우리가 만들 기능에만 집중하면 되는 것이지요.

----------------------------------

 

ATL COM 객체 생성

 

 궁극적으로 우리가 하고자 하는 것은 COM 객체를 만드는 것입니다. 앞에서 한 것은 이를 하기 위한 준비였습니다.

COM 객체를 추가해 보도록 하겠습니다.

 

1. 클래스를 추가 합니다. (VS2008화면)

 

2. ATL 단순 개체를 추가 합니다.

 

3. '약식이름'에 Hello라고 입력합니다. 그러면, 다른 이름들이 다 자동으로 들어갑니다. 물론 임의로 변경 해도 됩니다. 하지만, 그대로 두는 것이 나중에 확인하기 좋겠지요. 우리가 Cxxxx로 시작하면 클래스를 말하고, Ixxxx라고 하면 인터페이스를 말하는 것을 아는 것은 그 이름 자체가 기술적인 spec이기 때문이 아니라 이름에 대상의 특성을 담기로 한 보편적인 약속 때문이지요. 변수등의 표기법을 따르면 변수명만을 보고도 데이터 형을 알 수 있어, 코딩의 오류를 줄일 수도 있지요. 뭐 그런 의미의 보편적인 약속을 기본값으로 자동 설정해 주는 것이죠.

 

4. 다음 옵션 상자에서 '사용자 지정'을 선택 합니다. 이중 인터페이스는 자동화에서 다루게 된다고 합니다. 그 아래 Tool Tip을 보니 Vtable이라고 나오네요. 낮 익은 단어죠?!!

 

5. 이렇게 해서 등록을 하고 나면, 아래와 같이(왼쪽은 추가 전/ 오른쪽은 추가 후) 몇 개의 파일이 추가(빨간색)됩니다. 또한 추가 된 객체가 제공 할 인터페이스를 사용 할 수 있도록 idl 파일도 수정 됩니다.

 

 이 rgs 파일들은 레지스트리 스크립트인데, 앞에서 SetRegistryKey와 같은 역할을 해주지 않을까 예상 됩니다. 코드에 직접 넣는 것이 아니라 외부 스크립트로 만들어 실행하게끔...

 

Hello.h를 보면 앞에서 소개 한 VC++ COM의 예약어 등도 보이고, ATL 템플릿을 이용한 클래스 선언도 보입니다.

말 그대로 기본 틀만 잡혀져 있는 상태로 말이죠. 하지만, 이 틀도 직접 만들려면 큰 수고가 들어간다는 것을 이제 알고 있습니다.

Hello.cpp에는 헤더 파일 include 외엔 아직 아무런 코드가 없습니다.

 

idl 파일에는 아래 굵은 글씨 부분이 더 추가 되었습니다. 이번에 추가한 Hello 객체에 대한 내용인 것을 알 수 있습니다.

 

// HelloServer.idl : HelloServer의 IDL 소스입니다.
//

 

// 이 파일은 MIDL 도구에 의해 처리되어
// 형식 라이브러리(HelloServer.tlb) 및 마샬링 코드가 생성됩니다.

import "oaidl.idl";
import "ocidl.idl";

 

[
   object,
   uuid(9D5F134F-A593-4451-97DB-2FDCE45C08F2),
   helpstring("IHello 인터페이스"),
   pointer_default(unique)
]

interface IHello : IUnknown{
};


[
   uuid(5B76AF09-0671-4B19-BE72-C9083C765FA9),
   version(1.0),
   helpstring("HelloServer 1.0 형식 라이브러리")
]


library HelloServerLib
{
   importlib("stdole2.tlb");
   [
      uuid(FBA22F60-F3FB-4376-AF3C-A34DF460F260),
      helpstring("Hello Class")
   ]

   coclass Hello
  {
    [default] interface IHello;
  };
};

 

 레지스트리 스크립트에 대한 설명은 필요한 부분이 있을 것 같기도 한데, 일단 생략하도록 하겠습니다.

 오히려, 다른 곳에서 정확한 자료를 더 찾아 보시는 것이 더 유익 할 것 입니다.

 

컴파일을 해 보면 MIDL 컴파일 할 때 나왔던 것과 비슷한 로그도 보이고...(아니면 말고~ ㅋ)

뭐 그러네요~하하~

 

 이상으로 ATL의 개요에 대한 첫번째 순서를 마칩니다.

 여기까지 작성한 프로젝트를 첨부 합니다.

 

 다음에는 실제 ATL COM 객체를 구현 해 보겠습니다.


- Reference 

  http://cafe.naver.com/gisdev.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=936&