| < Free Open Study > |
This single ATL class contains
Secondary creation and post destruction calls for the CComModule instance.
Maintaining the number of server locks and active objects in the server.
Performing registration and unregistration
Retrieving class factories for
Every ATL COM server contains a single global instance of CComModule named _Module. ATL's implementation of DllMain() calls CComModule::Init() or CComModule::
// ATL in-proc servers initialize and terminate _Module via DllMain() BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) { if (dwReason ==
DLL_PROCESS_ATTACH
) { _Module.
Init
(ObjectMap, hInstance, &LIBID_ATLSHAPESLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason ==
DLL_PROCESS_DETACH
) { _Module.
Term
(); } return TRUE; // ok }
ATL EXE servers call the same methods within the scope of _tWinMain(). Regardless of the type of component housing, these methods are used to set the internal state of the global level CComModule object (_Module) and deallocate any
CComModule::Init() takes three parameters: the object map (which is an array of _ATL_OBJMAP_ENTRY structures, hence _ATL_OBJMAP_ENTRY*), the instance of the DLL or EXE module, and the LIBID that defines the classes and interfaces defined in the server. If the LIBID is NULL, ATL assumes the *.tlb defined by your project contains the necessary information:
// Pass in object map, DLL/EXE instance, and LIBID to the CComModule object. HRESULT Init ( _ATL_OBJMAP_ENTRY* p, // The object map. HINSTANCE h, // Module instance. const GUID* plibid = NULL) // LIBID.
CComModule::Term() takes no parameters, and is called when the server itself (DLL or EXE) is being removed from memory:
// Clean up CComModule instance when server is going down. void Term ( );
CComModule provides a number of methods used to monitor the number of server locks and currently active objects. When we were building in-proc servers by hand, we
// Active object/lock methods of CComModule. LONG Lock(); // Increments m_nLockCnt. LONG Unlock(); // Decrements m_nLockCnt. LONG GetLockCount(); // Returns current value of m_nLockCnt. LONG m_nLockCnt; // Active objects + server locks.
As we have seen, ATL DLLs make use of GetLockCount() from within the DllCanUnloadNow() export:
// The lock count is represented by m_nLockCnt and obtained via GetLockCount(). STDAPI DllCanUnloadNow(void) { return (_Module.
GetLockCount
()==0) ? S_OK : S_FALSE; }
Registration of your COM server is also handled by methods of CComModule. Both CComModule::RegisterServer() and CComModule::UnregisterServer() define a defaulted NULL LPCLSID parameter, which informs ATL to enter (or remove) registry information for every coclass contained in the server-wide object map.
ATL allows you to tweak the behavior of the server's (un)registration. If you wish to insert or remove registry information on a more selective coclass-by-coclass basis, set the default NULL LPCLSID parameter to a specific
// Enter/remove server information for each entry in the object map. HRESULT RegisterServer (BOOL bRegTypeLib = FALSE, CLSID* pCLSID = NULL ); HRESULT UnregisterServer (BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL);
For in-proc servers, these methods are called from the DllRegisterServer() and DllUnregisterServer() exports:
// DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { // Registers object, typelib, and all interfaces in typelib return _Module.
RegisterServer
(TRUE); } // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { return _Module.
UnregisterServer
(TRUE); }
A handful of CComModule methods are used to create class factories per client request. Given what you already know about class factories created by DLL and EXE servers, I'd bet you could decipher the following CComModule methods:
// Return an IClassFactory pointer for a client (DLL servers only) HRESULT GetClassObject ( REFCLSID rclsid, REFIID riid, LPVOID* ppv ); // Register a class object to the class table (EXE servers only) HRESULT RegisterClassObjects ( DWORD dwClsContext, DWORD dwFlags ); // Remove a class object from the class table (EXE servers only) HRESULT RevokeClassObjects ( );
As mentioned, the ATL COM AppWizard will always generate a global instance of CComModule named _Module. Don't start to get clever and attempt to rename this instance, as ATL source code is looking for this object by
// The single CComModule instance (DLL servers). CComModule _Module;
EXE servers do not create an instance of CComModule directly. Rather, the ATL COM AppWizard will create an instance of a class named CExeModule, which is derived from CComModule. CExeModule inherits the
// The single CExeModule instance (EXE servers). CExeModule _Module;
The reason ATL subclasses a new class from CComModule is to keep the amount of
| < Free Open Study > |