Source code of Windows XP (NT5)
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.

257 lines
8.1 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992 - 1998 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. // Base class hierachy for creating COM objects, December 1994
  12. /*
  13. a. Derive your COM object from CComBase
  14. b. Make a static CreateInstance function that takes an IUnknown* and an
  15. HRESULT*. The IUnknown* defines the object to delegate IUnknown calls
  16. to. The HRESULT * allows error codes to be passed around constructors.
  17. It is important that constructors only change the HRESULT * if they have
  18. to set an ERROR code, if it was successful then leave it alone or you may
  19. overwrite an error code from an object previously created.
  20. c. Have a constructor for your object that passes the IUnknown* and HRESULT*
  21. to the CComBase constructor. You can set the HRESULT if you have an error,
  22. or just simply pass it through to the constructor.
  23. The object creation will fail in the class factory if the HRESULT indicates
  24. an error (ie FAILED(HRESULT) == TRUE)
  25. d. Create a CComClassTemplate with your object's class id and CreateInstance
  26. function.
  27. Then (for each interface) either
  28. Multiple inheritance
  29. 1. Also derive it from ISomeInterface
  30. 2. Include DECLARE_IUNKNOWN in your class definition to declare
  31. implementations of QueryInterface, AddRef and Release that
  32. call the outer unknown
  33. 3. Override NDQueryInterface to expose ISomeInterface by
  34. code something like
  35. if (riid == IID_ISomeInterface) {
  36. return GetInterface((ISomeInterface *) this, ppv);
  37. } else {
  38. return CComBase::NDQueryInterface(riid, ppv);
  39. }
  40. 4. Declare and implement the member functions of ISomeInterface.
  41. or: Nested interfaces
  42. 1. Declare a class derived from CComBase
  43. 2. Include DECLARE_IUNKNOWN in your class definition
  44. 3. Override NDQueryInterface to expose ISomeInterface by
  45. code something like
  46. if (riid == IID_ISomeInterface) {
  47. return GetInterface((ISomeInterface *) this, ppv);
  48. } else {
  49. return CComBase::NDQueryInterface(riid, ppv);
  50. }
  51. 4. Implement the member functions of ISomeInterface. Use \() to
  52. access the COM object class.
  53. And in your COM object class:
  54. 5. Make the nested class a friend of the COM object class, and declare
  55. an instance of the nested class as a member of the COM object class.
  56. NOTE that because you must always pass the outer unknown and an hResult
  57. to the CComBase constructor you cannot use a default constructor, in
  58. other words you will have to make the member variable a pointer to the
  59. class and make a NEW call in your constructor to actually create it.
  60. 6. override the NDQueryInterface with code like this:
  61. if (riid == IID_ISomeInterface) {
  62. return m_pImplFilter->
  63. NDQueryInterface(IID_ISomeInterface, ppv);
  64. } else {
  65. return CComBase::NDQueryInterface(riid, ppv);
  66. }
  67. You can have mixed classes which support some interfaces via multiple
  68. inheritance and some via nested classes
  69. */
  70. #ifndef __COMBASE__
  71. #define __COMBASE__
  72. #include <windows.h>
  73. #include <basetyps.h>
  74. #include <unknwn.h>
  75. extern int g_cActiveObjects;
  76. STDAPI CreateCLSIDRegKey(REFCLSID clsid, const char *szName);
  77. STDAPI RemoveCLSIDRegKey(REFCLSID clsid);
  78. #ifdef DEBUG
  79. // We chose a common name for our ASSERT macro, MFC also uses this name
  80. // So long as the implementation evaluates the condition and handles it
  81. // then we will be ok. Rather than override the behaviour expected we
  82. // will leave whatever first defines ASSERT as the handler (i.e. MFC)
  83. #ifndef ASSERT
  84. #define ASSERT(_x_) if (!(_x_)) \
  85. DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
  86. #endif
  87. #define EXECUTE_ASSERT(_x_) ASSERT(_x_)
  88. #define ValidateReadPtr(p,cb) \
  89. {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \
  90. DbgBreak("Invalid read pointer");}
  91. #define ValidateWritePtr(p,cb) \
  92. {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \
  93. DbgBreak("Invalid write pointer");}
  94. #define ValidateReadWritePtr(p,cb) \
  95. {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)}
  96. #else
  97. #ifndef ASSERT
  98. #define ASSERT(_x_) ((void)0)
  99. #endif
  100. #define EXECUTE_ASSERT(_x_) ((void)(_x_))
  101. #define ValidateReadPtr(p,cb) 0
  102. #define ValidateWritePtr(p,cb) 0
  103. #define ValidateReadWritePtr(p,cb) 0
  104. #endif
  105. /* The DLLENTRY module initialises the module handle on loading */
  106. extern HINSTANCE g_hInst;
  107. /* On DLL load remember which platform we are running on */
  108. /* Version of IUnknown that is renamed to allow a class to support both
  109. non delegating and delegating IUnknowns in the same COM object */
  110. #ifndef INDUNKNOWN_DEFINED
  111. DECLARE_INTERFACE(INDUnknown)
  112. {
  113. STDMETHOD(NDQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
  114. STDMETHOD_(ULONG, NDAddRef)(THIS) PURE;
  115. STDMETHOD_(ULONG, NDRelease)(THIS) PURE;
  116. };
  117. #define INDUNKNOWN_DEFINED
  118. #endif
  119. class CBaseObject {
  120. public:
  121. CBaseObject() {g_cActiveObjects++;}
  122. ~CBaseObject() {g_cActiveObjects--;}
  123. };
  124. /* An object that supports one or more COM interfaces will be based on
  125. this class. It supports counting of total objects for DLLCanUnloadNow
  126. support, and an implementation of the core non delegating IUnknown */
  127. class CComBase : public INDUnknown,
  128. CBaseObject
  129. {
  130. private:
  131. IUnknown* m_pUnknown; /* Owner of this object */
  132. protected: /* So we can override NDRelease() */
  133. volatile LONG m_cRef; /* Number of reference counts */
  134. public:
  135. CComBase(IUnknown* pUnk);
  136. virtual ~CComBase() {};
  137. // This is redundant, just use the other constructor
  138. // as we never touch the HRESULT in this anyway
  139. CComBase(IUnknown* pUnk,HRESULT *phr);
  140. /* Return the owner of this object */
  141. IUnknown* GetOwner() const {
  142. return m_pUnknown;
  143. };
  144. /* Called from the class factory to create a new instance, it is
  145. pure virtual so it must be overriden in your derived class */
  146. /* static CComBase *CreateInstance(IUnknown*, HRESULT *) */
  147. /* Non delegating unknown implementation */
  148. STDMETHODIMP NDQueryInterface(REFIID, void **);
  149. STDMETHODIMP_(ULONG) NDAddRef();
  150. STDMETHODIMP_(ULONG) NDRelease();
  151. };
  152. /* Return an interface pointer to a requesting client
  153. performing a thread safe AddRef as necessary */
  154. STDAPI GetInterface(IUnknown* pUnk, void **ppv);
  155. /* A function that can create a new COM object */
  156. typedef CComBase *(CALLBACK *LPFNNewCOMObject)(IUnknown* pUnkOuter, HRESULT *phr);
  157. /* A function (can be NULL) which is called from the DLL entrypoint
  158. routine for each factory template:
  159. bLoading - TRUE on DLL load, FALSE on DLL unload
  160. rclsid - the m_ClsID of the entry
  161. */
  162. typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
  163. #define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
  164. /* Create one of these per object class in an array so that
  165. the default class factory code can create new instances */
  166. struct CComClassTemplate {
  167. const CLSID * m_ClsID;
  168. LPFNNewCOMObject m_lpfnNew;
  169. };
  170. /* You must override the (pure virtual) NDQueryInterface to return
  171. interface pointers (using GetInterface) to the interfaces your derived
  172. class supports (the default implementation only supports IUnknown) */
  173. #define DECLARE_IUNKNOWN \
  174. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
  175. return GetOwner()->QueryInterface(riid,ppv); \
  176. }; \
  177. STDMETHODIMP_(ULONG) AddRef() { \
  178. return GetOwner()->AddRef(); \
  179. }; \
  180. STDMETHODIMP_(ULONG) Release() { \
  181. return GetOwner()->Release(); \
  182. };
  183. HINSTANCE LoadOLEAut32();
  184. #endif /* __COMBASE__ */