ObjectMap.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #ifndef _ObjectMap_h__
  2. #define _ObjectMap_h__
  3. /////////////////////////////////////////////////////////////////////////////
  4. // Object Map Macros
  5. #ifdef _DOCJET_ONLY
  6. ///////////////////////////////////////////////////////////////////////////
  7. // Macro Group: TC_OBJECT Object Map Macros
  8. //
  9. // Declaration:
  10. // #define TC_OBJECT_EXTERN(theClass)
  11. // #define TC_OBJECT_EXTERN_IMPL(theClass)
  12. // #define TC_OBJECT_ENTRY(clsid, theClass)
  13. // #define TC_OBJECT_ENTRY_STD(theName)
  14. //
  15. // Parameters:
  16. // theClass - The name of the class that implements the component object.
  17. // clsid - The CLSID of the component object.
  18. // theName - The simple name of the component object. See the Remarks.
  19. //
  20. // Remarks:
  21. // The ATL framework uses the concept of an /Object/ /Map/ to associated a
  22. // component object CLSID with the static class method that is used to
  23. // create an instance of the C++ class that implements the object. The
  24. // object map is also used for automatic registration and unregistration of
  25. // each object listed. To simplify the maintenance of the object map, ATL
  26. // provides the *BEGIN_OBJECT_MAP*, *END_OBJECT_MAP*, *OBJECT_ENTRY*, and
  27. // *OBJECT_MAP_NONCREATEABLE* macros. The object map is declared with the
  28. // former two macros, and one *OBJECT_ENTRY* or
  29. // *OBJECT_MAP_NONCREATEABLE* macro is instantiated inside the map for
  30. // each component object implemented by the EXE or DLL module.
  31. //
  32. // The problem with the ATL *OBJECT_ENTRY* macros are that they refer to
  33. // *static* members of the component object C++ class. Because of this, it
  34. // is necessary for the CPP file that declares the object map to include
  35. // the H file declaration of each class. For a module that contains very
  36. // few component objects, this does not pose a great problem. But, for
  37. // modules that implement *many* component objects, the compile time for
  38. // the module's main CPP file (the one that declares the object map)
  39. // becomes extremely unbearable. Especially when you consider that the file
  40. // is dependent upon /every/ header file it includes, meaning that it must
  41. // be re-compiled even when only one of the header files changes. In
  42. // addition, I have encountered compiler heap limits in a DLL that had more
  43. // than 38 (or so) component objects.
  44. //
  45. // Upon close examination of the problem, I realized that *the* *only* „
  46. // *reason* the module's CPP file needs to include each class's H file is
  47. // to resolve the static member references. For global declarations, this
  48. // is easily resolved by declaring the global variables as *extern* in the
  49. // file that references them. A few attempts at declaring the
  50. // *static* members as *extern* proved futile. Either the C++ language
  51. // doesn't support it, the compiler doesn't support it, or my own
  52. // familiarity with such syntax is lacking. Regardless of the reason, the
  53. // *extern* global variable approach was sure to work. From this idea, the
  54. // TC_OBJECT macros were developed.
  55. //
  56. // To begin using the macros, first take a look at the module's main CPP
  57. // file (the one that declares the object map). Instead of including the
  58. // header file of each component object class declaration, use the
  59. // TC_OBJECT_EXTERN macro to declare the global variables as external:
  60. //
  61. // // #include "TCCodecAddress.h" <-- comment-out/remove this line
  62. // …
  63. // // External Declarations <-- Add this comment section
  64. // …
  65. // TC_OBJECT_EXTERN(CTCCodecAddress) // <-- Add this declaration
  66. //
  67. // Then, replace the *OBJECT_ENTRY* macro declaration with the
  68. // TC_OBJECT_ENTRY macro declaration. Notice that the ATL
  69. // *BEGIN_OBJECT_MAP* and *END_OBJECT_MAP* macros are still used to declare
  70. // the beginning and end of the object map:
  71. //
  72. // // Object Map
  73. // …
  74. // BEGIN_OBJECT_MAP(ObjectMap) // <-- Stays the same
  75. // TC_OBJECT_ENTRY(CLSID_TCCodecAddress, CTCCodecAddress)
  76. // END_OBJECT_MAP() // <-- Stays the same
  77. //
  78. // Note: Notice that the two parameters to the TC_OBJECT_ENTRY macros are
  79. // nearly identical, except for the prefixes. The object CLSID is the
  80. // simple name prefixed with *CLSID_* and the object class name is the
  81. // simple name prefixed with the letter *C*. When this is the case, the
  82. // following is an alternate way to list the object in the map, using the
  83. // TC_OBJECT_ENTRY_STD macro:
  84. //
  85. // TC_OBJECT_ENTRY_STD(TCCodecAddress)
  86. //
  87. // Now that the module's main CPP file references some external global
  88. // variables, the global variables have to actually be declared somewhere,
  89. // or else linker errors will result. The most logical place to put the
  90. // declarations is in the CPP file of the component object implementation:
  91. //
  92. // // Near the top of TCCodecAddress.cpp
  93. // …
  94. // // CTCCodecAddress
  95. // …
  96. // TC_OBJECT_EXTERN_IMPL(CTCCodecAddress)
  97. //
  98. // You would then repeat these steps for each component object implemented
  99. // by your module.
  100. //
  101. // Note: Since four static function pointers are declared global for each
  102. // TC_OBJECT_ENTRY or TC_OBJECT_ENTRY_STD macro used, this approach adds a
  103. // total of 16 bytes to the size of the module's global data segment for
  104. // each component object. This is hardly significant and the reduced
  105. // compile time is a fair tradeoff, but it does deserve to be noted here.
  106. // This may lead one to think that the macros should only be implemented
  107. // using the *extern* globals under _DEBUG builds; that release build
  108. // should use the stock ATL implementations. However, this still does not
  109. // address the problem of hitting the compiler heap limits after so many
  110. // object header files are included. So, it's probably best to leave the
  111. // macros the same for both _DEBUG and release builds.
  112. //
  113. // See Also: *BEGIN_OBJECT_MAP*, *END_OBJECT_MAP* „
  114. #define TC_OBJECT
  115. #endif // _DOCJET_ONLY
  116. /////////////////////////////////////////////////////////////////////////////
  117. // {secret}
  118. typedef HRESULT (WINAPI TC_UPDATEREGFUNC)(BOOL bRegister);
  119. typedef void (WINAPI TC_ObjectMainFunc)(bool bStarting);
  120. /////////////////////////////////////////////////////////////////////////////
  121. // {partof:TC_OBJECT}
  122. #define TC_OBJECT_EXTERN(theClass) \
  123. extern TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry; \
  124. extern _ATL_CREATORFUNC* g_pfn##theClass##_ClassFactoryCreator; \
  125. extern _ATL_CREATORFUNC* g_pfn##theClass##_Creator; \
  126. extern _ATL_DESCRIPTIONFUNC* g_pfn##theClass##_Description; \
  127. extern _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap; \
  128. extern TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain;
  129. /////////////////////////////////////////////////////////////////////////////
  130. // {partof:TC_OBJECT}
  131. #define TC_OBJECT_EXTERN_NON_CREATEABLE(theClass) \
  132. extern TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry; \
  133. extern _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap; \
  134. extern TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain;
  135. /////////////////////////////////////////////////////////////////////////////
  136. // {partof:TC_OBJECT}
  137. #define TC_OBJECT_EXTERN_IMPL(theClass) \
  138. TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry = \
  139. &theClass::UpdateRegistry; \
  140. _ATL_CREATORFUNC* g_pfn##theClass##_ClassFactoryCreator = \
  141. &theClass::_ClassFactoryCreatorClass::CreateInstance; \
  142. _ATL_CREATORFUNC* g_pfn##theClass##_Creator = \
  143. &theClass::_CreatorClass::CreateInstance; \
  144. _ATL_DESCRIPTIONFUNC* g_pfn##theClass##_Description = \
  145. &theClass::GetObjectDescription; \
  146. _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap = \
  147. &theClass::GetCategoryMap; \
  148. TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain = \
  149. &theClass::ObjectMain;
  150. /////////////////////////////////////////////////////////////////////////////
  151. // {partof:TC_OBJECT}
  152. #define TC_OBJECT_EXTERN_NON_CREATEABLE_IMPL(theClass) \
  153. TC_UPDATEREGFUNC* g_pfn##theClass##_UpdateRegistry = \
  154. &theClass::UpdateRegistry; \
  155. _ATL_CATMAPFUNC* g_pfn##theClass##_GetCategoryMap = \
  156. &theClass::GetCategoryMap; \
  157. TC_ObjectMainFunc* g_pfn##theClass##_ObjectMain = \
  158. &theClass::ObjectMain;
  159. /////////////////////////////////////////////////////////////////////////////
  160. // {partof:TC_OBJECT}
  161. #define TC_OBJECT_ENTRY(clsid, theClass) \
  162. { \
  163. &clsid, \
  164. g_pfn##theClass##_UpdateRegistry, \
  165. g_pfn##theClass##_ClassFactoryCreator, \
  166. g_pfn##theClass##_Creator, \
  167. NULL, \
  168. 0, \
  169. g_pfn##theClass##_Description, \
  170. g_pfn##theClass##_GetCategoryMap, \
  171. g_pfn##theClass##_ObjectMain \
  172. },
  173. /////////////////////////////////////////////////////////////////////////////
  174. // {partof:TC_OBJECT}
  175. #define TC_OBJECT_ENTRY_NON_CREATEABLE(clsid, theClass) \
  176. { \
  177. &clsid, \
  178. g_pfn##theClass##_UpdateRegistry, \
  179. NULL, \
  180. NULL, \
  181. NULL, \
  182. 0, \
  183. NULL, \
  184. g_pfn##theClass##_GetCategoryMap, \
  185. g_pfn##theClass##_ObjectMain \
  186. },
  187. /////////////////////////////////////////////////////////////////////////////
  188. // {partof:TC_OBJECT}
  189. #define TC_OBJECT_ENTRY_STD(theName) \
  190. TC_OBJECT_ENTRY(CLSID_##theName, C##theName)
  191. /////////////////////////////////////////////////////////////////////////////
  192. // {partof:TC_OBJECT}
  193. #define TC_OBJECT_ENTRY_STD_NON_CREATEABLE(theName) \
  194. TC_OBJECT_ENTRY_NON_CREATEABLE(CLSID_##theName, C##theName)
  195. /////////////////////////////////////////////////////////////////////////////
  196. #endif // !_ObjectMap_h__