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.

387 lines
10 KiB

  1. /*****************************************************************************
  2. *
  3. * common.c - Shared stuff that operates on all classes
  4. *
  5. * WARNING! The Common services work only if you pass in the
  6. * "primary object". This is vacuous if you don't use multiple
  7. * inheritance, since there's only one object in the first place.
  8. *
  9. * If you use multiple inheritance, make sure you pass the pointer
  10. * to the object that you use as IUnknown.
  11. *
  12. * The exceptions are the Forward_* functions, which work on
  13. * pointers to non-primary interfaces. They forward the call to the
  14. * primary interface.
  15. *
  16. *****************************************************************************/
  17. #include "fnd.h"
  18. /*****************************************************************************
  19. *
  20. * The sqiffle for this file.
  21. *
  22. *****************************************************************************/
  23. #define sqfl sqflCommon
  24. /*****************************************************************************
  25. *
  26. * USAGE FOR OLE OBJECTS
  27. *
  28. * Suppose you want to implement an object called CObj that supports
  29. * the interfaces Foo, Bar, and Baz. Suppose that you opt for
  30. * Foo as the primary interface.
  31. *
  32. * >> NAMING CONVENTION <<
  33. *
  34. * COM objects begin with the letter "C".
  35. *
  36. * (1) Declare the primary and secondary vtbls.
  37. *
  38. * Primary_Interface(CObj, IFoo);
  39. * Secondary_Interface(CObj, IBar);
  40. * Secondary_Interface(CObj, IBaz);
  41. *
  42. * (3) Declare the object itself.
  43. *
  44. * typedef struct CObj {
  45. * IFoo foo; // Primary must come first
  46. * IBar bar;
  47. * IBaz baz;
  48. * ... other fields ...
  49. * } CObj;
  50. *
  51. * (4) Implement the methods.
  52. *
  53. * You may *not* reimplement the AddRef and Release methods!
  54. * although you can subclass them.
  55. *
  56. * (5) To allocate an object of the appropriate type, write
  57. *
  58. * hres = Common_New(CObj, ppvOut);
  59. *
  60. * or, if the object is variable-sized,
  61. *
  62. * hres = Common_NewCb(cb, CObj, ppvOut);
  63. *
  64. * If the object supports multiple interfaces, you also need to
  65. * initialize all the secondary interfaces.
  66. *
  67. * CObj *pco = *ppvOut;
  68. * pco->bar = Secondary_Vtbl(CObj, IBar);
  69. * pco->baz = Secondary_Vtbl(CObj, IBaz);
  70. *
  71. * (6) Define the vtbls.
  72. *
  73. * #pragma BEGIN_CONST_DATA
  74. *
  75. * // The macros will declare QueryInterface, AddRef and Release
  76. * // so don't list them again
  77. *
  78. * Primary_Interface_Begin(CObj, IFoo)
  79. * CObj_FooMethod1,
  80. * CObj_FooMethod2,
  81. * CObj_FooMethod3,
  82. * CObj_FooMethod4,
  83. * Primary_Interface_End(Obj, IFoo)
  84. *
  85. * Secondary_Interface_Begin(CObj, IBar, bar)
  86. * CObj_Bar_BarMethod1,
  87. * CObj_Bar_BarMethod2,
  88. * Secondary_Interface_Begin(CObj, IBar, bar)
  89. *
  90. * Secondary_Interface_Begin(CObj, IBaz, baz)
  91. * CObj_Baz_BazMethod1,
  92. * CObj_Baz_BazMethod2,
  93. * CObj_Baz_BazMethod3,
  94. * Secondary_Interface_Begin(CObj, IBaz, baz)
  95. *
  96. *****************************************************************************/
  97. /*****************************************************************************
  98. *
  99. * USAGE FOR NON-OLE OBJECTS
  100. *
  101. * All objects are COM objects, even if they are never given out.
  102. * In the simplest case, it just derives from IUnknown.
  103. *
  104. * Suppose you want to implement an object called Obj which is
  105. * used only internally.
  106. *
  107. * (1) Declare the vtbl.
  108. *
  109. * Simple_Interface(Obj);
  110. *
  111. * (3) Declare the object itself.
  112. *
  113. * typedef struct Obj {
  114. * IUnknown unk;
  115. * ... other fields ...
  116. * } Obj;
  117. *
  118. * (4) Implement the methods.
  119. *
  120. * You may *not* override the QueryInterface, AddRef or
  121. * Release methods!
  122. *
  123. * (5) Allocating an object of the appropriate type is the same
  124. * as with OLE objects.
  125. *
  126. * (6) Define the "vtbl".
  127. *
  128. * #pragma BEGIN_CONST_DATA
  129. *
  130. * Simple_Interface_Begin(Obj)
  131. * Simple_Interface_End(Obj)
  132. *
  133. * That's right, nothing goes between the Begin and the End.
  134. *
  135. *****************************************************************************/
  136. /*****************************************************************************
  137. *
  138. * CommonInfo
  139. *
  140. * Information tracked for all common objects.
  141. *
  142. * A common object looks like this:
  143. *
  144. * riid
  145. * cRef FinalizeProc
  146. * pFoo -> lpVtbl -> QueryInterface
  147. * data Common_AddRef
  148. * data Common_Release
  149. * ... ...
  150. *
  151. * Essentially, we use the otherwise-unused space above the
  152. * pointers to record our bookkeeping information.
  153. *
  154. * cRef = object reference count
  155. * riid = object iid
  156. * FinalizeProc = Finalization procedure
  157. *
  158. * For secondary interfaces, it looks like this:
  159. *
  160. * offset to primary interface
  161. * pFoo -> lpVtbl -> Forward_QueryInterface
  162. * Forward_AddRef
  163. * Forward_Release
  164. * ...
  165. *
  166. *****************************************************************************/
  167. typedef struct CommonInfoN {
  168. D(ULONG cin_dwSig;)
  169. ULONG cin_cRef;
  170. } CommonInfoN, CIN, *PCIN;
  171. typedef struct CommonInfoP {
  172. PREVTBL *cip_prevtbl;
  173. } CommonInfoP, CIP, *PCIP;
  174. typedef struct CommonInfoP2 {
  175. PREVTBL2 *cip2_prevtbl2;
  176. } CommonInfoP2, CIP2, *PCIP2;
  177. typedef union CommonInfo {
  178. CIN cin[1];
  179. CIP cip[1];
  180. CIP2 cip2[1];
  181. } CommonInfo, CI, *PCI;
  182. #define ci_dwSig cin[-1].cin_dwSig
  183. #define ci_cRef cin[-1].cin_cRef
  184. #define ci_rgfp cip[0].cip_prevtbl
  185. #define ci_riid cip[0].cip_prevtbl[-1].riid
  186. #define ci_Finalize cip[0].cip_prevtbl[-1].FinalizeProc
  187. #define ci_lib cip2[0].cip2_prevtbl2[-1].lib
  188. #ifdef DEBUG
  189. #define ci_Start ci_dwSig
  190. #else
  191. #define ci_Start ci_cRef
  192. #endif
  193. #define ci_dwSignature 0x38162378 /* typed by my cat */
  194. /*****************************************************************************
  195. *
  196. * Common_QueryInterface (from IUnknown)
  197. *
  198. * Use this for objects that support only one interface.
  199. *
  200. *****************************************************************************/
  201. STDMETHODIMP
  202. Common_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  203. {
  204. PCI pci = pv;
  205. HRESULT hres;
  206. EnterProc(Common_QueryInterface, (_ "pG", pv, riid));
  207. AssertF(pci->ci_dwSig == ci_dwSignature);
  208. if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, pci->ci_riid)) {
  209. *ppvObj = pv;
  210. Common_AddRef(pv);
  211. hres = NOERROR;
  212. } else {
  213. *ppvObj = NULL;
  214. hres = ResultFromScode(E_NOINTERFACE);
  215. }
  216. ExitOleProcPpv(ppvObj);
  217. return hres;
  218. }
  219. /*****************************************************************************
  220. *
  221. * Common_AddRef (from IUnknown)
  222. *
  223. * Increment the object refcount and the dll refcount.
  224. *
  225. *****************************************************************************/
  226. STDMETHODIMP_(ULONG)
  227. _Common_AddRef(PV pv)
  228. {
  229. PCI pci = pv;
  230. AssertF(pci->ci_dwSig == ci_dwSignature);
  231. InterlockedIncrement((LPLONG)&g_cRef);
  232. return ++pci->ci_cRef;
  233. }
  234. /*****************************************************************************
  235. *
  236. * Common_Finalize (from Common_Release)
  237. *
  238. * By default, no finalization is necessary.
  239. *
  240. *****************************************************************************/
  241. void EXTERNAL
  242. Common_Finalize(PV pv)
  243. {
  244. SquirtSqflPtszV(sqfl, TEXT("Common_Finalize(%08x)"), pv);
  245. }
  246. /*****************************************************************************
  247. *
  248. * Common_Release (from IUnknown)
  249. *
  250. * Decrement the object refcount and the dll refcount.
  251. *
  252. * If the object refcount drops to zero, finalize the object
  253. * and free it.
  254. *
  255. * The finalization handler lives ahead of the object vtbl.
  256. *
  257. *****************************************************************************/
  258. STDMETHODIMP_(ULONG)
  259. _Common_Release(PV pv)
  260. {
  261. PCI pci = pv;
  262. ULONG ulRc;
  263. AssertF(pci->ci_dwSig == ci_dwSignature);
  264. InterlockedDecrement((LPLONG)&g_cRef);
  265. ulRc = --pci->ci_cRef;
  266. if (ulRc == 0) {
  267. pci->ci_Finalize(pv);
  268. FreePv(&pci->ci_Start);
  269. }
  270. return ulRc;
  271. }
  272. /*****************************************************************************
  273. *
  274. * Forward_QueryInterface (from IUnknown)
  275. *
  276. * Move to the main object and try again.
  277. *
  278. *****************************************************************************/
  279. STDMETHODIMP
  280. Forward_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  281. {
  282. PCI pci = pv;
  283. LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  284. return Common_QueryInterface(punk, riid, ppvObj);
  285. }
  286. /*****************************************************************************
  287. *
  288. * Forward_AddRef (from IUnknown)
  289. *
  290. * Move to the main object and try again.
  291. *
  292. *****************************************************************************/
  293. STDMETHODIMP_(ULONG)
  294. Forward_AddRef(PV pv)
  295. {
  296. PCI pci = pv;
  297. LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  298. return Common_AddRef(punk);
  299. }
  300. /*****************************************************************************
  301. *
  302. * Forward_Release (from IUnknown)
  303. *
  304. * Move to the main object and try again.
  305. *
  306. *****************************************************************************/
  307. STDMETHODIMP_(ULONG)
  308. Forward_Release(PV pv)
  309. {
  310. PCI pci = pv;
  311. LPUNKNOWN punk = pvAddPvCb(pv, 0 - pci->ci_lib);
  312. return Common_Release(punk);
  313. }
  314. /*****************************************************************************
  315. *
  316. * _Common_New
  317. *
  318. * Create a new object with refcount 1 and the specific vtbl.
  319. * All other fields are zero-initialized.
  320. *
  321. *****************************************************************************/
  322. STDMETHODIMP
  323. _Common_New(ULONG cb, PV vtbl, PPV ppvObj)
  324. {
  325. HRESULT hres;
  326. EnterProc(Common_New, (_ "u", cb));
  327. SquirtSqflPtszV(sqfl, TEXT("Common_New()"));
  328. hres = AllocCbPpv(cb + sizeof(CIN), ppvObj);
  329. if (SUCCEEDED(hres)) {
  330. PCI pci = pvAddPvCb(*ppvObj, sizeof(CIN));
  331. D(pci->ci_dwSig = ci_dwSignature);
  332. pci->ci_rgfp = (PV)vtbl;
  333. *ppvObj = pci;
  334. Common_AddRef(pci);
  335. hres = NOERROR;
  336. }
  337. ExitOleProcPpv(ppvObj);
  338. return hres;
  339. }
  340. /*****************************************************************************
  341. *
  342. * Invoke_Release
  343. *
  344. * Release the object (if there is one) and wipe out the back-pointer.
  345. * Note that we wipe out the value before calling the release, in order
  346. * to ameliorate various weird callback conditions.
  347. *
  348. *****************************************************************************/
  349. void EXTERNAL
  350. Invoke_Release(PV pv)
  351. {
  352. LPUNKNOWN punk = pvExchangePpvPv(pv, 0);
  353. if (punk) {
  354. punk->lpVtbl->Release(punk);
  355. }
  356. }