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.

1239 lines
37 KiB

  1. /*****************************************************************************
  2. *
  3. * Common.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Shared stuff that operates on all classes
  10. *
  11. * This version of the common services supports multiple
  12. * inheritance natively. You can pass any interface of an object,
  13. * and the common services will do the right thing.
  14. *
  15. * Contents:
  16. *
  17. *****************************************************************************/
  18. #include "dinputpr.h"
  19. /*****************************************************************************
  20. *
  21. * The sqiffle for this file.
  22. *
  23. *****************************************************************************/
  24. #define sqfl sqflCommon
  25. /*****************************************************************************
  26. *
  27. * USAGE FOR OLE OBJECTS
  28. *
  29. * Suppose you want to implement an object called CObj that supports
  30. * the interfaces Foo, Bar, and Baz. Suppose that you opt for
  31. * Foo as the primary interface.
  32. *
  33. * >> NAMING CONVENTION <<
  34. *
  35. * COM objects begin with the letter "C".
  36. *
  37. * (1) Declare the primary and secondary vtbls.
  38. *
  39. * Primary_Interface(CObj, IFoo);
  40. * Secondary_Interface(CObj, IBar);
  41. * Secondary_Interface(CObj, IBaz);
  42. *
  43. * (3) Declare the object itself.
  44. *
  45. * typedef struct CObj {
  46. * IFoo foo; // Primary must come first
  47. * IBar bar;
  48. * IBaz baz;
  49. * ... other fields ...
  50. * } CObj;
  51. *
  52. * (4) Implement the methods.
  53. *
  54. * You may *not* reimplement the AddRef and Release methods!
  55. * although you can subclass them.
  56. *
  57. * (5) To allocate an object of the appropriate type, write
  58. *
  59. * hres = Common_NewRiid(CObj, punkOuter, riid, ppvOut);
  60. *
  61. * or, if the object is variable-sized,
  62. *
  63. * hres = Common_NewCbRiid(cb, CObj, punkouter, riid, ppvOut);
  64. *
  65. * Common_NewRiid and Common_NewCbRiid will initialize both the
  66. * primary and secondary vtbls.
  67. *
  68. * (6) Define the object signature.
  69. *
  70. * #pragma BEGIN_CONST_DATA
  71. *
  72. * #define CObj_Signature 0x204A424F // "OBJ "
  73. *
  74. * (7) Define the object template.
  75. *
  76. * Interface_Template_Begin(CObj)
  77. * Primary_Interface_Template(CObj, IFoo)
  78. * Secondary_Interface_Template(CObj, IBar)
  79. * Secondary_Interface_Template(CObj, IBaz)
  80. * Interface_Template_End(CObj)
  81. *
  82. * (8) Define the interface descriptors.
  83. *
  84. * // The macros will declare QueryInterface, AddRef and Release
  85. * // so don't list them again
  86. *
  87. * Primary_Interface_Begin(CObj, IFoo)
  88. * CObj_FooMethod1,
  89. * CObj_FooMethod2,
  90. * CObj_FooMethod3,
  91. * CObj_FooMethod4,
  92. * Primary_Interface_End(Obj, IFoo)
  93. *
  94. * Secondary_Interface_Begin(CObj, IBar, bar)
  95. * CObj_Bar_BarMethod1,
  96. * CObj_Bar_BarMethod2,
  97. * Secondary_Interface_Begin(CObj, IBar, bar)
  98. *
  99. * Secondary_Interface_Begin(CObj, IBaz, baz)
  100. * CObj_Baz_BazMethod1,
  101. * CObj_Baz_BazMethod2,
  102. * CObj_Baz_BazMethod3,
  103. * Secondary_Interface_Begin(CObj, IBaz, baz)
  104. *
  105. *****************************************************************************/
  106. /*****************************************************************************
  107. *
  108. * USAGE FOR NON-OLE OBJECTS
  109. *
  110. * All objects are COM objects, even if they are never given out.
  111. * In the simplest case, it just derives from IUnknown.
  112. *
  113. * Suppose you want to implement an object called Obj which is
  114. * used only internally.
  115. *
  116. * (1) Declare the vtbl.
  117. *
  118. * Simple_Interface(Obj);
  119. *
  120. * (3) Declare the object itself.
  121. *
  122. * typedef struct Obj {
  123. * IUnknown unk;
  124. * ... other fields ...
  125. * } Obj;
  126. *
  127. * (4) Implement the methods.
  128. *
  129. * You may *not* override the QueryInterface, AddRef or
  130. * Release methods!
  131. *
  132. * (5) Allocating an object of the appropriate type is the same
  133. * as with OLE objects.
  134. *
  135. * (6) Define the "vtbl".
  136. *
  137. * #pragma BEGIN_CONST_DATA
  138. *
  139. * Simple_Interface_Begin(Obj)
  140. * Simple_Interface_End(Obj)
  141. *
  142. * That's right, nothing goes between the Begin and the End.
  143. *
  144. *****************************************************************************/
  145. /*****************************************************************************
  146. *
  147. * CommonInfo
  148. *
  149. * Information tracked for all common objects.
  150. *
  151. * A common object looks like this:
  152. *
  153. * rgvtbl
  154. * cbvtbl
  155. * D(dwSig) QIHelper
  156. * cHoldRef AppFinalizeProc
  157. * cRef FinalizeProc
  158. * punkOuter riid
  159. * unkPrivate 0
  160. * pFoo -> lpVtbl -> QueryInterface
  161. * lpVtbl2 Common_AddRef
  162. * data Common_Release
  163. * ... ...
  164. *
  165. * Essentially, we use the otherwise-unused space above the
  166. * pointers to record our bookkeeping information.
  167. *
  168. * punkOuter = controlling unknown, if object is aggregated
  169. * lpvtblPunk = special vtbl for controlling unknown to use
  170. * cHoldRef = Total reference count, including holds
  171. * cRef = object reference count from application
  172. * riid = object iid
  173. * rgvtbl = array of vtbls of supported interfaces
  174. * cbvtbl = size of array in bytes
  175. * QIHelper = QueryInterface helper for aggregation
  176. * AppFinalizeProc = Finalization procedure when app does last Release
  177. * FinalizeProc = Finalization procedure
  178. *
  179. * For secondary interfaces, it looks like this:
  180. *
  181. * riid
  182. * offset to primary interface
  183. * pFoo -> lpVtbl -> Forward_QueryInterface
  184. * Forward_AddRef
  185. * Forward_Release
  186. * ...
  187. *
  188. *
  189. * What is a hold?
  190. *
  191. * There is this annoying situation (particularly with
  192. * IDirectInputDevice) where an object wants to prevent itself
  193. * from being destroyed but we don't want to do an AddRef.
  194. *
  195. * The classic case (and for now the only one) is an
  196. * IDirectInputDevice which has been acquired. If we did
  197. * an honest AddRef() on the Acquire(), and the application does
  198. * a Release() without Unacquire()ing, then the device would
  199. * be acquired forever.
  200. *
  201. * If you thought that the Unacquire() in the finalization
  202. * would help, you'd be wrong, because the finalization happens
  203. * only when the last reference goes away, but the last reference
  204. * belongs to the device itself and will never go away until
  205. * the Unacquire() happens, which can't happen because the app
  206. * already lost its last reference to the device.
  207. *
  208. * So instead, we need to maintain *two* refcounts.
  209. *
  210. * cRef is the application-visible reference count, accessible
  211. * via PrivateAddRef() and PrivateRelease(). When this
  212. * drops to zero, we call the AppFinalize().
  213. *
  214. * cHoldRef is the "real" reference count. This is the sum of
  215. * cRef and the number of outstanding Common_Hold()s. When
  216. * this drops to zero, then the object is Finalize()d.
  217. *
  218. *
  219. *****************************************************************************/
  220. /* WARNING! cin_dwSig must be first: ci_Start relies on it */
  221. /* WARNING! cin_unkPrivate must be last: punkPrivateThis relies on it */
  222. typedef struct CommonInfoN { /* This goes in front of the object */
  223. RD(ULONG cin_dwSig;) /* Signature (for parameter validation) */
  224. LONG cin_cHoldRef; /* Total refcount, incl. holds */
  225. LONG cin_cRef; /* Object reference count */
  226. PUNK cin_punkOuter; /* Controlling unknown */
  227. IUnknown cin_unkPrivate; /* Private IUnknown */
  228. } CommonInfoN, CIN, *PCIN;
  229. typedef struct CommonInfoP { /* This is how we pun the object itself */
  230. PREVTBLP *cip_prevtbl; /* Vtbl of object (will be -1'd) */
  231. } CommonInfoP, CIP, *PCIP;
  232. typedef union CommonInfo {
  233. CIN cin[1];
  234. CIP cip[1];
  235. } CommonInfo, CI, *PCI;
  236. #define ci_dwSig cin[-1].cin_dwSig
  237. #define ci_cHoldRef cin[-1].cin_cHoldRef
  238. #define ci_cRef cin[-1].cin_cRef
  239. #define ci_punkOuter cin[-1].cin_punkOuter
  240. #define ci_unkPrivate cin[-1].cin_unkPrivate
  241. #define ci_rgfp cip[0].cip_prevtbl
  242. #define ci_tszClass cip[0].cip_prevtbl[-1].tszClass
  243. #define ci_rgvtbl cip[0].cip_prevtbl[-1].rgvtbl
  244. #define ci_cbvtbl cip[0].cip_prevtbl[-1].cbvtbl
  245. #define ci_QIHelper cip[0].cip_prevtbl[-1].QIHelper
  246. #define ci_AppFinalize cip[0].cip_prevtbl[-1].AppFinalizeProc
  247. #define ci_Finalize cip[0].cip_prevtbl[-1].FinalizeProc
  248. #define ci_riid cip[0].cip_prevtbl[-1].prevtbl.riid
  249. #define ci_lib cip[0].cip_prevtbl[-1].prevtbl.lib
  250. #ifdef XDEBUG
  251. #define ci_Start ci_dwSig
  252. #else
  253. #define ci_Start ci_cRef
  254. #endif
  255. #define ci_dwSignature 0x38162378 /* typed by my cat */
  256. /*****************************************************************************
  257. *
  258. * Common_Finalize (from Common_Release)
  259. *
  260. * By default, no finalization is necessary.
  261. *
  262. *****************************************************************************/
  263. void EXTERNAL
  264. Common_Finalize(PV pv)
  265. {
  266. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  267. SquirtSqflPtszV(sqfl, TEXT("Common_Finalize(%p)"), pv);
  268. }
  269. /*****************************************************************************
  270. *
  271. * "Private" IUnknown methods
  272. *
  273. * When a COM object is aggregated, it exports *two* IUnknown
  274. * interfaces.
  275. *
  276. * The "private" IUnknown is the one that is returned to the
  277. * controlling unknown. It is this unknown that the controlling
  278. * unknown uses to manipulate the refcount on the inner object.
  279. *
  280. * The "public" IUnknown is the one that all external callers see.
  281. * For this, we just hand out the controlling unknown.
  282. *
  283. *****************************************************************************/
  284. Secondary_Interface(CCommon, IUnknown);
  285. /*****************************************************************************
  286. *
  287. * @doc INTERNAL
  288. *
  289. * @func PV | thisPunk |
  290. *
  291. * Convert a private punk (&cin_unkPrivate) into the beginning of
  292. * the actual object.
  293. *
  294. * @parm PUNK | punkPrivate |
  295. *
  296. * The private punk (&cin_unkPrivate) corresponding to some
  297. * object we are managing.
  298. *
  299. * @returns
  300. *
  301. * The object pointer on success, or 0 on error.
  302. *
  303. * @comm
  304. *
  305. * We do not return an <t HRESULT> on error, because the
  306. * callers of the procedure typically do not return
  307. * <t HRESULT>s themselves.
  308. *
  309. *****************************************************************************/
  310. #ifndef XDEBUG
  311. #define thisPunk_(punk, z) \
  312. _thisPunk_(punk) \
  313. #endif
  314. PV INLINE
  315. thisPunk_(PUNK punkPrivate, LPCSTR s_szProc)
  316. {
  317. PV pv;
  318. if (SUCCEEDED(hresFullValidPitf(punkPrivate, 0))) {
  319. if (punkPrivate->lpVtbl == Class_Vtbl(CCommon, IUnknown)) {
  320. pv = pvAddPvCb(punkPrivate,
  321. cbX(CIN) - FIELD_OFFSET(CIN, cin_unkPrivate));
  322. } else {
  323. RPF("%s: Invalid parameter 0", s_szProc);
  324. pv = 0;
  325. }
  326. } else {
  327. RPF("%s: Invalid parameter 0", s_szProc);
  328. pv = 0;
  329. }
  330. return pv;
  331. }
  332. #define thisPunk(punk) \
  333. thisPunk_(punk, s_szProc) \
  334. /*****************************************************************************
  335. *
  336. * @doc INTERNAL
  337. *
  338. * @func HRESULT | Common_QIHelper |
  339. *
  340. * Called when we can't find any interface in the standard list.
  341. * See if there's a dynamic interface we can use.
  342. *
  343. * Objects are expected to override this method if
  344. * they implement dynamic interfaces.
  345. *
  346. * @parm PV | pv |
  347. *
  348. * The object being queried.
  349. *
  350. * @parm RIID | riid |
  351. *
  352. * The interface being requested.
  353. *
  354. * @parm PPV | ppvObj |
  355. *
  356. * Output pointer.
  357. *
  358. * @returns
  359. *
  360. * Always returns <c E_NOINTERFACE>.
  361. *
  362. *****************************************************************************/
  363. STDMETHODIMP
  364. Common_QIHelper(PV pv, RIID riid, PPV ppvObj)
  365. {
  366. HRESULT hres;
  367. *ppvObj = NULL;
  368. hres = E_NOINTERFACE;
  369. return hres;
  370. }
  371. /*****************************************************************************
  372. *
  373. * @doc INTERNAL
  374. *
  375. * @func HRESULT | Common_PrivateQueryInterface |
  376. *
  377. * Common implementation of <mf IUnknown::QueryInterface> for
  378. * the "private <i IUnknown>".
  379. *
  380. * Note that we AddRef through the public <i IUnknown>
  381. * (<ie>, through the controlling unknown).
  382. * That's part of the rules of aggregation,
  383. * and we have to follow them in order to keep the controlling
  384. * unknown from getting confused.
  385. *
  386. * @parm PUNK | punkPrivate |
  387. *
  388. * The object being queried.
  389. *
  390. * @parm RIID | riid |
  391. *
  392. * The interface being requested.
  393. *
  394. * @parm PPV | ppvObj |
  395. *
  396. * Output pointer.
  397. *
  398. *****************************************************************************/
  399. /*****************************************************************************
  400. *
  401. * The "Ensure jump is to end" remark boils down to the fact that
  402. * compilers have failed to recognize this:
  403. *
  404. * for (i = 0; i < n; i++) {
  405. * if (cond) {
  406. * mumble();
  407. * break;
  408. * }
  409. * }
  410. * if (i >= n) {
  411. * gurgle();
  412. * }
  413. *
  414. * and turn it into this:
  415. *
  416. * for (i = 0; i < n; i++) {
  417. * if (cond) {
  418. * mumble();
  419. * goto done;
  420. * }
  421. * }
  422. * gurgle();
  423. * done:;
  424. *
  425. * But even with this help, the compiler emits pretty dumb code.
  426. *
  427. *****************************************************************************/
  428. STDMETHODIMP
  429. Common_PrivateQueryInterface(PUNK punkPrivate, REFIID riid, PPV ppvObj)
  430. {
  431. PCI pci;
  432. HRESULT hres;
  433. EnterProcR(IUnknown::QueryInterface, (_ "pG", punkPrivate, riid));
  434. pci = thisPunk(punkPrivate);
  435. if (pci) {
  436. if (IsEqualIID(riid, &IID_IUnknown)) {
  437. *ppvObj = pci;
  438. OLE_AddRef(pci->ci_punkOuter);
  439. hres = S_OK;
  440. } else {
  441. UINT ivtbl;
  442. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  443. if (IsEqualIID(riid, ((PCI)(&pci->ci_rgvtbl[ivtbl]))->ci_riid)) {
  444. *ppvObj = pvAddPvCb(pci, ivtbl * sizeof(PV));
  445. OLE_AddRef(pci->ci_punkOuter);
  446. hres = S_OK;
  447. goto exit; /* Ensure jump is to end */
  448. }
  449. }
  450. hres = pci->ci_QIHelper(pci, riid, ppvObj);
  451. }
  452. } else {
  453. hres = E_INVALIDARG;
  454. }
  455. exit:;
  456. ExitOleProcPpv(ppvObj);
  457. return hres;
  458. }
  459. /*****************************************************************************
  460. *
  461. * @doc INTERNAL
  462. *
  463. * @func void | Common_FastHold |
  464. *
  465. * Increment the object hold count inline.
  466. *
  467. * @parm PV | pvObj |
  468. *
  469. * The object being held.
  470. *
  471. *****************************************************************************
  472. *
  473. * @doc INTERNAL
  474. *
  475. * @func void | Common_Hold |
  476. *
  477. * Increment the object hold count.
  478. *
  479. * @parm PV | pvObj |
  480. *
  481. * The object being held.
  482. *
  483. *****************************************************************************/
  484. void INLINE
  485. Common_FastHold(PV pvObj)
  486. {
  487. PCI pci = pvObj;
  488. InterlockedIncrement(&pci->ci_cHoldRef);
  489. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  490. D(SquirtSqflPtszV(sqflObj | sqflVerbose,
  491. TEXT("%s %p Common_FastHold ci_cRef(%d) ci_cHoldRef(%d)"),
  492. pci->ci_tszClass,
  493. pci,
  494. pci->ci_cRef,
  495. pci->ci_cHoldRef));
  496. }
  497. STDMETHODIMP_(void)
  498. Common_Hold(PV pvObj)
  499. {
  500. PCI pci = pvObj;
  501. AssertF(pvObj == _thisPv(pvObj)); /* Make sure it's the primary */
  502. AssertF(pci->ci_cHoldRef >= pci->ci_cRef);
  503. Common_FastHold(pvObj);
  504. }
  505. /*****************************************************************************
  506. *
  507. * @doc INTERNAL
  508. *
  509. * @func void | Common_FastUnhold |
  510. *
  511. * Decrement the object hold count. Assumes that the reference
  512. * count is <y not> dropping to zero.
  513. *
  514. * @parm PV | pvObj |
  515. *
  516. * The object being unheld.
  517. *
  518. *****************************************************************************
  519. *
  520. * @doc INTERNAL
  521. *
  522. * @func void | Common_Unhold |
  523. *
  524. * Decrement the object hold count. If the hold count drops
  525. * to zero, then the object is destroyed.
  526. *
  527. * @parm PV | pvObj |
  528. *
  529. * The object being unheld.
  530. *
  531. *****************************************************************************/
  532. void INLINE
  533. Common_FastUnhold(PV pvObj)
  534. {
  535. PCI pci = pvObj;
  536. AssertF(pci->ci_cHoldRef > 0);
  537. InterlockedDecrement(&pci->ci_cHoldRef);
  538. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  539. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_FastUnHold ci_cRef(%d) ci_cHoldRef(%d)"),
  540. pci->ci_tszClass,
  541. pci,
  542. pci->ci_cRef,
  543. pci->ci_cHoldRef));
  544. }
  545. STDMETHODIMP_(void)
  546. Common_Unhold(PV pvObj)
  547. {
  548. PCI pci = pvObj;
  549. AssertF(pci->ci_cHoldRef >= pci->ci_cRef);
  550. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  551. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_Unhold ci_cRef(%d) ci_cHoldRef(%d)"),
  552. pci->ci_tszClass,
  553. pci,
  554. pci->ci_cRef,
  555. pci->ci_cHoldRef-1));
  556. if (InterlockedDecrement(&pci->ci_cHoldRef) == 0) {
  557. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  558. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("Destroy %s %p "),
  559. pci->ci_tszClass,
  560. pci));
  561. /*
  562. * Last reference. Do an artifical addref so that
  563. * anybody who does an artificial addref during
  564. * finalization won't accidentally destroy us twice.
  565. */
  566. pci->ci_cHoldRef = 1;
  567. pci->ci_Finalize(pci);
  568. /* Artificial release is pointless: we're being freed */
  569. FreePv(pvSubPvCb(pci, sizeof(CIN)));
  570. DllRelease();
  571. }
  572. }
  573. /*****************************************************************************
  574. *
  575. * @doc INTERNAL
  576. *
  577. * @func ULONG | Common_PrivateAddRef |
  578. *
  579. * Increment the object refcount.
  580. *
  581. * @parm PUNK | punkPrivate |
  582. *
  583. * The object being addref'd.
  584. *
  585. *****************************************************************************/
  586. STDMETHODIMP_(ULONG)
  587. Common_PrivateAddRef(PUNK punkPrivate)
  588. {
  589. PCI pci;
  590. ULONG ulRef;
  591. EnterProcR(IUnknown::AddRef, (_ "p", punkPrivate));
  592. pci = thisPunk(punkPrivate);
  593. if (pci) {
  594. /*
  595. * Don't let anyone AddRef from 0 to 1. This happens if
  596. * somebody does a terminal release, but we have an internal
  597. * hold on the object, and the app tries to do an AddRef
  598. * even though the object is "gone".
  599. *
  600. * Yes, there is a race condition here, but it's not
  601. * a big one, and this is only a rough test anyway.
  602. */
  603. if (pci->ci_cRef) {
  604. /*
  605. * We must use an interlocked operation in case two threads
  606. * do AddRef or Release simultaneously. Note that the hold
  607. * comes first, so that we never have the case where the
  608. * hold count is less than the reference count.
  609. */
  610. Common_Hold(pci);
  611. InterlockedIncrement(&pci->ci_cRef);
  612. ulRef = pci->ci_cRef;
  613. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  614. D(SquirtSqflPtszV(sqflObj , TEXT("%s %p Common_PrivateAddref ci_cRef(%d) ci_cHoldRef(%d)"),
  615. pci->ci_tszClass,
  616. pci,
  617. pci->ci_cRef,
  618. pci->ci_cHoldRef));
  619. } else {
  620. RPF("ERROR: %s: Attempting to addref a deleted object", s_szProc);
  621. ulRef = 0;
  622. }
  623. } else {
  624. ulRef = 0;
  625. }
  626. ExitProcX(ulRef);
  627. return ulRef;
  628. }
  629. /*****************************************************************************
  630. *
  631. * @doc INTERNAL
  632. *
  633. * @func ULONG | Common_PrivateRelease |
  634. *
  635. * Decrement the object refcount. Note that decrementing
  636. * the hold count may cause the object to vanish, so stash
  637. * the resulting refcount ahead of time.
  638. *
  639. * Note that we release the hold last, so that the hold
  640. * count is always at least as great as the refcount.
  641. *
  642. * @parm PUNK | punkPrivate |
  643. *
  644. * The object being release'd.
  645. *
  646. *****************************************************************************/
  647. STDMETHODIMP_(ULONG)
  648. Common_PrivateRelease(PUNK punkPrivate)
  649. {
  650. PCI pci;
  651. ULONG ulRc;
  652. EnterProcR(IUnknown::Release, (_ "p", punkPrivate));
  653. pci = thisPunk(punkPrivate);
  654. if (pci) {
  655. LONG lRc;
  656. /*
  657. * We must use an interlocked operation in case two threads
  658. * do AddRef or Release simultaneously. And if the count
  659. * drops negative, then ignore it. (This means that the
  660. * app is Release()ing something too many times.)
  661. */
  662. lRc = InterlockedDecrement(&pci->ci_cRef);
  663. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  664. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_PrivateRelease ci_cRef(%d) ci_cHoldRef(%d)"),
  665. pci->ci_tszClass,
  666. pci->ci_tszClass,
  667. pci->ci_cRef,
  668. pci->ci_cHoldRef));
  669. if (lRc > 0) {
  670. /*
  671. * Not the last release; release the hold and return
  672. * the resulting refcount. Note that we can safely
  673. * use a fast unhold here, because there will always
  674. * be a hold lying around to match the refcount we
  675. * just got rid of.
  676. */
  677. Common_FastUnhold(pci);
  678. /*
  679. * This isn't 100% accurate, but it's close enough.
  680. * (OLE notes that the value is good only for debugging.)
  681. */
  682. ulRc = pci->ci_cRef;
  683. } else if (lRc == 0) {
  684. /*
  685. * That was the last application-visible reference.
  686. * Do app-level finalization.
  687. */
  688. pci->ci_AppFinalize(pci);
  689. /*
  690. * Note that we can't do
  691. * a fast unhold here, because this might be the last
  692. * hold.
  693. */
  694. Common_Unhold(pci);
  695. ulRc = 0;
  696. } else {
  697. /*
  698. * The app messed up big time.
  699. */
  700. RPF("ERROR: %s: Attempting to release a deleted object",
  701. s_szProc);
  702. ulRc = 0;
  703. }
  704. } else {
  705. ulRc = 0;
  706. }
  707. ExitProcX(ulRc);
  708. return ulRc;
  709. }
  710. /*****************************************************************************
  711. *
  712. * @doc INTERNAL
  713. *
  714. * @global IUnknownVtbl * | c_lpvtblPunk |
  715. *
  716. * The special IUnknown object that only the controlling unknown
  717. * knows about.
  718. *
  719. * This is the one that calls the "Real" services. All the normal
  720. * vtbl's go through the controlling unknown (which, if we are
  721. * not aggregated, points to ourselves).
  722. *
  723. *****************************************************************************/
  724. #pragma BEGIN_CONST_DATA
  725. _Secondary_Interface_Begin(CCommon, IUnknown,
  726. (ULONG)(FIELD_OFFSET(CIN, cin_unkPrivate) - cbX(CIN)),
  727. Common_Private)
  728. _Secondary_Interface_End(CCommon, IUnknown)
  729. #pragma END_CONST_DATA
  730. /*****************************************************************************
  731. *
  732. * "Public" IUnknown methods
  733. *
  734. * These simply forward through the controlling unknown.
  735. *
  736. *****************************************************************************/
  737. /*****************************************************************************
  738. *
  739. * @doc INTERNAL
  740. *
  741. * @func HRESULT | Common_QueryInterface |
  742. *
  743. * Forward through the controlling unknown.
  744. *
  745. * @parm PUNK | punk |
  746. *
  747. * The object being queried.
  748. *
  749. * @parm RIID | riid |
  750. *
  751. * The interface being requested.
  752. *
  753. * @parm PPV | ppvObj |
  754. *
  755. * Output pointer.
  756. *
  757. *****************************************************************************/
  758. STDMETHODIMP
  759. Common_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  760. {
  761. HRESULT hres;
  762. EnterProcR(IUnknown::QueryInterface, (_ "pG", pv, riid));
  763. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0)) &&
  764. SUCCEEDED(hres = hresFullValidRiid(riid, 1)) &&
  765. SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 2))) {
  766. PCI pci = _thisPv(pv);
  767. AssertF(pci->ci_punkOuter);
  768. hres = OLE_QueryInterface(pci->ci_punkOuter, riid, ppvObj);
  769. }
  770. ExitOleProcPpv(ppvObj);
  771. return hres;
  772. }
  773. /*****************************************************************************
  774. *
  775. * @doc INTERNAL
  776. *
  777. * @func ULONG | Common_AddRef |
  778. *
  779. * Forward through the controlling unknown.
  780. *
  781. * @parm PUNK | punk |
  782. *
  783. * The object being addref'd.
  784. *
  785. *****************************************************************************/
  786. STDMETHODIMP_(ULONG)
  787. Common_AddRef(PV pv)
  788. {
  789. ULONG ulRef;
  790. HRESULT hres;
  791. EnterProcR(IUnknown::AddRef, (_ "p", pv));
  792. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  793. PCI pci = _thisPv(pv);
  794. ulRef = OLE_AddRef(pci->ci_punkOuter);
  795. } else {
  796. ulRef = 0;
  797. }
  798. ExitProcX(ulRef);
  799. return ulRef;
  800. }
  801. /*****************************************************************************
  802. *
  803. * @doc INTERNAL
  804. *
  805. * @func ULONG | Common_Release |
  806. *
  807. * Forward through the controlling unknown.
  808. *
  809. * @parm PUNK | punk |
  810. *
  811. * Object being release'd.
  812. *
  813. *****************************************************************************/
  814. STDMETHODIMP_(ULONG)
  815. Common_Release(PV pv)
  816. {
  817. ULONG ulRc;
  818. HRESULT hres;
  819. EnterProcR(IUnknown::Release, (_ "p", pv));
  820. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  821. PCI pci = _thisPv(pv);
  822. ulRc = OLE_Release(pci->ci_punkOuter);
  823. } else {
  824. ulRc = 0;
  825. }
  826. ExitProcX(ulRc);
  827. return ulRc;
  828. }
  829. /*****************************************************************************
  830. *
  831. * @doc INTERNAL
  832. *
  833. * @func HRESULT | __Common_New |
  834. *
  835. * Create a new object with refcount 1 and the specific vtbl.
  836. * All other fields are zero-initialized. All parameters must
  837. * already be validated.
  838. *
  839. * @parm ULONG | cb |
  840. *
  841. * Size of object. This does not include the hidden bookkeeping
  842. * bytes maintained by the object manager.
  843. *
  844. * @parm PUNK | punkOuter |
  845. *
  846. * Controlling unknown for OLE aggregation. May be 0 to indicate
  847. * that the object is not aggregated.
  848. *
  849. * @parm PV | vtbl |
  850. *
  851. * Pointer to primary vtbl for this object. Note that the
  852. * vtbl declaration macros include other magic goo near the vtbl,
  853. * which we consult in order to create the object.
  854. *
  855. * @parm PPV | ppvObj |
  856. *
  857. * Output pointer.
  858. *
  859. *****************************************************************************/
  860. STDMETHODIMP
  861. __Common_New(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj)
  862. {
  863. HRESULT hres;
  864. EnterProc(__Common_New, (_ "uxx", cb, punkOuter, vtbl));
  865. hres = AllocCbPpv(cb + sizeof(CIN), ppvObj);
  866. if (SUCCEEDED(hres)) {
  867. PCI pciO = (PV)&vtbl;
  868. PCI pci = pvAddPvCb(*ppvObj, sizeof(CIN));
  869. RD(pci->ci_dwSig = ci_dwSignature);
  870. pci->ci_unkPrivate.lpVtbl = Class_Vtbl(CCommon, IUnknown);
  871. if (punkOuter) {
  872. pci->ci_punkOuter = punkOuter;
  873. } else {
  874. pci->ci_punkOuter = &pci->ci_unkPrivate;
  875. }
  876. CopyMemory(pci, pciO->ci_rgvtbl, pciO->ci_cbvtbl);
  877. *ppvObj = pci;
  878. /*
  879. * On an X86, it is simpler to increment a variable up
  880. * from zero to one. On a RISC, it is simpler to
  881. * store the value one directly.
  882. */
  883. #ifdef _X86_
  884. pci->ci_cHoldRef++;
  885. pci->ci_cRef++;
  886. #else
  887. pci->ci_cHoldRef = 1;
  888. pci->ci_cRef = 1;
  889. #endif
  890. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  891. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p __Common_New ci_cRef(%d) ci_cHoldRef(%d)"),
  892. pci->ci_tszClass,
  893. pci,
  894. pci->ci_cRef,
  895. pci->ci_cHoldRef
  896. ));
  897. DllAddRef();
  898. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  899. D(SquirtSqflPtszV(sqflObj, TEXT("Created %s %p "),
  900. pci->ci_tszClass,
  901. pci));
  902. hres = S_OK;
  903. }
  904. ExitOleProcPpv(ppvObj);
  905. return hres;
  906. }
  907. /*****************************************************************************
  908. *
  909. * @doc INTERNAL
  910. *
  911. * @func HRESULT | _Common_New_ |
  912. *
  913. * Create a new object with refcount 1 and the specific vtbl.
  914. * All other fields are zero-initialized. This entry point
  915. * validates parameters.
  916. *
  917. * @parm ULONG | cb |
  918. *
  919. * Size of object. This does not include the hidden bookkeeping
  920. * bytes maintained by the object manager.
  921. *
  922. * @parm PUNK | punkOuter |
  923. *
  924. * Controlling unknown for OLE aggregation. May be 0 to indicate
  925. * that the object is not aggregated.
  926. *
  927. * @parm PV | vtbl |
  928. *
  929. * Pointer to primary vtbl for this object. Note that the
  930. * vtbl declaration macros include other magic goo near the vtbl,
  931. * which we consult in order to create the object.
  932. *
  933. * @parm PPV | ppvObj |
  934. *
  935. * Output pointer.
  936. *
  937. *****************************************************************************/
  938. STDMETHODIMP
  939. _Common_New_(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj, LPCSTR pszProc)
  940. {
  941. HRESULT hres;
  942. EnterProc(_Common_New, (_ "uxx", cb, punkOuter, vtbl));
  943. if (SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  944. SUCCEEDED(hres = hresFullValidPcbOut_(ppvObj, cbX(*ppvObj), pszProc, 3))) {
  945. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  946. }
  947. ExitOleProcPpv(ppvObj);
  948. return hres;
  949. }
  950. /*****************************************************************************
  951. *
  952. * @doc INTERNAL
  953. *
  954. * @func HRESULT | _Common_NewRiid_ |
  955. *
  956. * Create a new object with refcount 1 and the specific vtbl,
  957. * but only if the object supports the indicated interface.
  958. * All other fields are zero-initialized.
  959. *
  960. * If punkOut is nonzero, then the object is being created for
  961. * aggregation. The interface must then be &IID_IUnknown.
  962. *
  963. * Aggregation is used to allow multiple IDirectInputXxx interfaces
  964. * to hang off one logical object.
  965. *
  966. * It is assumed that the prototype of the calling function is
  967. *
  968. * foo(PV this, PUNK punkOuter, RIID riid, PPV ppvObj);
  969. *
  970. * @parm ULONG | cb |
  971. *
  972. * Size of object. This does not include the hidden bookkeeping
  973. * bytes maintained by the object manager.
  974. *
  975. * @parm PV | vtbl |
  976. *
  977. * Pointer to primary vtbl for this object. Note that the
  978. * vtbl declaration macros include other magic goo near the vtbl,
  979. * which we consult in order to create the object.
  980. *
  981. * @parm PUNK | punkOuter |
  982. *
  983. * Controlling unknown for OLE aggregation. May be 0 to indicate
  984. * that the object is not aggregated.
  985. *
  986. * @parm RIID | riid |
  987. *
  988. * Interface requested.
  989. *
  990. * @parm PPV | ppvObj |
  991. *
  992. * Output pointer.
  993. *
  994. *****************************************************************************/
  995. STDMETHODIMP
  996. _Common_NewRiid_(ULONG cb, PV vtbl, PUNK punkOuter, RIID riid, PPV ppvObj,
  997. LPCSTR pszProc)
  998. {
  999. HRESULT hres;
  1000. EnterProc(Common_NewRiid, (_ "upG", cb, punkOuter, riid));
  1001. /*
  1002. * Note: __Common_New does not validate punkOuter or ppvObj,
  1003. * so we have to. Note also that we validate ppvObj first,
  1004. * so that it will be set to zero as soon as possible.
  1005. */
  1006. if (SUCCEEDED(hres = hresFullValidPcbOut_(ppvObj, cbX(*ppvObj), pszProc, 3)) &&
  1007. SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  1008. SUCCEEDED(hres = hresFullValidRiid_(riid, pszProc, 2))) {
  1009. if (fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown))) {
  1010. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  1011. if (SUCCEEDED(hres)) {
  1012. /*
  1013. * Move to the requested interface if we aren't aggregated.
  1014. * Don't do this if aggregated! or we will lose the private
  1015. * IUnknown and then the caller will be hosed.
  1016. */
  1017. if (punkOuter) {
  1018. PCI pci = *ppvObj;
  1019. *ppvObj = &pci->ci_unkPrivate;
  1020. } else {
  1021. PUNK punk = *ppvObj;
  1022. hres = Common_QueryInterface(punk, riid, ppvObj);
  1023. Common_Release(punk);
  1024. }
  1025. }
  1026. } else {
  1027. RD(RPF("%s: IID must be IID_IUnknown if created for aggregation",
  1028. pszProc));
  1029. *ppvObj = 0;
  1030. hres = CLASS_E_NOAGGREGATION;
  1031. }
  1032. }
  1033. ExitOleProcPpv(ppvObj);
  1034. return hres;
  1035. }
  1036. /*****************************************************************************
  1037. *
  1038. * Invoke_Release
  1039. *
  1040. * Release the object (if there is one) and wipe out the back-pointer.
  1041. * Note that we wipe out the value before calling the release, in order
  1042. * to ameliorate various weird callback conditions.
  1043. *
  1044. *****************************************************************************/
  1045. void EXTERNAL
  1046. Invoke_Release(PV pv)
  1047. {
  1048. LPUNKNOWN punk = (LPUNKNOWN) pvExchangePpvPv64(pv, 0);
  1049. if (punk) {
  1050. punk->lpVtbl->Release(punk);
  1051. }
  1052. }
  1053. /*****************************************************************************
  1054. *
  1055. * @doc INTERNAL
  1056. *
  1057. * @func HRESULT | hresPvVtbl_ |
  1058. *
  1059. * Validate that an interface pointer is what it claims to be.
  1060. * It must be the object associated with the <p vtbl>.
  1061. *
  1062. * @parm IN PV | pv |
  1063. *
  1064. * The thing that claims to be an interface pointer.
  1065. *
  1066. * @parm IN PV | vtbl |
  1067. *
  1068. * What it should be, or something equivalent to this.
  1069. *
  1070. * @returns
  1071. *
  1072. * Returns <c S_OK> if everything is okay, else
  1073. * <c E_INVALIDARG>.
  1074. *
  1075. *****************************************************************************/
  1076. HRESULT EXTERNAL
  1077. hresPvVtbl_(PV pv, PV vtbl, LPCSTR s_szProc)
  1078. {
  1079. PUNK punk = pv;
  1080. HRESULT hres;
  1081. AssertF(vtbl);
  1082. if (SUCCEEDED(hres = hresFullValidPitf(punk, 0))) {
  1083. #ifdef XDEBUG
  1084. if (punk->lpVtbl == vtbl) {
  1085. hres = S_OK;
  1086. } else {
  1087. RPF("ERROR %s: arg %d: invalid pointer", s_szProc, 0);
  1088. hres = E_INVALIDARG;
  1089. }
  1090. #else
  1091. /*
  1092. * ISSUE-2001/03/29-timgill Really only want to see the primary interface
  1093. * If we are looking for the primary interface,
  1094. * then allow any interface. All the dual-character set
  1095. * interfaces point all the vtbls at the same function,
  1096. * which uses hresPvT to validate. hresPvT passes the
  1097. * primary interface, hence the need to allow anything
  1098. * if you are asking for the primary interface.
  1099. *
  1100. * The problem is that this is too lenient in the case
  1101. * where we really want to see only the primary interface
  1102. * and not accept any of the secondaries.
  1103. *
  1104. */
  1105. UINT ivtbl;
  1106. PV vtblUnk = punk->lpVtbl;
  1107. PCI pci = (PV)&vtbl;
  1108. if (pci->ci_lib == 0) {
  1109. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  1110. if (pci->ci_rgvtbl[ivtbl] == vtblUnk) {
  1111. hres = S_OK;
  1112. goto found;
  1113. }
  1114. }
  1115. hres = E_INVALIDARG;
  1116. found:;
  1117. } else {
  1118. if (punk->lpVtbl == vtbl) {
  1119. hres = S_OK;
  1120. } else {
  1121. hres = E_INVALIDARG;
  1122. }
  1123. }
  1124. #endif
  1125. }
  1126. return hres;
  1127. }