123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- #ifndef _ObjectMap_h__
- #define _ObjectMap_h__
- /////////////////////////////////////////////////////////////////////////////
- // Object Map Macros
- #ifdef _DOCJET_ONLY
- ///////////////////////////////////////////////////////////////////////////
- // Macro Group: TC_OBJECT Object Map Macros
- //
- // Declaration:
- // #define TC_OBJECT_EXTERN(theClass)
- // #define TC_OBJECT_EXTERN_IMPL(theClass)
- // #define TC_OBJECT_ENTRY(clsid, theClass)
- // #define TC_OBJECT_ENTRY_STD(theName)
- //
- // Parameters:
- // theClass - The name of the class that implements the component object.
- // clsid - The CLSID of the component object.
- // theName - The simple name of the component object. See the Remarks.
- //
- // Remarks:
- // The ATL framework uses the concept of an /Object/ /Map/ to associated a
- // component object CLSID with the static class method that is used to
- // create an instance of the C++ class that implements the object. The
- // object map is also used for automatic registration and unregistration of
- // each object listed. To simplify the maintenance of the object map, ATL
- // provides the *BEGIN_OBJECT_MAP*, *END_OBJECT_MAP*, *OBJECT_ENTRY*, and
- // *OBJECT_MAP_NONCREATEABLE* macros. The object map is declared with the
- // former two macros, and one *OBJECT_ENTRY* or
- // *OBJECT_MAP_NONCREATEABLE* macro is instantiated inside the map for
- // each component object implemented by the EXE or DLL module.
- //
- // The problem with the ATL *OBJECT_ENTRY* macros are that they refer to
- // *static* members of the component object C++ class. Because of this, it
- // is necessary for the CPP file that declares the object map to include
- // the H file declaration of each class. For a module that contains very
- // few component objects, this does not pose a great problem. But, for
- // modules that implement *many* component objects, the compile time for
- // the module's main CPP file (the one that declares the object map)
- // becomes extremely unbearable. Especially when you consider that the file
- // is dependent upon /every/ header file it includes, meaning that it must
- // be re-compiled even when only one of the header files changes. In
- // addition, I have encountered compiler heap limits in a DLL that had more
- // than 38 (or so) component objects.
- //
- // Upon close examination of the problem, I realized that *the* *only* „
- // *reason* the module's CPP file needs to include each class's H file is
- // to resolve the static member references. For global declarations, this
- // is easily resolved by declaring the global variables as *extern* in the
- // file that references them. A few attempts at declaring the
- // *static* members as *extern* proved futile. Either the C++ language
- // doesn't support it, the compiler doesn't support it, or my own
- // familiarity with such syntax is lacking. Regardless of the reason, the
- // *extern* global variable approach was sure to work. From this idea, the
- // TC_OBJECT macros were developed.
- //
- // To begin using the macros, first take a look at the module's main CPP
- // file (the one that declares the object map). Instead of including the
- // header file of each component object class declaration, use the
- // TC_OBJECT_EXTERN macro to declare the global variables as external:
- //
- // // #include "TCCodecAddress.h" <-- comment-out/remove this line
- // …
- // // External Declarations <-- Add this comment section
- // …
- // TC_OBJECT_EXTERN(CTCCodecAddress) // <-- Add this declaration
- //
- // Then, replace the *OBJECT_ENTRY* macro declaration with the
- // TC_OBJECT_ENTRY macro declaration. Notice that the ATL
- // *BEGIN_OBJECT_MAP* and *END_OBJECT_MAP* macros are still used to declare
- // the beginning and end of the object map:
- //
- // // Object Map
- // …
- // BEGIN_OBJECT_MAP(ObjectMap) // <-- Stays the same
- // TC_OBJECT_ENTRY(CLSID_TCCodecAddress, CTCCodecAddress)
- // END_OBJECT_MAP() // <-- Stays the same
- //
- // Note: Notice that the two parameters to the TC_OBJECT_ENTRY macros are
- // nearly identical, except for the prefixes. The object CLSID is the
- // simple name prefixed with *CLSID_* and the object class name is the
- // simple name prefixed with the letter *C*. When this is the case, the
- // following is an alternate way to list the object in the map, using the
- // TC_OBJECT_ENTRY_STD macro:
- //
- // TC_OBJECT_ENTRY_STD(TCCodecAddress)
- //
- // Now that the module's main CPP file references some external global
- // variables, the global variables have to actually be declared somewhere,
- // or else linker errors will result. The most logical place to put the
- // declarations is in the CPP file of the component object implementation:
- //
- // // Near the top of TCCodecAddress.cpp
- // …
- // // CTCCodecAddress
- // …
- // TC_OBJECT_EXTERN_IMPL(CTCCodecAddress)
- //
- // You would then repeat these steps for each component object implemented
- // by your module.
- //
- // Note: Since four static function pointers are declared global for each
- // TC_OBJECT_ENTRY or TC_OBJECT_ENTRY_STD macro used, this approach adds a
- // total of 16 bytes to the size of the module's global data segment for
- // each component object. This is hardly significant and the reduced
- // compile time is a fair tradeoff, but it does deserve to be noted here.
- // This may lead one to think that the macros should only be implemented
- // using the *extern* globals under _DEBUG builds; that release build
- // should use the stock ATL implementations. However, this still does not
- // address the problem of hitting the compiler heap limits after so many
- // object header files are included. So, it's probably best to leave the
- // macros the same for both _DEBUG and release builds.
- //
- // See Also: *BEGIN_OBJECT_MAP*, *END_OBJECT_MAP* „
- #define TC_OBJECT
- #endif // _DOCJET_ONLY
- /////////////////////////////////////////////////////////////////////////////
- // {secret}
- typedef HRESULT (WINAPI TC_UPDATEREGFUNC)(BOOL bRegister);
- typedef void (WINAPI TC_ObjectMainFunc)(bool bStarting);
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_EXTERN(theClass) \
- extern TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry; \
- extern _ATL_CREATORFUNC* g_pfn##theClass##_ClassFactoryCreator; \
- extern _ATL_CREATORFUNC* g_pfn##theClass##_Creator; \
- extern _ATL_DESCRIPTIONFUNC* g_pfn##theClass##_Description; \
- extern _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap; \
- extern TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain;
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_EXTERN_NON_CREATEABLE(theClass) \
- extern TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry; \
- extern _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap; \
- extern TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain;
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_EXTERN_IMPL(theClass) \
- TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry = \
- &theClass::UpdateRegistry; \
- _ATL_CREATORFUNC* g_pfn##theClass##_ClassFactoryCreator = \
- &theClass::_ClassFactoryCreatorClass::CreateInstance; \
- _ATL_CREATORFUNC* g_pfn##theClass##_Creator = \
- &theClass::_CreatorClass::CreateInstance; \
- _ATL_DESCRIPTIONFUNC* g_pfn##theClass##_Description = \
- &theClass::GetObjectDescription; \
- _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap = \
- &theClass::GetCategoryMap; \
- TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain = \
- &theClass::ObjectMain;
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_EXTERN_NON_CREATEABLE_IMPL(theClass) \
- TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry = \
- &theClass::UpdateRegistry; \
- _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap = \
- &theClass::GetCategoryMap; \
- TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain = \
- &theClass::ObjectMain;
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_ENTRY(clsid, theClass) \
- { \
- &clsid, \
- g_pfn##theClass##_UpdateRegistry, \
- g_pfn##theClass##_ClassFactoryCreator, \
- g_pfn##theClass##_Creator, \
- NULL, \
- 0, \
- g_pfn##theClass##_Description, \
- g_pfn##theClass##_GetCategoryMap, \
- g_pfn##theClass##_ObjectMain \
- },
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_ENTRY_NON_CREATEABLE(clsid, theClass) \
- { \
- &clsid, \
- g_pfn##theClass##_UpdateRegistry, \
- NULL, \
- NULL, \
- NULL, \
- 0, \
- NULL, \
- g_pfn##theClass##_GetCategoryMap, \
- g_pfn##theClass##_ObjectMain \
- },
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_ENTRY_STD(theName) \
- TC_OBJECT_ENTRY(CLSID_##theName, C##theName)
- /////////////////////////////////////////////////////////////////////////////
- // {partof:TC_OBJECT}
- #define TC_OBJECT_ENTRY_STD_NON_CREATEABLE(theName) \
- TC_OBJECT_ENTRY_NON_CREATEABLE(CLSID_##theName, C##theName)
- /////////////////////////////////////////////////////////////////////////////
- #endif // !_ObjectMap_h__
|