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.

1463 lines
45 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. #if DIRECTINPUT_VERSION > 0x0300
  154. * rgvtbl
  155. * cbvtbl
  156. * D(dwSig) QIHelper
  157. * cHoldRef AppFinalizeProc
  158. * cRef FinalizeProc
  159. * punkOuter riid
  160. * unkPrivate 0
  161. * pFoo -> lpVtbl -> QueryInterface
  162. * lpVtbl2 Common_AddRef
  163. * data Common_Release
  164. * ... ...
  165. #else
  166. * rgvtbl
  167. * cbvtbl
  168. * D(dwSig) QIHelper
  169. * cRef FinalizeProc
  170. * punkOuter riid
  171. * unkPrivate 0
  172. * pFoo -> lpVtbl -> QueryInterface
  173. * lpVtbl2 Common_AddRef
  174. * data Common_Release
  175. * ... ...
  176. *
  177. * Essentially, we use the otherwise-unused space above the
  178. * pointers to record our bookkeeping information.
  179. *
  180. * punkOuter = controlling unknown, if object is aggregated
  181. * lpvtblPunk = special vtbl for controlling unknown to use
  182. * cHoldRef = Total reference count, including holds
  183. #if DIRECTINPUT_VERSION > 0x0300
  184. * cRef = object reference count from application
  185. #else
  186. * cRef = object reference count
  187. #endif
  188. * riid = object iid
  189. * rgvtbl = array of vtbls of supported interfaces
  190. * cbvtbl = size of array in bytes
  191. * QIHelper = QueryInterface helper for aggregation
  192. * AppFinalizeProc = Finalization procedure when app does last Release
  193. * FinalizeProc = Finalization procedure
  194. *
  195. * For secondary interfaces, it looks like this:
  196. *
  197. * riid
  198. * offset to primary interface
  199. * pFoo -> lpVtbl -> Forward_QueryInterface
  200. * Forward_AddRef
  201. * Forward_Release
  202. * ...
  203. *
  204. #if DIRECTINPUT_VERSION > 0x0300
  205. *
  206. * What is a hold?
  207. *
  208. * There is this annoying situation (particularly with
  209. * IDirectInputDevice) where an object wants to prevent itself
  210. * from being destroyed but we don't want to do an AddRef.
  211. *
  212. * The classic case (and for now the only one) is an
  213. * IDirectInputDevice which has been acquired. If we did
  214. * an honest AddRef() on the Acquire(), and the application does
  215. * a Release() without Unacquire()ing, then the device would
  216. * be acquired forever.
  217. *
  218. * If you thought that the Unacquire() in the finalization
  219. * would help, you'd be wrong, because the finalization happens
  220. * only when the last reference goes away, but the last reference
  221. * belongs to the device itself and will never go away until
  222. * the Unacquire() happens, which can't happen because the app
  223. * already lost its last reference to the device.
  224. *
  225. * So instead, we need to maintain *two* refcounts.
  226. *
  227. * cRef is the application-visible reference count, accessible
  228. * via PrivateAddRef() and PrivateRelease(). When this
  229. * drops to zero, we call the AppFinalize().
  230. *
  231. * cHoldRef is the "real" reference count. This is the sum of
  232. * cRef and the number of outstanding Common_Hold()s. When
  233. * this drops to zero, then the object is Finalize()d.
  234. *
  235. #endif
  236. *
  237. *****************************************************************************/
  238. /* WARNING! cin_dwSig must be first: ci_Start relies on it */
  239. /* WARNING! cin_unkPrivate must be last: punkPrivateThis relies on it */
  240. typedef struct CommonInfoN { /* This goes in front of the object */
  241. RD(ULONG cin_dwSig;) /* Signature (for parameter validation) */
  242. #if DIRECTINPUT_VERSION > 0x0300
  243. LONG cin_cHoldRef; /* Total refcount, incl. holds */
  244. #endif
  245. LONG cin_cRef; /* Object reference count */
  246. PUNK cin_punkOuter; /* Controlling unknown */
  247. IUnknown cin_unkPrivate; /* Private IUnknown */
  248. } CommonInfoN, CIN, *PCIN;
  249. typedef struct CommonInfoP { /* This is how we pun the object itself */
  250. PREVTBLP *cip_prevtbl; /* Vtbl of object (will be -1'd) */
  251. } CommonInfoP, CIP, *PCIP;
  252. typedef union CommonInfo {
  253. CIN cin[1];
  254. CIP cip[1];
  255. } CommonInfo, CI, *PCI;
  256. #define ci_dwSig cin[-1].cin_dwSig
  257. #define ci_cHoldRef cin[-1].cin_cHoldRef
  258. #define ci_cRef cin[-1].cin_cRef
  259. #define ci_punkOuter cin[-1].cin_punkOuter
  260. #define ci_unkPrivate cin[-1].cin_unkPrivate
  261. #define ci_rgfp cip[0].cip_prevtbl
  262. #define ci_tszClass cip[0].cip_prevtbl[-1].tszClass
  263. #define ci_rgvtbl cip[0].cip_prevtbl[-1].rgvtbl
  264. #define ci_cbvtbl cip[0].cip_prevtbl[-1].cbvtbl
  265. #define ci_QIHelper cip[0].cip_prevtbl[-1].QIHelper
  266. #define ci_AppFinalize cip[0].cip_prevtbl[-1].AppFinalizeProc
  267. #define ci_Finalize cip[0].cip_prevtbl[-1].FinalizeProc
  268. #define ci_riid cip[0].cip_prevtbl[-1].prevtbl.riid
  269. #define ci_lib cip[0].cip_prevtbl[-1].prevtbl.lib
  270. #ifdef XDEBUG
  271. #define ci_Start ci_dwSig
  272. #else
  273. #define ci_Start ci_cRef
  274. #endif
  275. #define ci_dwSignature 0x38162378 /* typed by my cat */
  276. /*****************************************************************************
  277. *
  278. * Common_Finalize (from Common_Release)
  279. *
  280. * By default, no finalization is necessary.
  281. *
  282. *****************************************************************************/
  283. void EXTERNAL
  284. Common_Finalize(PV pv)
  285. {
  286. SquirtSqflPtszV(sqfl, TEXT("Common_Finalize(%08x)"), pv);
  287. }
  288. /*****************************************************************************
  289. *
  290. * "Private" IUnknown methods
  291. *
  292. * When a COM object is aggregated, it exports *two* IUnknown
  293. * interfaces.
  294. *
  295. * The "private" IUnknown is the one that is returned to the
  296. * controlling unknown. It is this unknown that the controlling
  297. * unknown uses to manipulate the refcount on the inner object.
  298. *
  299. * The "public" IUnknown is the one that all external callers see.
  300. * For this, we just hand out the controlling unknown.
  301. *
  302. *****************************************************************************/
  303. Secondary_Interface(CCommon, IUnknown);
  304. /*****************************************************************************
  305. *
  306. * @doc INTERNAL
  307. *
  308. * @func PV | thisPunk |
  309. *
  310. * Convert a private punk (&cin_unkPrivate) into the beginning of
  311. * the actual object.
  312. *
  313. * @parm PUNK | punkPrivate |
  314. *
  315. * The private punk (&cin_unkPrivate) corresponding to some
  316. * object we are managing.
  317. *
  318. * @returns
  319. *
  320. * The object pointer on success, or 0 on error.
  321. *
  322. * @comm
  323. *
  324. * We do not return an <t HRESULT> on error, because the
  325. * callers of the procedure typically do not return
  326. * <t HRESULT>s themselves.
  327. *
  328. *****************************************************************************/
  329. #ifndef XDEBUG
  330. #define thisPunk_(punk, z) \
  331. _thisPunk_(punk) \
  332. #endif
  333. PV INLINE
  334. thisPunk_(PUNK punkPrivate, LPCSTR s_szProc)
  335. {
  336. PV pv;
  337. if (SUCCEEDED(hresFullValidPitf(punkPrivate, 0))) {
  338. if (punkPrivate->lpVtbl == Class_Vtbl(CCommon, IUnknown)) {
  339. pv = pvAddPvCb(punkPrivate,
  340. cbX(CIN) - FIELD_OFFSET(CIN, cin_unkPrivate));
  341. } else {
  342. RPF("%s: Invalid parameter 0", s_szProc);
  343. pv = 0;
  344. }
  345. } else {
  346. RPF("%s: Invalid parameter 0", s_szProc);
  347. pv = 0;
  348. }
  349. return pv;
  350. }
  351. #define thisPunk(punk) \
  352. thisPunk_(punk, s_szProc) \
  353. /*****************************************************************************
  354. *
  355. * @doc INTERNAL
  356. *
  357. * @func HRESULT | Common_QIHelper |
  358. *
  359. * Called when we can't find any interface in the standard list.
  360. * See if there's a dynamic interface we can use.
  361. *
  362. * Objects are expected to override this method if
  363. * they implement dynamic interfaces.
  364. *
  365. * @parm PV | pv |
  366. *
  367. * The object being queried.
  368. *
  369. * @parm RIID | riid |
  370. *
  371. * The interface being requested.
  372. *
  373. * @parm PPV | ppvObj |
  374. *
  375. * Output pointer.
  376. *
  377. * @returns
  378. *
  379. * Always returns <c E_NOINTERFACE>.
  380. *
  381. *****************************************************************************/
  382. STDMETHODIMP
  383. Common_QIHelper(PV pv, RIID riid, PPV ppvObj)
  384. {
  385. HRESULT hres;
  386. *ppvObj = NULL;
  387. hres = E_NOINTERFACE;
  388. return hres;
  389. }
  390. /*****************************************************************************
  391. *
  392. * @doc INTERNAL
  393. *
  394. * @func HRESULT | Common_PrivateQueryInterface |
  395. *
  396. * Common implementation of <mf IUnknown::QueryInterface> for
  397. * the "private <i IUnknown>".
  398. *
  399. * Note that we AddRef through the public <i IUnknown>
  400. * (<ie>, through the controlling unknown).
  401. * That's part of the rules of aggregation,
  402. * and we have to follow them in order to keep the controlling
  403. * unknown from getting confused.
  404. *
  405. * @parm PUNK | punkPrivate |
  406. *
  407. * The object being queried.
  408. *
  409. * @parm RIID | riid |
  410. *
  411. * The interface being requested.
  412. *
  413. * @parm PPV | ppvObj |
  414. *
  415. * Output pointer.
  416. *
  417. *****************************************************************************/
  418. /*****************************************************************************
  419. *
  420. * The "Ensure jump is to end" remark boils down to the fact that
  421. * compilers have failed to recognize this:
  422. *
  423. * for (i = 0; i < n; i++) {
  424. * if (cond) {
  425. * mumble();
  426. * break;
  427. * }
  428. * }
  429. * if (i >= n) {
  430. * gurgle();
  431. * }
  432. *
  433. * and turn it into this:
  434. *
  435. * for (i = 0; i < n; i++) {
  436. * if (cond) {
  437. * mumble();
  438. * goto done;
  439. * }
  440. * }
  441. * gurgle();
  442. * done:;
  443. *
  444. * But even with this help, the compiler emits pretty dumb code.
  445. *
  446. *****************************************************************************/
  447. STDMETHODIMP
  448. Common_PrivateQueryInterface(PUNK punkPrivate, REFIID riid, PPV ppvObj)
  449. {
  450. PCI pci;
  451. HRESULT hres;
  452. EnterProcR(IUnknown::QueryInterface, (_ "pG", punkPrivate, riid));
  453. pci = thisPunk(punkPrivate);
  454. if (pci) {
  455. if (IsEqualIID(riid, &IID_IUnknown)) {
  456. *ppvObj = pci;
  457. OLE_AddRef(pci->ci_punkOuter);
  458. hres = S_OK;
  459. } else {
  460. UINT ivtbl;
  461. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  462. if (IsEqualIID(riid, ((PCI)(&pci->ci_rgvtbl[ivtbl]))->ci_riid)) {
  463. *ppvObj = pvAddPvCb(pci, ivtbl * sizeof(PV));
  464. OLE_AddRef(pci->ci_punkOuter);
  465. hres = S_OK;
  466. goto exit; /* Ensure jump is to end */
  467. }
  468. }
  469. hres = pci->ci_QIHelper(pci, riid, ppvObj);
  470. }
  471. } else {
  472. hres = E_INVALIDARG;
  473. }
  474. exit:;
  475. ExitOleProcPpv(ppvObj);
  476. return hres;
  477. }
  478. #if DIRECTINPUT_VERSION > 0x0300
  479. /*****************************************************************************
  480. *
  481. * @doc INTERNAL
  482. *
  483. * @func void | Common_FastHold |
  484. *
  485. * Increment the object hold count inline.
  486. *
  487. * @parm PV | pvObj |
  488. *
  489. * The object being held.
  490. *
  491. *****************************************************************************
  492. *
  493. * @doc INTERNAL
  494. *
  495. * @func void | Common_Hold |
  496. *
  497. * Increment the object hold count.
  498. *
  499. * @parm PV | pvObj |
  500. *
  501. * The object being held.
  502. *
  503. *****************************************************************************/
  504. void INLINE
  505. Common_FastHold(PV pvObj)
  506. {
  507. PCI pci = pvObj;
  508. InterlockedIncrement(&pci->ci_cHoldRef);
  509. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  510. D(SquirtSqflPtszV(sqflObj | sqflVerbose,
  511. TEXT("%s %p Common_FastHold ci_cRef(%d) ci_cHoldRef(%d)"),
  512. pci->ci_tszClass,
  513. pci,
  514. pci->ci_cRef,
  515. pci->ci_cHoldRef));
  516. }
  517. STDMETHODIMP_(void)
  518. Common_Hold(PV pvObj)
  519. {
  520. PCI pci = pvObj;
  521. AssertF(pvObj == _thisPv(pvObj)); /* Make sure it's the primary */
  522. AssertF(pci->ci_cHoldRef >= pci->ci_cRef);
  523. Common_FastHold(pvObj);
  524. }
  525. /*****************************************************************************
  526. *
  527. * @doc INTERNAL
  528. *
  529. * @func void | Common_FastUnhold |
  530. *
  531. * Decrement the object hold count. Assumes that the reference
  532. * count is <y not> dropping to zero.
  533. *
  534. * @parm PV | pvObj |
  535. *
  536. * The object being unheld.
  537. *
  538. *****************************************************************************
  539. *
  540. * @doc INTERNAL
  541. *
  542. * @func void | Common_Unhold |
  543. *
  544. * Decrement the object hold count. If the hold count drops
  545. * to zero, then the object is destroyed.
  546. *
  547. * @parm PV | pvObj |
  548. *
  549. * The object being unheld.
  550. *
  551. *****************************************************************************/
  552. void INLINE
  553. Common_FastUnhold(PV pvObj)
  554. {
  555. PCI pci = pvObj;
  556. AssertF(pci->ci_cHoldRef > 0);
  557. InterlockedDecrement(&pci->ci_cHoldRef);
  558. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  559. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_FastUnHold ci_cRef(%d) ci_cHoldRef(%d)"),
  560. pci->ci_tszClass,
  561. pci,
  562. pci->ci_cRef,
  563. pci->ci_cHoldRef));
  564. }
  565. STDMETHODIMP_(void)
  566. Common_Unhold(PV pvObj)
  567. {
  568. PCI pci = pvObj;
  569. AssertF(pci->ci_cHoldRef >= pci->ci_cRef);
  570. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  571. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_Unhold ci_cRef(%d) ci_cHoldRef(%d)"),
  572. pci->ci_tszClass,
  573. pci,
  574. pci->ci_cRef,
  575. pci->ci_cHoldRef-1));
  576. if (InterlockedDecrement(&pci->ci_cHoldRef) == 0) {
  577. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  578. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("Destroy %s %p "),
  579. pci->ci_tszClass,
  580. pci));
  581. /*
  582. * Last reference. Do an artifical addref so that
  583. * anybody who does an artificial addref during
  584. * finalization won't accidentally destroy us twice.
  585. */
  586. pci->ci_cHoldRef = 1;
  587. pci->ci_Finalize(pci);
  588. /* Artificial release is pointless: we're being freed */
  589. FreePv(pvSubPvCb(pci, sizeof(CIN)));
  590. DllRelease();
  591. }
  592. }
  593. #endif
  594. /*****************************************************************************
  595. *
  596. * @doc INTERNAL
  597. *
  598. * @func ULONG | Common_PrivateAddRef |
  599. *
  600. * Increment the object refcount.
  601. *
  602. * @parm PUNK | punkPrivate |
  603. *
  604. * The object being addref'd.
  605. *
  606. *****************************************************************************/
  607. STDMETHODIMP_(ULONG)
  608. Common_PrivateAddRef(PUNK punkPrivate)
  609. {
  610. PCI pci;
  611. ULONG ulRef;
  612. EnterProcR(IUnknown::AddRef, (_ "p", punkPrivate));
  613. pci = thisPunk(punkPrivate);
  614. if (pci) {
  615. #if DIRECTINPUT_VERSION <= 0x0300
  616. ulRef = ++pci->ci_cRef;
  617. #else
  618. /*
  619. * Don't let anyone AddRef from 0 to 1. This happens if
  620. * somebody does a terminal release, but we have an internal
  621. * hold on the object, and the app tries to do an AddRef
  622. * even though the object is "gone".
  623. *
  624. * Yes, there is a race condition here, but it's not
  625. * a big one, and this is only a rough test anyway.
  626. */
  627. if (pci->ci_cRef) {
  628. /*
  629. * We must use an interlocked operation in case two threads
  630. * do AddRef or Release simultaneously. Note that the hold
  631. * comes first, so that we never have the case where the
  632. * hold count is less than the reference count.
  633. */
  634. Common_Hold(pci);
  635. InterlockedIncrement(&pci->ci_cRef);
  636. ulRef = pci->ci_cRef;
  637. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  638. D(SquirtSqflPtszV(sqflObj , TEXT("%s %p Common_PrivateAddref ci_cRef(%d) ci_cHoldRef(%d)"),
  639. pci->ci_tszClass,
  640. pci,
  641. pci->ci_cRef,
  642. pci->ci_cHoldRef));
  643. } else {
  644. RPF("ERROR: %s: Attempting to addref a deleted object", s_szProc);
  645. ulRef = 0;
  646. }
  647. #endif
  648. } else {
  649. ulRef = 0;
  650. }
  651. ExitProcX(ulRef);
  652. return ulRef;
  653. }
  654. #if DIRECTINPUT_VERSION <= 0x0300
  655. /*****************************************************************************
  656. *
  657. * @doc INTERNAL
  658. *
  659. * @func ULONG | Common_PrivateRelease |
  660. *
  661. * Decrement the object refcount.
  662. *
  663. * If the object refcount drops to zero, finalize the object
  664. * and free it, then decrement the dll refcount.
  665. *
  666. * To protect against potential re-entrancy during finalization
  667. * (in case finalization does an artificial
  668. * <f AddRef>/<f Release>), we
  669. * do our own artificial <f AddRef>/<f Release> up front.
  670. *
  671. * @parm PUNK | punkPrivate |
  672. *
  673. * The object being release'd.
  674. *
  675. *****************************************************************************/
  676. STDMETHODIMP_(ULONG)
  677. Common_PrivateRelease(PUNK punkPrivate)
  678. {
  679. PCI pci;
  680. ULONG ulRc;
  681. EnterProcR(IUnknown::Release, (_ "p", punkPrivate));
  682. pci = thisPunk(punkPrivate);
  683. if (pci) {
  684. /*
  685. * Note that we don't actually decrement the refcount to
  686. * zero (if that's where it's going). This avoids a race
  687. * condition in case somebody with a non-refcounted-reference
  688. * to the object peeks at the refcount and gets confused
  689. * because it is zero!
  690. */
  691. ulRc = pci->ci_cRef - 1;
  692. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  693. D(SquirtSqflPtszV(sqflObj|sqflVerbose, TEXT("%s %p Common_PrivateRelease ci_cRef(%d) ci_cHoldRef(%d)"),
  694. pci->ci_tszClass,
  695. pci,
  696. ulRc,
  697. pci->ci_cHoldRef));
  698. if (ulRc == 0) {
  699. /*
  700. * Don't need artificial addref because we never actually
  701. * dropped the refcount to zero. We merely thought about
  702. * it.
  703. */
  704. AssertF(pci->ci_cRef == 1);
  705. pci->ci_Finalize(pci);
  706. /* Artificial release is pointless: we're being freed */
  707. FreePv(pvSubPvCb(pci, sizeof(CIN)));
  708. DllRelease();
  709. ulRc = 0;
  710. } else {
  711. /*
  712. * Not the last Release, so make this one count.
  713. */
  714. pci->ci_cRef = ulRc;
  715. }
  716. } else {
  717. ulRc = 0;
  718. }
  719. ExitProcX(ulRc);
  720. return ulRc;
  721. }
  722. #else
  723. /*****************************************************************************
  724. *
  725. * @doc INTERNAL
  726. *
  727. * @func ULONG | Common_PrivateRelease |
  728. *
  729. * Decrement the object refcount. Note that decrementing
  730. * the hold count may cause the object to vanish, so stash
  731. * the resulting refcount ahead of time.
  732. *
  733. * Note that we release the hold last, so that the hold
  734. * count is always at least as great as the refcount.
  735. *
  736. * @parm PUNK | punkPrivate |
  737. *
  738. * The object being release'd.
  739. *
  740. *****************************************************************************/
  741. STDMETHODIMP_(ULONG)
  742. Common_PrivateRelease(PUNK punkPrivate)
  743. {
  744. PCI pci;
  745. ULONG ulRc;
  746. EnterProcR(IUnknown::Release, (_ "p", punkPrivate));
  747. pci = thisPunk(punkPrivate);
  748. if (pci) {
  749. LONG lRc;
  750. /*
  751. * We must use an interlocked operation in case two threads
  752. * do AddRef or Release simultaneously. And if the count
  753. * drops negative, then ignore it. (This means that the
  754. * app is Release()ing something too many times.)
  755. */
  756. lRc = InterlockedDecrement(&pci->ci_cRef);
  757. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  758. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p Common_PrivateRelease ci_cRef(%d) ci_cHoldRef(%d)"),
  759. pci->ci_tszClass,
  760. pci->ci_tszClass,
  761. pci->ci_cRef,
  762. pci->ci_cHoldRef));
  763. if (lRc > 0) {
  764. /*
  765. * Not the last release; release the hold and return
  766. * the resulting refcount. Note that we can safely
  767. * use a fast unhold here, because there will always
  768. * be a hold lying around to match the refcount we
  769. * just got rid of.
  770. */
  771. Common_FastUnhold(pci);
  772. /*
  773. * This isn't 100% accurate, but it's close enough.
  774. * (OLE notes that the value is good only for debugging.)
  775. */
  776. ulRc = pci->ci_cRef;
  777. } else if (lRc == 0) {
  778. /*
  779. * That was the last application-visible reference.
  780. * Do app-level finalization.
  781. */
  782. pci->ci_AppFinalize(pci);
  783. /*
  784. * Note that we can't do
  785. * a fast unhold here, because this might be the last
  786. * hold.
  787. */
  788. Common_Unhold(pci);
  789. ulRc = 0;
  790. } else {
  791. /*
  792. * The app messed up big time.
  793. */
  794. RPF("ERROR: %s: Attempting to release a deleted object",
  795. s_szProc);
  796. ulRc = 0;
  797. }
  798. } else {
  799. ulRc = 0;
  800. }
  801. ExitProcX(ulRc);
  802. return ulRc;
  803. }
  804. #endif
  805. /*****************************************************************************
  806. *
  807. * @doc INTERNAL
  808. *
  809. * @global IUnknownVtbl * | c_lpvtblPunk |
  810. *
  811. * The special IUnknown object that only the controlling unknown
  812. * knows about.
  813. *
  814. * This is the one that calls the "Real" services. All the normal
  815. * vtbl's go through the controlling unknown (which, if we are
  816. * not aggregated, points to ourselves).
  817. *
  818. *****************************************************************************/
  819. #pragma BEGIN_CONST_DATA
  820. _Secondary_Interface_Begin(CCommon, IUnknown,
  821. (ULONG)(FIELD_OFFSET(CIN, cin_unkPrivate) - cbX(CIN)),
  822. Common_Private)
  823. _Secondary_Interface_End(CCommon, IUnknown)
  824. #pragma END_CONST_DATA
  825. /*****************************************************************************
  826. *
  827. * "Public" IUnknown methods
  828. *
  829. * These simply forward through the controlling unknown.
  830. *
  831. *****************************************************************************/
  832. /*****************************************************************************
  833. *
  834. * @doc INTERNAL
  835. *
  836. * @func HRESULT | Common_QueryInterface |
  837. *
  838. * Forward through the controlling unknown.
  839. *
  840. * @parm PUNK | punk |
  841. *
  842. * The object being queried.
  843. *
  844. * @parm RIID | riid |
  845. *
  846. * The interface being requested.
  847. *
  848. * @parm PPV | ppvObj |
  849. *
  850. * Output pointer.
  851. *
  852. *****************************************************************************/
  853. STDMETHODIMP
  854. Common_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  855. {
  856. HRESULT hres;
  857. EnterProcR(IUnknown::QueryInterface, (_ "pG", pv, riid));
  858. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0)) &&
  859. SUCCEEDED(hres = hresFullValidRiid(riid, 1)) &&
  860. SUCCEEDED(hres = hresFullValidPcbOut(ppvObj, cbX(*ppvObj), 2))) {
  861. PCI pci = _thisPv(pv);
  862. AssertF(pci->ci_punkOuter);
  863. hres = OLE_QueryInterface(pci->ci_punkOuter, riid, ppvObj);
  864. }
  865. ExitOleProcPpv(ppvObj);
  866. return hres;
  867. }
  868. /*****************************************************************************
  869. *
  870. * @doc INTERNAL
  871. *
  872. * @func ULONG | Common_AddRef |
  873. *
  874. * Forward through the controlling unknown.
  875. *
  876. * @parm PUNK | punk |
  877. *
  878. * The object being addref'd.
  879. *
  880. *****************************************************************************/
  881. STDMETHODIMP_(ULONG)
  882. Common_AddRef(PV pv)
  883. {
  884. ULONG ulRef;
  885. HRESULT hres;
  886. EnterProcR(IUnknown::AddRef, (_ "p", pv));
  887. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  888. PCI pci = _thisPv(pv);
  889. ulRef = OLE_AddRef(pci->ci_punkOuter);
  890. } else {
  891. ulRef = 0;
  892. }
  893. ExitProcX(ulRef);
  894. return ulRef;
  895. }
  896. /*****************************************************************************
  897. *
  898. * @doc INTERNAL
  899. *
  900. * @func ULONG | Common_Release |
  901. *
  902. * Forward through the controlling unknown.
  903. *
  904. * @parm PUNK | punk |
  905. *
  906. * Object being release'd.
  907. *
  908. *****************************************************************************/
  909. STDMETHODIMP_(ULONG)
  910. Common_Release(PV pv)
  911. {
  912. ULONG ulRc;
  913. HRESULT hres;
  914. EnterProcR(IUnknown::Release, (_ "p", pv));
  915. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  916. PCI pci = _thisPv(pv);
  917. ulRc = OLE_Release(pci->ci_punkOuter);
  918. } else {
  919. ulRc = 0;
  920. }
  921. ExitProcX(ulRc);
  922. return ulRc;
  923. }
  924. /*****************************************************************************
  925. *
  926. * @doc INTERNAL
  927. *
  928. * @func HRESULT | __Common_New |
  929. *
  930. * Create a new object with refcount 1 and the specific vtbl.
  931. * All other fields are zero-initialized. All parameters must
  932. * already be validated.
  933. *
  934. * @parm ULONG | cb |
  935. *
  936. * Size of object. This does not include the hidden bookkeeping
  937. * bytes maintained by the object manager.
  938. *
  939. * @parm PUNK | punkOuter |
  940. *
  941. * Controlling unknown for OLE aggregation. May be 0 to indicate
  942. * that the object is not aggregated.
  943. *
  944. * @parm PV | vtbl |
  945. *
  946. * Pointer to primary vtbl for this object. Note that the
  947. * vtbl declaration macros include other magic goo near the vtbl,
  948. * which we consult in order to create the object.
  949. *
  950. * @parm PPV | ppvObj |
  951. *
  952. * Output pointer.
  953. *
  954. *****************************************************************************/
  955. STDMETHODIMP
  956. __Common_New(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj)
  957. {
  958. HRESULT hres;
  959. EnterProc(__Common_New, (_ "uxx", cb, punkOuter, vtbl));
  960. hres = AllocCbPpv(cb + sizeof(CIN), ppvObj);
  961. if (SUCCEEDED(hres)) {
  962. PCI pciO = (PV)&vtbl;
  963. PCI pci = pvAddPvCb(*ppvObj, sizeof(CIN));
  964. RD(pci->ci_dwSig = ci_dwSignature);
  965. pci->ci_unkPrivate.lpVtbl = Class_Vtbl(CCommon, IUnknown);
  966. if (punkOuter) {
  967. pci->ci_punkOuter = punkOuter;
  968. } else {
  969. pci->ci_punkOuter = &pci->ci_unkPrivate;
  970. }
  971. CopyMemory(pci, pciO->ci_rgvtbl, pciO->ci_cbvtbl);
  972. *ppvObj = pci;
  973. /*
  974. * On an X86, it is simpler to increment a variable up
  975. * from zero to one. On a RISC, it is simpler to
  976. * store the value one directly.
  977. */
  978. #ifdef _X86_
  979. #if DIRECTINPUT_VERSION > 0x0300
  980. pci->ci_cHoldRef++;
  981. #endif
  982. pci->ci_cRef++;
  983. #else
  984. #if DIRECTINPUT_VERSION > 0x0300
  985. pci->ci_cHoldRef = 1;
  986. #endif
  987. pci->ci_cRef = 1;
  988. #endif
  989. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  990. D(SquirtSqflPtszV(sqflObj | sqflVerbose, TEXT("%s %p __Common_New ci_cRef(%d) ci_cHoldRef(%d)"),
  991. pci->ci_tszClass,
  992. pci,
  993. pci->ci_cRef,
  994. pci->ci_cHoldRef
  995. ));
  996. DllAddRef();
  997. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  998. D(SquirtSqflPtszV(sqflObj, TEXT("Created %s %p "),
  999. pci->ci_tszClass,
  1000. pci));
  1001. hres = S_OK;
  1002. }
  1003. ExitOleProcPpv(ppvObj);
  1004. return hres;
  1005. }
  1006. /*****************************************************************************
  1007. *
  1008. * @doc INTERNAL
  1009. *
  1010. * @func HRESULT | _Common_New_ |
  1011. *
  1012. * Create a new object with refcount 1 and the specific vtbl.
  1013. * All other fields are zero-initialized. This entry point
  1014. * validates parameters.
  1015. *
  1016. * @parm ULONG | cb |
  1017. *
  1018. * Size of object. This does not include the hidden bookkeeping
  1019. * bytes maintained by the object manager.
  1020. *
  1021. * @parm PUNK | punkOuter |
  1022. *
  1023. * Controlling unknown for OLE aggregation. May be 0 to indicate
  1024. * that the object is not aggregated.
  1025. *
  1026. * @parm PV | vtbl |
  1027. *
  1028. * Pointer to primary vtbl for this object. Note that the
  1029. * vtbl declaration macros include other magic goo near the vtbl,
  1030. * which we consult in order to create the object.
  1031. *
  1032. * @parm PPV | ppvObj |
  1033. *
  1034. * Output pointer.
  1035. *
  1036. *****************************************************************************/
  1037. STDMETHODIMP
  1038. _Common_New_(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj, LPCSTR pszProc)
  1039. {
  1040. HRESULT hres;
  1041. EnterProc(_Common_New, (_ "uxx", cb, punkOuter, vtbl));
  1042. if (SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  1043. SUCCEEDED(hres = hresFullValidPcbOut_(ppvObj, cbX(*ppvObj), pszProc, 3))) {
  1044. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  1045. }
  1046. ExitOleProcPpv(ppvObj);
  1047. return hres;
  1048. }
  1049. /*****************************************************************************
  1050. *
  1051. * @doc INTERNAL
  1052. *
  1053. * @func HRESULT | _Common_NewRiid_ |
  1054. *
  1055. * Create a new object with refcount 1 and the specific vtbl,
  1056. * but only if the object supports the indicated interface.
  1057. * All other fields are zero-initialized.
  1058. *
  1059. * If punkOut is nonzero, then the object is being created for
  1060. * aggregation. The interface must then be &IID_IUnknown.
  1061. *
  1062. * Aggregation is used to allow multiple IDirectInputXxx interfaces
  1063. * to hang off one logical object.
  1064. *
  1065. * It is assumed that the prototype of the calling function is
  1066. *
  1067. * foo(PV this, PUNK punkOuter, RIID riid, PPV ppvObj);
  1068. *
  1069. * @parm ULONG | cb |
  1070. *
  1071. * Size of object. This does not include the hidden bookkeeping
  1072. * bytes maintained by the object manager.
  1073. *
  1074. * @parm PV | vtbl |
  1075. *
  1076. * Pointer to primary vtbl for this object. Note that the
  1077. * vtbl declaration macros include other magic goo near the vtbl,
  1078. * which we consult in order to create the object.
  1079. *
  1080. * @parm PUNK | punkOuter |
  1081. *
  1082. * Controlling unknown for OLE aggregation. May be 0 to indicate
  1083. * that the object is not aggregated.
  1084. *
  1085. * @parm RIID | riid |
  1086. *
  1087. * Interface requested.
  1088. *
  1089. * @parm PPV | ppvObj |
  1090. *
  1091. * Output pointer.
  1092. *
  1093. *****************************************************************************/
  1094. STDMETHODIMP
  1095. _Common_NewRiid_(ULONG cb, PV vtbl, PUNK punkOuter, RIID riid, PPV ppvObj,
  1096. LPCSTR pszProc)
  1097. {
  1098. HRESULT hres;
  1099. EnterProc(Common_NewRiid, (_ "upG", cb, punkOuter, riid));
  1100. /*
  1101. * Note: __Common_New does not validate punkOuter or ppvObj,
  1102. * so we have to. Note also that we validate ppvObj first,
  1103. * so that it will be set to zero as soon as possible.
  1104. */
  1105. if (SUCCEEDED(hres = hresFullValidPcbOut_(ppvObj, cbX(*ppvObj), pszProc, 3)) &&
  1106. SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  1107. SUCCEEDED(hres = hresFullValidRiid_(riid, pszProc, 2))) {
  1108. if (fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown))) {
  1109. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  1110. if (SUCCEEDED(hres)) {
  1111. /*
  1112. * Move to the requested interface if we aren't aggregated.
  1113. * Don't do this if aggregated! or we will lose the private
  1114. * IUnknown and then the caller will be hosed.
  1115. */
  1116. if (punkOuter) {
  1117. PCI pci = *ppvObj;
  1118. *ppvObj = &pci->ci_unkPrivate;
  1119. } else {
  1120. PUNK punk = *ppvObj;
  1121. hres = Common_QueryInterface(punk, riid, ppvObj);
  1122. Common_Release(punk);
  1123. }
  1124. }
  1125. } else {
  1126. RD(RPF("%s: IID must be IID_IUnknown if created for aggregation",
  1127. pszProc));
  1128. *ppvObj = 0;
  1129. hres = CLASS_E_NOAGGREGATION;
  1130. }
  1131. }
  1132. ExitOleProcPpv(ppvObj);
  1133. return hres;
  1134. }
  1135. /*****************************************************************************
  1136. *
  1137. * Invoke_Release
  1138. *
  1139. * Release the object (if there is one) and wipe out the back-pointer.
  1140. * Note that we wipe out the value before calling the release, in order
  1141. * to ameliorate various weird callback conditions.
  1142. *
  1143. *****************************************************************************/
  1144. void EXTERNAL
  1145. Invoke_Release(PV pv)
  1146. {
  1147. LPUNKNOWN punk = (LPUNKNOWN) pvExchangePpvPv64(pv, 0);
  1148. if (punk) {
  1149. punk->lpVtbl->Release(punk);
  1150. }
  1151. }
  1152. #ifdef IDirectInputDevice2Vtbl
  1153. /*****************************************************************************
  1154. *
  1155. * @doc INTERNAL
  1156. *
  1157. * @func HRESULT | hresPvVtbl2_ |
  1158. *
  1159. * Validate that an interface pointer is what it claims to be.
  1160. * It must be the object associated with the <p vtbl> or
  1161. * the object associated with the <p vtbl2>.
  1162. *
  1163. * @parm IN PV | pv |
  1164. *
  1165. * The thing that claims to be an interface pointer.
  1166. *
  1167. * @parm IN PV | vtbl |
  1168. *
  1169. * What it should be, or something equivalent to this.
  1170. *
  1171. * @parm IN PV | vtbl2 |
  1172. *
  1173. * The other thing it should be, if it isn't <p vtbl>.
  1174. *
  1175. * @returns
  1176. *
  1177. * Returns <c S_OK> if everything is okay, else
  1178. * <c E_INVALIDARG>.
  1179. *
  1180. *****************************************************************************/
  1181. HRESULT EXTERNAL
  1182. hresPvVtbl2_(PV pv, PV vtbl, PV vtbl2, LPCSTR s_szProc)
  1183. {
  1184. PUNK punk = pv;
  1185. HRESULT hres;
  1186. AssertF(vtbl);
  1187. if (SUCCEEDED(hres = hresFullValidPitf(punk, 0))) {
  1188. #ifdef XDEBUG
  1189. if (punk->lpVtbl == vtbl || punk->lpVtbl == vtbl2) {
  1190. hres = S_OK;
  1191. } else {
  1192. RPF("ERROR %s: arg %d: invalid pointer", s_szProc, 0);
  1193. hres = E_INVALIDARG;
  1194. }
  1195. #else
  1196. /*
  1197. * ISSUE-2001/03/29-timgill Really only want to see the primary interface
  1198. * If we are looking for the primary interface,
  1199. * then allow any interface. All the dual-character set
  1200. * interfaces point all the vtbls at the same function,
  1201. * which uses hresPvT to validate. hresPvT passes the
  1202. * primary interface, hence the need to allow anything
  1203. * if you are asking for the primary interface.
  1204. *
  1205. * The problem is that this is too lenient in the case
  1206. * where we really want to see only the primary interface
  1207. * and not accept any of the secondaries.
  1208. *
  1209. */
  1210. UINT ivtbl;
  1211. PV vtblUnk = punk->lpVtbl;
  1212. PCI pci = (PV)&vtbl;
  1213. if (pci->ci_lib == 0) {
  1214. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  1215. if (pci->ci_rgvtbl[ivtbl] == vtblUnk) {
  1216. hres = S_OK;
  1217. goto found;
  1218. }
  1219. }
  1220. hres = E_INVALIDARG;
  1221. found:;
  1222. } else {
  1223. if (punk->lpVtbl == vtbl || punk->lpVtbl == vtbl2) {
  1224. hres = S_OK;
  1225. } else {
  1226. hres = E_INVALIDARG;
  1227. }
  1228. }
  1229. #endif
  1230. }
  1231. return hres;
  1232. }
  1233. /*****************************************************************************
  1234. *
  1235. * @doc INTERNAL
  1236. *
  1237. * @func HRESULT | hresPvVtbl_ |
  1238. *
  1239. * Validate that an interface pointer is what it claims to be.
  1240. * It must be the object associated with the <p vtbl>.
  1241. *
  1242. * @parm IN PV | pv |
  1243. *
  1244. * The thing that claims to be an interface pointer.
  1245. *
  1246. * @parm IN PV | vtbl |
  1247. *
  1248. * What it should be, or something equivalent to this.
  1249. *
  1250. * @returns
  1251. *
  1252. * Returns <c S_OK> if everything is okay, else
  1253. * <c E_INVALIDARG>.
  1254. *
  1255. *****************************************************************************/
  1256. HRESULT EXTERNAL
  1257. hresPvVtbl_(PV pv, PV vtbl, LPCSTR s_szProc)
  1258. {
  1259. return hresPvVtbl2_(pv, vtbl, vtbl, s_szProc);
  1260. }
  1261. #else
  1262. /*****************************************************************************
  1263. *
  1264. * @doc INTERNAL
  1265. *
  1266. * @func HRESULT | hresPvVtbl_ |
  1267. *
  1268. * Validate that an interface pointer is what it claims to be.
  1269. * It must be the object associated with the <p vtbl>.
  1270. *
  1271. * @parm IN PV | pv |
  1272. *
  1273. * The thing that claims to be an interface pointer.
  1274. *
  1275. * @parm IN PV | vtbl |
  1276. *
  1277. * What it should be, or something equivalent to this.
  1278. *
  1279. * @returns
  1280. *
  1281. * Returns <c S_OK> if everything is okay, else
  1282. * <c E_INVALIDARG>.
  1283. *
  1284. *****************************************************************************/
  1285. HRESULT EXTERNAL
  1286. hresPvVtbl_(PV pv, PV vtbl, LPCSTR s_szProc)
  1287. {
  1288. PUNK punk = pv;
  1289. HRESULT hres;
  1290. AssertF(vtbl);
  1291. if (SUCCEEDED(hres = hresFullValidPitf(punk, 0))) {
  1292. #ifdef XDEBUG
  1293. if (punk->lpVtbl == vtbl) {
  1294. hres = S_OK;
  1295. } else {
  1296. RPF("ERROR %s: arg %d: invalid pointer", s_szProc, 0);
  1297. hres = E_INVALIDARG;
  1298. }
  1299. #else
  1300. /*
  1301. * ISSUE-2001/03/29-timgill Really only want to see the primary interface
  1302. * If we are looking for the primary interface,
  1303. * then allow any interface. All the dual-character set
  1304. * interfaces point all the vtbls at the same function,
  1305. * which uses hresPvT to validate. hresPvT passes the
  1306. * primary interface, hence the need to allow anything
  1307. * if you are asking for the primary interface.
  1308. *
  1309. * The problem is that this is too lenient in the case
  1310. * where we really want to see only the primary interface
  1311. * and not accept any of the secondaries.
  1312. *
  1313. */
  1314. UINT ivtbl;
  1315. PV vtblUnk = punk->lpVtbl;
  1316. PCI pci = (PV)&vtbl;
  1317. if (pci->ci_lib == 0) {
  1318. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  1319. if (pci->ci_rgvtbl[ivtbl] == vtblUnk) {
  1320. hres = S_OK;
  1321. goto found;
  1322. }
  1323. }
  1324. hres = E_INVALIDARG;
  1325. found:;
  1326. } else {
  1327. if (punk->lpVtbl == vtbl) {
  1328. hres = S_OK;
  1329. } else {
  1330. hres = E_INVALIDARG;
  1331. }
  1332. }
  1333. #endif
  1334. }
  1335. return hres;
  1336. }
  1337. #endif