궁극적으로 우리가 만들어야 할 것은 COM 사용 환경이 아니라 COM 객체이죠.
한번 만들어 보겠습니다.
1. 앞의 예에서 계속 사용 한 것 처럼 sayHello를 만들겠습니다. 인터페이스에 메서드를 추가 합니다.
2. 매개 변수 형식과 변수 특성 등을 선택하고 추가를 누릅니다.
3. 이런 방법으로 입출력용 인자 두개를 등록 합니다.
4. 추가 한 후, idl 파일에서 살펴보면 어떻게 추가 되어 있는지 볼 수 있습니다. 클래스에 함수 추가하는 것과 크게 다르지 않습니다만 인자에 특성이 들어가는 것과 만들어진 결과가 그냥 헤더 파일의 함수 선언과는 좀 다르다는 점이 있지요.
또한, CHello에도 같은 이름으로 헤더 파일과 소스에 해당 메서드가 추가 되었습니다. 즉, 이 클래스에 정의 된 함수 중 외부로 서비스를 제공하는 인터페이스가 되는 경우에는 IDL을 통해 인터페이스가 생성되는 것이죠. 외부와 인터페이스 역할을 하지 않을 함수라면 IDL 파일에 추가 될 필요 없이 해당 클래스에서만 선언해서 쓰면 됩니다.
이런 이유로, 인터페이스에 추가한 메서드는 IDL 및 해당 클래스에 각각 코드가 추가가 되는 것이죠.
헤더 파일에 선언
public:
STDMETHOD(sayHello)(wchar_t* name, wchar_t** message);
소스 파일에 정의
STDMETHODIMP CHello::sayHello(wchar_t* name, wchar_t** message)
{
//
TODO: 여기에 구현 코드를 추가합니다.
return S_OK;
}
5. 실제 구현 할 코드를 입력해 보겠습니다. 아래 주석처리 된 문장들은 책의 본문이고, VS2008에서는 char* 대신 LPWSTR을 써줘야 합니다. 역시 항상 신경쓰이는 문자열처리~~~
STDMETHODIMP
CHello::sayHello(wchar_t* name, wchar_t** message)<?xml:namespace prefix = o ns =
"urn:schemas-microsoft-com:office:office" />
{
// TODO:
여기에구현코드를추가합니다.
//char*
buffer = (char*)::CoTaskMemAlloc(256);
LPWSTR buffer =
(LPWSTR)::CoTaskMemAlloc(256);
if(buffer==NULL)
return E_FAIL;
//::wsprintf(buffer, "Hello~
%s!",name);
::wsprintf(buffer, L"Hello~ %s!",name);
*message = (wchar_t*)buffer;
return
S_OK;
}
이렇게 하면 됩니다~ 편리하지요~
이제 ATL에 대해서 조금 더 깊게 알아 보겠습니다.
제법 많은 양이니, 간단히 요약하는 정도로 하겠습니다. 자세한 것은 책을 참고 하시고~
그 동안, 너무 언급을 안해서 간만에 언급을 하자면...
이 연재는 '전병선의 'Component Development with Visual C++ & ATL'이라는 책을 읽으며 작성하고 있습니다.
설명이 부족한 부분은 책을 통해 정확히 확인 하시기 바랍니다.
ATL 기반 클래스
글 쓰신 분이 지치신 걸까요?? 아니면, 제가 지친 걸까요? ㅎㅎ
여기 부터의 내용은 쉽게 잘 읽어지지가 않았어요. 뭐랄까...뭔가 잔뜩 설명은 있는데 눈으로는 보이나 머리속으로는 들어오지 않는 듯한...IUnknown을 볼때와 비슷하군요.ㅋ
COM Module
앞에서 ATL 프로젝트를 만들 때 다음의 옵션을 보았습니다.
이 옵션에 따라, 모듈 클래스가 상속받는 부모 클래스가 달라지게 됩니다. 당연히 달라야 할텐데 상속을 통해 구현하고 있다는 점을 알고 있으면 좋을 것 같네요.
DLL - CAtlDllModuleT
실행EXE - CAtlExeModuelT
서비스EXE - CAtlServiceModuleT
끝에 붙은 T는 템플릿을 의미하는 것 같네요.
각각은 스타일에 맞게 익스포트 함수를 노출하기도 하고, ROT에 클래스 팩토리를 등록/해제하고, 서비스를 실행하는데 필요한 여러가지 코드가 있습니다.
COM 객체 기초 클래스
앞에서는 COM module을 봤고, 이제 COM 객체를 살펴봅시다.
class ATL_NO_VTABLE CHello : |
위와 같이 클래스가 만들어 집니다.
두 개의 클래스로부터 다중 상속을 받고 있는데..
CComObjectRootEx는 IUnknow인터페이스의 내부 구현 코드를 제공하고
CComCoClass는 COM 객체의 디폴트 클래스 팩토리 COM 객체를 정의 합니다.
CComObjectRootEx에서 뒤에 템플릿으로 쓰레드 모델을 넘겨주고 있는데 이는 우리가 처음 프로젝트를 선택 할 때 지정한 옵션에 따라 정해집니다. 일단, 멀티 쓰레드는 생각하지 말도록 하겠습니다.
위와 같이 상속을 받았지만 인터페이스의 가장 기본이 되는 AddRef, Release, QueryInterface는 재정의 되어 있지 않습니다. 이는 우리가 정의한 클래스를 다시 상속받아서 CComObject 템플릿 클래스에서 재정의 됩니다.
자료를 찾다보니 ESRI에서 제공하는 SDK의 설명에 좋은 그림이 있군요.
http://edndoc.esri.com/arcobjects/9.1/ArcGISDevHelp/DevelopmentEnvs/COM/VCpp/ATLDiscussion.htm
이 두개의 기반 클래스에는 InternalAddRef, InternalRelease, InternalQueryInterface 메서드를 통해 레퍼런스 카운트와 인터페이스 조회 기능을 구현 합니다. Internal~~~ 말고 Outer~~~도 있는데 이는 통합(Aggregation)으로 사용 될 때 사용된다고 합니다.
...
통합...
...
낯익은 단어인데 잘 모르겠더라구요. 찾아보니 뒤에서 설명하겠다고 하며 앞에서 나온 내용이었어요. 아직 설명이 나올 거기가 아니라서 몰랐군요.ㅋ. 재사용 부분에서 좀 더 자세히 다루게 될 것 입니다.
COM 객체 클래스 선언부에는 BEGIN_COM_MAP/ END_COM_MAP 매크로로 구성되는 COM맵이 있습니다. 이것은 흡사 MFC 프로그래밍 할 때 메세지 맵과 매우 비슷해 보이는군요.
저기 선언 된 순서대로 QueryInterface 메서드에서 인터페이스를 찾아보게 됩니다.
그런데, 우리가 만든 COM 객체를 상속받아 AddRef와 Release, QueryInterface를 재정의 할 CComObject는 어디 있는 것일까요??? 찾을 수가 없군요.ㅋㅋ..보다보면 나오겠지요.
COM 객체의 부모 클래스에 대한 좀 더 자세한 설명이 나오긴 하는데 일단, 큰 그림이 없이 코드 한 줄, 한 줄에 대한 설명을 들으니 잘 이해가 안되네요. 일단 패스하고 전반적인 개념이 좀 잡히면 다시 심화 학습을 하도록 하죠.
정리를 좀 하면...
ATL에서 COM 객체는 두 개의 기반 클래스를 상속받아 만들어지며, 이 기반 클래스 덕분에 많은 수고를 덜고 있으며, 실제로 필요한 메서드를 재정의 하기 위해 우리가 정의한 COM 객체를 다시 상속받는 템플릿 클래스가 추가 됩니다.
이렇게 해서 COM 객체가 ATL의 도움으로 편리하게 만들어진다는 정도만 알고 넘어가겠습니다.
다음에는 앞에서 많이 다루었던 스마트 포인터에 대해서 소개 합니다. 같은 내용은 아니고 ATL에서 이 역할을 어떻게 해주느냐 하는 내용이죠. 물론, 더 편리한 방법을 제시하겠지요??
'[ Windows Program ] > ActiveX / COM' 카테고리의 다른 글
[COM] 31. ATL의 개요 (1) - 프로젝트와 객체의 생성 (0) | 2011.03.17 |
---|