Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

572 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: combase.h
  4. //
  5. // Contents: IUnknown and COM server declarations.
  6. //
  7. // Using this file:
  8. //
  9. // 1. For each C++ class you want to expose as a COM object, derive from
  10. //
  11. // CComObjectRootImmx - standard COM object
  12. // CComObjectRootImmx_NoDllAddRef - internal COM object
  13. // CComObjectRootImmx_InternalReference - internal/external object
  14. // CComObjectRoot_CreateInstance - standard COM object, exposed directly
  15. // from class factory.
  16. // CComObjectRoot_CreateInstanceSingleton - standard COM object, exposed
  17. // directly from class factory, one instance per thread.
  18. // CComObjectRoot_CreateInstanceSingleton_Verify - standard COM object,
  19. // exposed directly from class factory, one instance per thread.
  20. // Includes callback to fail create instance for custom reasons,
  21. // and a callback after the singleton is successfully created.
  22. //
  23. // 2. For each C++ class, declare the interfaces exposed by QueryInterface
  24. // using the BEGIN_COM_MAP_IMMX macro. IUknown will be automatically mapped
  25. // to the first interface listed. The IUnknown methods are implemented by
  26. // the BEGIN_COM_MAP_IMMX macro.
  27. //
  28. // 3. Use the BEGIN_COCLASSFACTORY_TABLE macro to declare the COM objects you
  29. // want to expose directly from the class factory.
  30. //
  31. // 4. Implement DllInit(), DllUninit(), DllRegisterServerCallback(),
  32. // DllUnregisterServerCallback(), and GetServerHINSTANCE.
  33. // Behavior commented next to the prototypes below.
  34. //
  35. // Example:
  36. //
  37. // // this class is exposed by the class factory
  38. // class MyCoCreateableObject : public ITfLangBarItemMgr,
  39. // public CComObjectRoot_CreateInstance<MyCoCreateableObject>
  40. // {
  41. // MyCoCreateableObject();
  42. //
  43. // BEGIN_COM_MAP_IMMX(MyCoCreateableObject)
  44. // COM_INTERFACE_ENTRY(ITfLangBarItemMgr)
  45. // END_COM_MAP_IMMX()
  46. // };
  47. //
  48. // // this class is only exposed indirectly, through another interface
  49. // class MyObject : public ITfLangBarItemMgr,
  50. // public CComObjectRootImmx
  51. // {
  52. // MyCoCreateableObject();
  53. //
  54. // BEGIN_COM_MAP_IMMX(MyObject)
  55. // COM_INTERFACE_ENTRY(ITfLangBarItemMgr)
  56. // END_COM_MAP_IMMX()
  57. // };
  58. //
  59. // // in .cpp file, declare the objects exposed through the class factory
  60. // // along with thier clsid and description. Currently the apartment
  61. // // threading model is assumed.
  62. // BEGIN_COCLASSFACTORY_TABLE
  63. // DECLARE_COCLASSFACTORY_ENTRY(CLSID_TF_LangBarItemMgr, MyCoCreateableObject::CreateInstance, TEXT("TF_LangBarItemMgr"))
  64. // END_COCLASSFACTORY_TABLE
  65. //
  66. // // finally implement DllInit(), DllUninit(), DllRegisterServerCallback(),
  67. // // DllUnregisterServerCallback(), and GetServerHINSTANCE.
  68. //----------------------------------------------------------------------------
  69. #ifndef UNKNOWN_H
  70. #define UNKNOWN_H
  71. #include "private.h"
  72. #ifdef __cplusplus
  73. //+---------------------------------------------------------------------------
  74. //
  75. // extern prototypes that the server dll must implement
  76. //
  77. //----------------------------------------------------------------------------
  78. // Called on every new external object reference.
  79. BOOL DllInit(void);
  80. // Called when an external reference goes away.
  81. void DllUninit(void);
  82. // Should return the server dll's HINSTANCE.
  83. HINSTANCE GetServerHINSTANCE(void);
  84. // Should return a mutex callable whenever the server ref count changes (i.e. not during DllMain).
  85. CRITICAL_SECTION *GetServerCritSec(void);
  86. //+---------------------------------------------------------------------------
  87. //
  88. // COM server export implementations.
  89. //
  90. //----------------------------------------------------------------------------
  91. HRESULT COMBase_DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppvObj);
  92. HRESULT COMBase_DllCanUnloadNow(void);
  93. HRESULT COMBase_DllRegisterServer(void);
  94. HRESULT COMBase_DllUnregisterServer(void);
  95. //+---------------------------------------------------------------------------
  96. //
  97. // CComObjectRootImmx_NoDllAddRef
  98. //
  99. // Use this base class if you don't want your COM object to AddRef the server.
  100. // Typically you DON'T want to do this.
  101. //----------------------------------------------------------------------------
  102. class CComObjectRootImmx_NoDllAddRef
  103. {
  104. public:
  105. CComObjectRootImmx_NoDllAddRef()
  106. {
  107. // Automatic AddRef().
  108. m_dwRef = 1L;
  109. #ifdef DEBUG
  110. m_fTraceAddRef = FALSE;
  111. #endif
  112. }
  113. protected:
  114. virtual BOOL InternalReferenced()
  115. {
  116. return FALSE;
  117. }
  118. void DebugRefBreak()
  119. {
  120. #ifdef DEBUG
  121. if (m_fTraceAddRef)
  122. {
  123. DebugBreak();
  124. }
  125. #endif
  126. }
  127. long m_dwRef;
  128. #ifdef DEBUG
  129. BOOL m_fTraceAddRef;
  130. #endif
  131. };
  132. //+---------------------------------------------------------------------------
  133. //
  134. // CComObjectRootImmx
  135. //
  136. // Use this base class for standard COM objects.
  137. //----------------------------------------------------------------------------
  138. class CComObjectRootImmx : public CComObjectRootImmx_NoDllAddRef
  139. {
  140. public:
  141. CComObjectRootImmx()
  142. {
  143. void DllAddRef(void);
  144. DllAddRef();
  145. }
  146. ~CComObjectRootImmx()
  147. {
  148. void DllRelease(void);
  149. DllRelease();
  150. }
  151. };
  152. //+---------------------------------------------------------------------------
  153. //
  154. // CComObjectRootImmx_InternalReference
  155. //
  156. // Use this base class for COM objects that have an "internal reference".
  157. //
  158. // With this base class, the server will only be AddRef'd if the object
  159. // ref count reaches 2. The server will be Release'd when the object
  160. // ref count returns to 1. This allows the object to be held internally
  161. // (and even released in DllMain) while still allowing outside references.
  162. //----------------------------------------------------------------------------
  163. class CComObjectRootImmx_InternalReference : public CComObjectRootImmx_NoDllAddRef
  164. {
  165. public:
  166. CComObjectRootImmx_InternalReference() {}
  167. BOOL InternalReferenced()
  168. {
  169. return TRUE;
  170. }
  171. };
  172. typedef BOOL (*VERIFYFUNC)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj);
  173. typedef void (*POSTCREATE)(REFIID riid, void *pvObj);
  174. // helper function, don't call this directly
  175. template<class DerivedClass>
  176. static HRESULT Unk_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj, VERIFYFUNC pfnVerify, POSTCREATE pfnPostCreate)
  177. {
  178. DerivedClass *pObject;
  179. HRESULT hr;
  180. if (ppvObj == NULL)
  181. return E_INVALIDARG;
  182. *ppvObj = NULL;
  183. if (pUnkOuter != NULL)
  184. return CLASS_E_NOAGGREGATION;
  185. if (pfnVerify != NULL && !pfnVerify(pUnkOuter, riid, ppvObj))
  186. return E_FAIL;
  187. pObject = new DerivedClass;
  188. if (pObject == NULL)
  189. return E_OUTOFMEMORY;
  190. hr = pObject->QueryInterface(riid, ppvObj);
  191. pObject->Release();
  192. if (hr == S_OK && pfnPostCreate != NULL)
  193. {
  194. pfnPostCreate(riid, ppvObj);
  195. }
  196. return hr;
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // CComObjectRoot_CreateInstance
  201. //
  202. // Use this base class for standard COM objects that are exposed directly
  203. // from the class factory.
  204. //----------------------------------------------------------------------------
  205. template<class DerivedClass>
  206. class CComObjectRoot_CreateInstance : public CComObjectRootImmx
  207. {
  208. public:
  209. CComObjectRoot_CreateInstance() {}
  210. static HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  211. {
  212. return Unk_CreateInstance<DerivedClass>(pUnkOuter, riid, ppvObj, NULL, NULL);
  213. }
  214. };
  215. //+---------------------------------------------------------------------------
  216. //
  217. // CComObjectRoot_CreateInstance_Verify
  218. //
  219. // Use this base class for standard COM objects that are exposed directly
  220. // from the class factory.
  221. //----------------------------------------------------------------------------
  222. template<class DerivedClass>
  223. class CComObjectRoot_CreateInstance_Verify : public CComObjectRootImmx
  224. {
  225. public:
  226. CComObjectRoot_CreateInstance_Verify() {}
  227. static HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  228. {
  229. return Unk_CreateInstance<DerivedClass>(pUnkOuter, riid, ppvObj,
  230. DerivedClass::VerifyCreateInstance, DerivedClass::PostCreateInstance);
  231. }
  232. };
  233. // helper function, don't call this directly
  234. template<class DerivedClass>
  235. static HRESULT Unk_CreateInstanceSingleton(IUnknown *pUnkOuter, REFIID riid, void **ppvObj, VERIFYFUNC pfnVerify, POSTCREATE pfnPostCreate)
  236. {
  237. DerivedClass *pObject;
  238. HRESULT hr;
  239. if (ppvObj == NULL)
  240. return E_INVALIDARG;
  241. *ppvObj = NULL;
  242. if (pUnkOuter != NULL)
  243. return CLASS_E_NOAGGREGATION;
  244. pObject = DerivedClass::_GetThis();
  245. if (pObject == NULL)
  246. {
  247. if (pfnVerify != NULL && !pfnVerify(pUnkOuter, riid, ppvObj))
  248. {
  249. hr = E_FAIL;
  250. goto Exit;
  251. }
  252. pObject = new DerivedClass;
  253. if (pObject == NULL)
  254. {
  255. hr = E_OUTOFMEMORY;
  256. goto Exit;
  257. }
  258. hr = pObject->QueryInterface(riid, ppvObj);
  259. pObject->Release();
  260. if (hr == S_OK)
  261. {
  262. Assert(DerivedClass::_GetThis() != NULL); // _GetThis() should be set in object ctor on success
  263. if (pfnPostCreate != NULL)
  264. {
  265. pfnPostCreate(riid, *ppvObj);
  266. }
  267. }
  268. }
  269. else
  270. {
  271. hr = pObject->QueryInterface(riid, ppvObj);
  272. }
  273. Exit:
  274. return hr;
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // CComObjectRoot_CreateSingletonInstance
  279. //
  280. // Use this base class for standard COM objects that are exposed directly
  281. // from the class factory, and are singletons (one instance per thread).
  282. //
  283. // Classes deriving from this base must implement a _GetThis() method which
  284. // returns the singleton object, if it already exists, or null.
  285. //----------------------------------------------------------------------------
  286. template<class DerivedClass>
  287. class CComObjectRoot_CreateSingletonInstance : public CComObjectRootImmx
  288. {
  289. public:
  290. CComObjectRoot_CreateSingletonInstance() {}
  291. static HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  292. {
  293. return Unk_CreateInstanceSingleton<DerivedClass>(pUnkOuter, riid, ppvObj, NULL, NULL);
  294. }
  295. };
  296. //+---------------------------------------------------------------------------
  297. //
  298. // CComObjectRoot_CreateSingletonInstance_Verify
  299. //
  300. // Use this base class for standard COM objects that are exposed directly
  301. // from the class factory, and are singletons (one instance per thread).
  302. //
  303. // Classes deriving from this base must implement a VerifyCreateInstance
  304. // method that is called before allocating a new singleton instance, if
  305. // necessary. The Verify method can return FALSE to fail the class factory
  306. // CreateInstance call for any reason.
  307. //
  308. // The derived class must also implement a PostCreateInstance method that will
  309. // be called after allocating a new singleton, if the createinstance is about
  310. // to return S_OK (QueryInterface succecceded). This method is intended for
  311. // lazy load work.
  312. //
  313. // typedef BOOL (*VERIFYFUNC)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj);
  314. // typedef void (*POSTCREATE)(REFIID riid, void *pvObj);
  315. //
  316. // Classes deriving from this base must implement a _GetThis() method which
  317. // returns the singleton object, if it already exists, or null.
  318. //----------------------------------------------------------------------------
  319. template<class DerivedClass>
  320. class CComObjectRoot_CreateSingletonInstance_Verify : public CComObjectRootImmx
  321. {
  322. public:
  323. CComObjectRoot_CreateSingletonInstance_Verify() {}
  324. static HRESULT CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  325. {
  326. return Unk_CreateInstanceSingleton<DerivedClass>(pUnkOuter, riid, ppvObj,
  327. DerivedClass::VerifyCreateInstance, DerivedClass::PostCreateInstance);
  328. }
  329. };
  330. //+---------------------------------------------------------------------------
  331. //
  332. // BEGIN_COM_MAP_IMMX
  333. //
  334. //----------------------------------------------------------------------------
  335. #define BEGIN_COM_MAP_IMMX(class_type) \
  336. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) \
  337. { \
  338. BOOL fUseFirstIID = FALSE; \
  339. \
  340. if (ppvObject == NULL) \
  341. return E_INVALIDARG; \
  342. \
  343. *ppvObject = NULL; \
  344. \
  345. if (IsEqualIID(IID_IUnknown, riid)) \
  346. { \
  347. /* use first IID for IUnknown */ \
  348. fUseFirstIID = TRUE; \
  349. }
  350. //+---------------------------------------------------------------------------
  351. //
  352. // COM_INTERFACE_ENTRY
  353. //
  354. //----------------------------------------------------------------------------
  355. #define COM_INTERFACE_ENTRY(interface_type) \
  356. if (fUseFirstIID || IsEqualIID(IID_##interface_type, riid)) \
  357. { \
  358. *ppvObject = (interface_type *)this; \
  359. } \
  360. else
  361. //+---------------------------------------------------------------------------
  362. //
  363. // COM_INTERFACE_ENTRY_IID
  364. //
  365. //----------------------------------------------------------------------------
  366. #define COM_INTERFACE_ENTRY_IID(interface_iid, interface_type) \
  367. if (fUseFirstIID || IsEqualIID(interface_iid, riid)) \
  368. { \
  369. *ppvObject = (interface_type *)this; \
  370. } \
  371. else
  372. //+---------------------------------------------------------------------------
  373. //
  374. // COM_INTERFACE_ENTRY_FUNC
  375. //
  376. //----------------------------------------------------------------------------
  377. #define COM_INTERFACE_ENTRY_FUNC(interface_iid, param, pfn) \
  378. /* compiler will complain about unused vars, so reuse fUseFirstIID if we need it here */ \
  379. if (IsEqualIID(interface_iid, riid) && \
  380. (fUseFirstIID = pfn(this, interface_iid, ppvObject, param)) != S_FALSE) \
  381. { \
  382. return (HRESULT)fUseFirstIID; /* pfn set ppvObject */ \
  383. } \
  384. else
  385. //+---------------------------------------------------------------------------
  386. //
  387. // END_COM_MAP_IMMX
  388. //
  389. //----------------------------------------------------------------------------
  390. #define END_COM_MAP_IMMX() \
  391. {} \
  392. if (*ppvObject) \
  393. { \
  394. AddRef(); \
  395. return S_OK; \
  396. } \
  397. \
  398. return E_NOINTERFACE; \
  399. } \
  400. \
  401. STDMETHODIMP_(ULONG) AddRef() \
  402. { \
  403. void DllAddRef(void); \
  404. DebugRefBreak(); \
  405. \
  406. if (m_dwRef == 1 && InternalReferenced()) \
  407. { \
  408. /* first external reference to this object */ \
  409. DllAddRef(); \
  410. } \
  411. \
  412. return ++m_dwRef; \
  413. } \
  414. \
  415. STDMETHODIMP_(ULONG) Release() \
  416. { \
  417. void DllRelease(void); \
  418. long cr; \
  419. \
  420. DebugRefBreak(); \
  421. \
  422. cr = --m_dwRef; \
  423. Assert(cr >= 0); \
  424. \
  425. if (cr == 1 && InternalReferenced()) \
  426. { \
  427. /* last external reference just went away */ \
  428. DllRelease(); \
  429. } \
  430. else if (cr == 0) \
  431. { \
  432. delete this; \
  433. } \
  434. \
  435. return cr; \
  436. }
  437. // here for backwards compat with old atl based code, unused
  438. #define IMMX_OBJECT_IUNKNOWN_FOR_ATL()
  439. // class factory entry
  440. typedef HRESULT (STDAPICALLTYPE * PFNCREATEINSTANCE)(IUnknown *pUnkOuter, REFIID riid, void **ppvObj);
  441. typedef struct
  442. {
  443. const CLSID *pclsid;
  444. PFNCREATEINSTANCE pfnCreateInstance;
  445. const TCHAR *pszDesc;
  446. } OBJECT_ENTRY;
  447. // instantiated by the BEGIN_COCLASSFACTORY_TABLE macro
  448. extern const OBJECT_ENTRY c_rgCoClassFactoryTable[];
  449. //+---------------------------------------------------------------------------
  450. //
  451. // DllRefCount
  452. //
  453. // Returns the number of outstanding object references held by clients of the
  454. // server. This is useful for asserting all objects have been released at
  455. // process detach, and for delay loading/unitializing resources.
  456. //----------------------------------------------------------------------------
  457. inline LONG DllRefCount()
  458. {
  459. extern LONG g_cRefDll;
  460. // our ref starts at -1
  461. return g_cRefDll+1;
  462. }
  463. class CClassFactory;
  464. //+---------------------------------------------------------------------------
  465. //
  466. // BEGIN_COCLASSFACTORY_TABLE
  467. //
  468. //----------------------------------------------------------------------------
  469. #define BEGIN_COCLASSFACTORY_TABLE \
  470. const OBJECT_ENTRY c_rgCoClassFactoryTable[] = {
  471. //+---------------------------------------------------------------------------
  472. //
  473. // DECLARE_COCLASSFACTORY_ENTRY
  474. //
  475. // clsid - clsid of the object
  476. // cclass - C++ class of the object. This macro expects to find
  477. // ClassName::CreateInstance, which the CComObject bases provide by default.
  478. // desc - description, default REG_SZ value under the CLSID registry entry.
  479. //----------------------------------------------------------------------------
  480. #define DECLARE_COCLASSFACTORY_ENTRY(clsid, cclass, desc) \
  481. { &clsid, cclass##::CreateInstance, desc },
  482. //+---------------------------------------------------------------------------
  483. //
  484. // END_COCLASSFACTORY_TABLE
  485. //
  486. //----------------------------------------------------------------------------
  487. #define END_COCLASSFACTORY_TABLE \
  488. { NULL, NULL, NULL } }; \
  489. CClassFactory *g_ObjectInfo[ARRAYSIZE(c_rgCoClassFactoryTable)] = { NULL };
  490. #endif // __cplusplus
  491. #endif // UNKNOWN_H