아... 천하의 정성태가. ^^; 논리 버그도 아닌, 컴파일러 에러에 이렇게 시간을 허비했다니... 부끄러울 따름입니다.
어느 날... 기존 구현된 COM 개체의 인터페이스와 그 메서드들이 제공하는 기능을 구현해야 할 일이 생겼습니다.
그런데, 컴파일 단계에서 다음과 같은 오류가 발생하는 것이었습니다.
e:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(2578) : error C2259: 'ATL::CComObject<Base>' : cannot instantiate abstract class
with
[
Base=CXApplication
]
due to following members:
'HRESULT IXApplication2::IsDestinationReachable(BSTR,VARIANT_BOOL *)' : is abstract
d:\workshop\infopath\DxDocsViewer\DxDocsViewer.h(7595) : see declaration of 'IXApplication2::IsDestinationReachable'
e:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(2570) : while compiling class template member function 'HRESULT ATL::CComObject<Base>::CreateInstance(ATL::CComObject<Base> **) throw()'
with
[
Base=CXApplication
]
d:\workshop\infopath\DxDocsViewer\DocsServer.h(500) : see reference to class template instantiation 'ATL::CComObject<Base>' being compiled
with
[
Base=CXApplication
]
다들 익히 아시는 거지요? ^^ 자... 찬찬히 살펴보겠습니다.
우선, IDL 파일에는 다음과 같은 인터페이스를 정의했습니다.
[
object,
uuid(096CD6BB-0786-11D1-95FA-0080C78EE3BB),
dual,
nonextensible,
helpstring("IXApplication2 Interface"),
pointer_default(unique)
]
interface IXApplication2 : IXApplication
{
[id(0x00000010)] HRESULT IsDestinationReachable([in] BSTR bstrDestination, [out, retval] VARIANT_BOOL *pfReachable);
};
그리고는, 해당 인터페이스를 구현하는 ATL COM 개체의 헤더 파일에는 다음과 같이 정의했습니다.
STDMETHOD( IsDestinationReachable )(BSTR bstrDestination, VARIANT_BOOL *pfReachable)
{
return E_NOTIMPL;
}
그런데... 그와 같은 컴파일 오류가 발생한 것입니다. 여러분들은 어떻게 생각하십니까? ^^; 제가 뭐 잘못한 거라도 있는 걸까요?
정말이지... 컴파일 에러에서 고심한다고,,, 챙피해서 주변에 도움을 구할 수도 없고... ^^;
요리 저리 해보다가... ^^; 결국 문제가 밝혀지긴 했습니다.
제가 기능 구현을 위해 포함시켜 두었던
#include <sensapi.h>
가 문제였지요.
바로 그 헤더 파일에 동일한 이름의 메서드가 선언되었던 것입니다. 물론... 메서드 선언만이었다면 그런 문제는 발생하지 않았을 것입니다. 즉,
BOOL IsDestinationReachable( LPCSTR lpszDestination, LPQOCINFO lpQOCInfo);
위의 선언이라면 컴파일 에러가 발생하지 않았을 텐데.
윈도우 헤더 파일의 특기인 Ansi / Unicode API 지원을 위해 정의해 두었던 매크로 들과 겹쳐서 문제가 되었던 것입니다.
#ifdef UNICODE
#define IsDestinationReachable IsDestinationReachableW
#else
#define IsDestinationReachable IsDestinationReachableA
#endif // UNICODE
보통 위와 같은 트릭을 많이 쓰죠.
위의 매크로 영향으로 인해서, 제가 정의했던 메서든 다음과 같이 치환이 되었고,
STDMETHOD( IsDestinationReachableA )(BSTR bstrDestination, VARIANT_BOOL *pfReachable)
{
return E_NOTIMPL;
}
결국, IDL 에서 정의한 인터페이스 명세대로 IsDestinationReachable 메서드를 구현하지 않았으므로 컴파일러는 그와 같은 오류를 발생시킨 것입니다.