由于有3种COM Server,ATL提供了CAtlModule的派生类对应
CAtlDllModuleT:in-process dll
CAtlExeModuleT:out-process exe
CAtlServiceModuleT:system service exe
CAtlModule使用了Object Map管理server中所有的类
CAtlModule的职责
找到每个class,注册/反注册
为每个createable class创建class object
在SCM中注册/反注册class object
为一个class查找component categories
调用class的静态初始化和静态终结函数
注册Server
Inproc Server Registration
template <class T> class ATL_NO_VTABLE CAtlDllModuleT : public CAtlModuleT<T> { public: ... HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) { ... T* pT = static_cast<T*>(this); HRESULT hr = pT->RegisterAppId(); // execute server script ... return hr; } ... };
Local Server and Windows Service Registration
template <class T> class CAtlExeModuleT : public CAtlModuleT<T> { public : int WinMain(int nShowCmd) throw() { ... HRESULT hr = S_OK; LPTSTR lpCmdLine = GetCommandLine(); if (pT->ParseCommandLine(lpCmdLine, &hr) == true) hr = pT->Run(nShowCmd); ... } bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { *pnRetCode = S_OK; TCHAR szTokens[] = _T("-/"); T* pT = static_cast<T*>(this); LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens); while (lpszToken != NULL) { if (WordCmpI(lpszToken, _T("UnregServer"))==0) { *pnRetCode = pT->UnregisterServer(TRUE); // server script if (SUCCEEDED(*pnRetCode)) *pnRetCode = pT->UnregisterAppId(); // all class scripts return false; } // Register as Local Server if (WordCmpI(lpszToken, _T("RegServer"))==0) { *pnRetCode = pT->RegisterAppId(); // server script if (SUCCEEDED(*pnRetCode)) *pnRetCode = pT->RegisterServer(TRUE); // all class scripts return false; } lpszToken = FindOneOf(lpszToken, szTokens); } return true; } };
The Object Map
每一个createable class都类似:
class CMyClass : public CComCoClass< ... >, ... { public: ... }; OBJECT_ENTRY_AUTO(__uuidof(MyClass), CMyClass) //第一个参数是clsid
在ATL3中,我们使用BEGIN_OBJECT_MAP和END_OBJECT_MAP,到了ATL7之后不再需要了。
_ATL_OBJMAP_ENTRY Structure
Object Map就是一个_ATL_OBJMAP_ENTRY的数组:
struct _ATL_OBJMAP_ENTRY30 { const CLSID* pclsid; //CLSID HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);//用于注册 _ATL_CREATORFUNC* pfnGetClassObject; //用于创建class object _ATL_CREATORFUNC* pfnCreateInstance; //用于创建instance IUnknown* pCF; //class object的IUnknown* DWORD dwRegister; //CoRegisterClassObject的cookie返回 _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription; //用于返回object description _ATL_CATMAPFUNC* pfnGetCategoryMap; //用于component category void (WINAPI *pfnObjectMain)(bool bStarting); //initilization/termination function }; typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY;
OBJECT_ENTRY_AUTO Macro
当我们使用这个宏来指定COM-createable class,默认情况下这个类需要派生自CComCoClass,然后用户可以使用CoCreateInstance()来创建它们
OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO macro
使用这个宏用于noncreateable class,如果这个类需要class-level initialization/termination或者在注册表注册
Methods Required of an Object Map Class
为了支持Object Map,用户需要提供下列函数:
Static Member Function | Description |
---|---|
UpdateRegistry | Registers and unregisters the class. The DECLARE_REGISTRY_RESOURCE macros provide various implementations of this method for nonattributed projects. Attributed projects have an implementation injected by the attribute provider. |
ObjectMain | Initializes and uninitializes the class. CComObjectRootBase provides a default implementation of this method. |
GetCategoryMap | Returns a pointer to a component category map. The BEGIN_CATEGORY_MAP macro provides an implementation.CComObjectRootBase provides a default implementation of this method. |
CreatorClass::CreateInstance | _The DECLARE_AGGREGATABLE macros set the _CreatorClass typedef to the name of the class that creates instances. CComCoClass provides a default definition of this typedef. |
_ClassFactoryCreatorClass:: CreateInstance | The DECLARE_CLASSFACTORY macros set the _ClassFactoryCreatorClass typedef to the name of the class that creates class objects.CComCoClass provides a default definition of this typedef. |
GetObjectDescription | Returns the object description text string. CComCoClass provides a default implementation of this method. |
其中前三条不管使用OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO还是OBJECT_ENTRY_AUTO都必须提供
使用OBJECT_ENTRY_AUTO必须提供所有
The GetObjectDescription Method
使用DECLARE_OBJECT_DESCRIPTION macro,例如:
class CMyClass : public CComCoClass< ... >, ... { public: DECLARE_OBJECT_DESCRIPTION("MyClass Object Description") ... };
The UpdateRegistry Method
class必须提供一个静态函数:
static HRESULT WINAPI UpdateRegistry(BOOL bRegister) ;
可以使用DECLARE_REGISTRY:
#define DECLARE_NO_REGISTRY()\ static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) \ {return S_OK;} #define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\ static HRESULT WINAPI UpdateRegistry(BOOL bRegister) {\ return _Module.UpdateRegistryClass(GetObjectCLSID(), \ pid, vpid, nid,\ flags, bRegister);\ } #define DECLARE_REGISTRY_RESOURCE(x)\ static HRESULT WINAPI UpdateRegistry(BOOL bRegister) {\ ... return ATL::_pAtlModule->UpdateRegistryFromResource(_T(#x), \ bRegister); \ ... } #define DECLARE_REGISTRY_RESOURCEID(x)\ static HRESULT WINAPI UpdateRegistry(BOOL bRegister) {\ ... return ATL::_pAtlModule->UpdateRegistryFromResource(x, \ bRegister); \ ... }
注意,DECLARE_REGISTRY只能在ATL3中使用,在ATL7+版本将会出现编译错误
如果使用DECLARE_REGISTRY_RESOURCE或者使用DECLARE_REGISTRY_RESOURCEID,需要指定脚本,详见原书
The GetCategoryMap Method
需要一个静态函数:
static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() { return NULL; }
通常可以使用宏来解决,例如:
// {0D22FF22-28CC-11d2-ABDD-00A0C9C8E50D} static const GUID CATID_ATLINTERNALS_SAMPLES = {0xd22ff22, 0x28cc, 0x11d2, {0xab, 0xdd, 0x0, 0xa0, 0xc9, 0xc8, 0xe5, 0xd}}; BEGIN_CATEGORY_MAP(CDemagogue) IMPLEMENTED_CATEGORY(CATID_ATLINTERNALS_SAMPLES) END_CATEGORY_MAP()
这3个宏详见原书
The ObjectMain Method
需要一个静态函数:
static void WINAPI ObjectMain(bool /* bStarting */ ) {};
例如:
class ATL_NO_VTABLE CSoapBox :
public CComObjectRootEx<CComSingleThreadModel>,
...
{
public:
DECLARE_NO_REGISTRY()
...
static void WINAPI ObjectMain(bool bStarting) ;
};
The _ClassFactoryCreatorClass and _CreatorClass Typedefs
OBJECT_ENTRY_AUTO中
class::_ClassFactoryCreatorClass::CreateInstance用于创建class object
class::_CreatorClass::CreateInstance用于创建instance
在CComCoClass中,有_ClassFactoryCreatorClass定义:
template <class T, const CLSID* pclsid = &CLSID_NULL> class CComCoClass { public: DECLARE_CLASSFACTORY() DECLARE_AGGREGATABLE(T) ... };
其中:
#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory) 1 #if defined(_WINDLL) | defined(_USRDLL) #define DECLARE_CLASSFACTORY_EX(cf) \ typedef ATL::CComCreator< \ ATL::CComObjectCached< cf > > _ClassFactoryCreatorClass; #else // don't let class factory refcount influence lock count #define DECLARE_CLASSFACTORY_EX(cf) \ typedef ATL::CComCreator< \ ATL::CComObjectNoLock< cf > > _ClassFactoryCreatorClass; #endif
上面的代码,当使用inproc dll时,CComCreator创建一个CComObjectCached<>作为cf,当使用exe时,创建一个CComObjectNoLock<>作为cf
而其中的CComClassFactory定义如下:
class CComClassFactory : public IClassFactory, public CComObjectRootEx<CComGlobalsThreadModel> { public: ... void SetVoid(void* pv) { m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;} _ATL_CREATORFUNC* m_pfnCreateInstance; };
上面SetVoid重载了CComObjectRootBase中的定义