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.

959 lines
27 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. /*
  19. #include <windows.h>
  20. #include <windowsx.h>
  21. #include <objbase.h>
  22. #include <regstr.h>
  23. #include <setupapi.h>
  24. #include <cfgmgr32.h>
  25. #include <devguid.h>
  26. #include <stdio.h>
  27. #include <stilog.h>
  28. #include <stiregi.h>
  29. #include <sti.h>
  30. #include <stierr.h>
  31. #include <stiusd.h>
  32. #include "wia.h"
  33. #include "stipriv.h"
  34. #include "stiapi.h"
  35. #include "stirc.h"
  36. #include "debug.h"
  37. */
  38. #include "sticomm.h"
  39. #define DbgFl DbgFlCommon
  40. /*****************************************************************************
  41. *
  42. * USAGE FOR OLE OBJECTS
  43. *
  44. * Suppose you want to implement an object called CObj that supports
  45. * the interfaces Foo, Bar, and Baz. Suppose that you opt for
  46. * Foo as the primary interface.
  47. *
  48. * >> NAMING CONVENTION <<
  49. *
  50. * COM objects begin with the letter "C".
  51. *
  52. * (1) Declare the primary and secondary vtbls.
  53. *
  54. * Primary_Interface(CObj, IFoo);
  55. * Secondary_Interface(CObj, IBar);
  56. * Secondary_Interface(CObj, IBaz);
  57. *
  58. * (3) Declare the object itself.
  59. *
  60. * typedef struct CObj {
  61. * IFoo foo; // Primary must come first
  62. * IBar bar;
  63. * IBaz baz;
  64. * ... other fields ...
  65. * } CObj;
  66. *
  67. * (4) Implement the methods.
  68. *
  69. * You may *not* reimplement the AddRef and Release methods!
  70. * although you can subclass them.
  71. *
  72. * (5) To allocate an object of the appropriate type, write
  73. *
  74. * hres = Common_NewRiid(CObj, punkOuter, riid, ppvOut);
  75. *
  76. * or, if the object is variable-sized,
  77. *
  78. * hres = Common_NewCbRiid(cb, CObj, punkouter, riid, ppvOut);
  79. *
  80. * Common_NewRiid and Common_NewCbRiid will initialize both the
  81. * primary and secondary vtbls.
  82. *
  83. * (6) Define the object signature.
  84. *
  85. * #pragma BEGIN_CONST_DATA
  86. *
  87. * #define CObj_Signature 0x204A424F // "OBJ "
  88. *
  89. * (7) Define the object template.
  90. *
  91. * Interface_Template_Begin(CObj)
  92. * Primary_Interface_Template(CObj, IFoo)
  93. * Secondary_Interface_Template(CObj, IBar)
  94. * Secondary_Interface_Template(CObj, IBaz)
  95. * Interface_Template_End(CObj)
  96. *
  97. * (8) Define the interface descriptors.
  98. *
  99. * // The macros will declare QueryInterface, AddRef and Release
  100. * // so don't list them again
  101. *
  102. * Primary_Interface_Begin(CObj, IFoo)
  103. * CObj_FooMethod1,
  104. * CObj_FooMethod2,
  105. * CObj_FooMethod3,
  106. * CObj_FooMethod4,
  107. * Primary_Interface_End(Obj, IFoo)
  108. *
  109. * Secondary_Interface_Begin(CObj, IBar, bar)
  110. * CObj_Bar_BarMethod1,
  111. * CObj_Bar_BarMethod2,
  112. * Secondary_Interface_Begin(CObj, IBar, bar)
  113. *
  114. * Secondary_Interface_Begin(CObj, IBaz, baz)
  115. * CObj_Baz_BazMethod1,
  116. * CObj_Baz_BazMethod2,
  117. * CObj_Baz_BazMethod3,
  118. * Secondary_Interface_Begin(CObj, IBaz, baz)
  119. *
  120. *****************************************************************************/
  121. /*****************************************************************************
  122. *
  123. * USAGE FOR NON-OLE OBJECTS
  124. *
  125. * All objects are COM objects, even if they are never given out.
  126. * In the simplest case, it just derives from IUnknown.
  127. *
  128. * Suppose you want to implement an object called Obj which is
  129. * used only internally.
  130. *
  131. * (1) Declare the vtbl.
  132. *
  133. * Simple_Interface(Obj);
  134. *
  135. * (3) Declare the object itself.
  136. *
  137. * typedef struct Obj {
  138. * IUnknown unk;
  139. * ... other fields ...
  140. * } Obj;
  141. *
  142. * (4) Implement the methods.
  143. *
  144. * You may *not* override the QueryInterface, AddRef or
  145. * Release methods!
  146. *
  147. * (5) Allocating an object of the appropriate type is the same
  148. * as with OLE objects.
  149. *
  150. * (6) Define the "vtbl".
  151. *
  152. * #pragma BEGIN_CONST_DATA
  153. *
  154. * Simple_Interface_Begin(Obj)
  155. * Simple_Interface_End(Obj)
  156. *
  157. * That's right, nothing goes between the Begin and the End.
  158. *
  159. *****************************************************************************/
  160. /*****************************************************************************
  161. *
  162. * CommonInfo
  163. *
  164. * Information tracked for all common objects.
  165. *
  166. * A common object looks like this:
  167. *
  168. * rgvtbl
  169. * cbvtbl
  170. * D(dwSig) QIHelper
  171. * cRef FinalizeProc
  172. * punkOuter riid
  173. * unkPrivate 0
  174. * pFoo -> lpVtbl -> QueryInterface
  175. * lpVtbl2 Common_AddRef
  176. * data Common_Release
  177. * ... ...
  178. *
  179. * Essentially, we use the otherwise-unused space above the
  180. * pointers to record our bookkeeping information.
  181. *
  182. * punkOuter = controlling unknown, if object is aggregated
  183. * lpvtblPunk = special vtbl for controlling unknown to use
  184. * cRef = object reference count
  185. * riid = object iid
  186. * rgvtbl = array of vtbls of supported interfaces
  187. * cbvtbl = size of array in bytes
  188. * QIHelper = QueryInterface helper for aggregation
  189. * FinalizeProc = Finalization procedure
  190. *
  191. * For secondary interfaces, it looks like this:
  192. *
  193. * riid
  194. * offset to primary interface
  195. * pFoo -> lpVtbl -> Forward_QueryInterface
  196. * Forward_AddRef
  197. * Forward_Release
  198. * ...
  199. *
  200. *****************************************************************************/
  201. /* WARNING! cin_dwSig must be first: ci_Start relies on it */
  202. typedef struct CommonInfoN { /* This goes in front of the object */
  203. RD(ULONG cin_dwSig;) /* Signature (for parameter validation) */
  204. ULONG cin_cRef; /* Object reference count */
  205. PUNK cin_punkOuter; /* Controlling unknown */
  206. IUnknown cin_unkPrivate; /* Private IUnknown */
  207. } CommonInfoN, CIN, *PCIN;
  208. typedef struct CommonInfoP { /* This is how we pun the object itself */
  209. PREVTBLP *cip_prevtbl; /* Vtbl of object (will be -1'd) */
  210. } CommonInfoP, CIP, *PCIP;
  211. typedef union CommonInfo {
  212. CIN cin[1];
  213. CIP cip[1];
  214. } CommonInfo, CI, *PCI;
  215. #define ci_dwSig cin[-1].cin_dwSig
  216. #define ci_cRef cin[-1].cin_cRef
  217. #define ci_punkOuter cin[-1].cin_punkOuter
  218. #define ci_unkPrivate cin[-1].cin_unkPrivate
  219. #define ci_rgfp cip[0].cip_prevtbl
  220. #define ci_rgvtbl cip[0].cip_prevtbl[-1].rgvtbl
  221. #define ci_cbvtbl cip[0].cip_prevtbl[-1].cbvtbl
  222. #define ci_QIHelper cip[0].cip_prevtbl[-1].QIHelper
  223. #define ci_Finalize cip[0].cip_prevtbl[-1].FinalizeProc
  224. #define ci_riid cip[0].cip_prevtbl[-1].prevtbl.riid
  225. #define ci_lib cip[0].cip_prevtbl[-1].prevtbl.lib
  226. #ifdef MAXDEBUG
  227. #define ci_Start ci_dwSig
  228. #else
  229. #define ci_Start ci_cRef
  230. #endif
  231. #define ci_dwSignature 0x38162378 /* typed by my cat */
  232. /*****************************************************************************
  233. *
  234. * Common_Finalize (from Common_Release)
  235. *
  236. * By default, no finalization is necessary.
  237. *
  238. *****************************************************************************/
  239. void EXTERNAL
  240. Common_Finalize(PV pv)
  241. {
  242. DebugOutPtszV(DbgFlCommon, TEXT("Common_Finalize(%08x)"), pv);
  243. }
  244. /*****************************************************************************
  245. *
  246. * "Private" IUnknown methods
  247. *
  248. * When a COM object is aggregated, it exports *two* IUnknown
  249. * interfaces.
  250. *
  251. * The "private" IUnknown is the one that is returned to the
  252. * controlling unknown. It is this unknown that the controlling
  253. * unknown uses to manipulate the refcount on the inner object.
  254. *
  255. * The "public" IUnknown is the one that all external callers see.
  256. * For this, we just hand out the controlling unknown.
  257. *
  258. *****************************************************************************/
  259. Secondary_Interface(CCommon, IUnknown);
  260. /*****************************************************************************
  261. *
  262. * @doc INTERNAL
  263. *
  264. * @func PV | thisPunk |
  265. *
  266. * Convert a private punk (&cin_unkPrivate) into the beginning of
  267. * the actual object.
  268. *
  269. * @parm PUNK | punkPrivate |
  270. *
  271. * The private punk (&cin_unkPrivate) corresponding to some
  272. * object we are managing.
  273. *
  274. * @returns
  275. *
  276. * The object pointer on success, or 0 on error.
  277. *
  278. * @comm
  279. *
  280. * We do not return an <t HRESULT> on error, because the
  281. * callers of the procedure typically do not return
  282. * <t HRESULT>s themselves.
  283. *
  284. *****************************************************************************/
  285. #ifndef MAXDEBUG
  286. #define thisPunk_(punk, z) \
  287. _thisPunk_(punk) \
  288. #endif
  289. PV INLINE
  290. thisPunk_(PUNK punkPrivate, LPCSTR s_szProc)
  291. {
  292. PV pv = NULL;
  293. if (SUCCEEDED(hresFullValidReadPdw(punkPrivate, 0))) {
  294. if (punkPrivate->lpVtbl == Class_Vtbl(CCommon, IUnknown)) {
  295. pv = pvAddPvCb(punkPrivate,
  296. cbX(CIN) - FIELD_OFFSET(CIN, cin_unkPrivate));
  297. } else {
  298. // WarnPszV("%s: Invalid parameter 0", szProc);
  299. pv = NULL;
  300. }
  301. }
  302. return pv;
  303. }
  304. #define thisPunk(punk) \
  305. thisPunk_(punk, s_szProc) \
  306. /*****************************************************************************
  307. *
  308. * @doc INTERNAL
  309. *
  310. * @func HRESULT | Common_QIHelper |
  311. *
  312. * Called when we can't find any interface in the standard list.
  313. * See if there's a dynamic interface we can use.
  314. *
  315. * Objects are expected to override this method if
  316. * they implement dynamic interfaces.
  317. *
  318. * @parm PV | pv |
  319. *
  320. * The object being queried.
  321. *
  322. * @parm RIID | riid |
  323. *
  324. * The interface being requested.
  325. *
  326. * @parm PPV | ppvObj |
  327. *
  328. * Output pointer.
  329. *
  330. * @returns
  331. *
  332. * Always returns <c E_NOINTERFACE>.
  333. *
  334. *****************************************************************************/
  335. STDMETHODIMP
  336. Common_QIHelper(PV pv, RIID riid, PPV ppvObj)
  337. {
  338. HRESULT hres;
  339. *ppvObj = NULL;
  340. hres = E_NOINTERFACE;
  341. return hres;
  342. }
  343. /*****************************************************************************
  344. *
  345. * @doc INTERNAL
  346. *
  347. * @func HRESULT | Common_PrivateQueryInterface |
  348. *
  349. * Common implementation of <mf IUnknown::QueryInterface> for
  350. * the "private <i IUnknown>".
  351. *
  352. * Note that we AddRef through the public <i IUnknown>
  353. * (<ie>, through the controlling unknown).
  354. * That's part of the rules of aggregation,
  355. * and we have to follow them in order to keep the controlling
  356. * unknown from getting confused.
  357. *
  358. * @parm PUNK | punkPrivate |
  359. *
  360. * The object being queried.
  361. *
  362. * @parm RIID | riid |
  363. *
  364. * The interface being requested.
  365. *
  366. * @parm PPV | ppvObj |
  367. *
  368. * Output pointer.
  369. *
  370. *****************************************************************************/
  371. /*****************************************************************************
  372. *
  373. * The "compiler issue" remark boils down to the fact that the
  374. * compiler fails to recognize this:
  375. *
  376. * for (i = 0; i < n; i++) {
  377. * if (cond) {
  378. * mumble();
  379. * break;
  380. * }
  381. * }
  382. * if (i >= n) {
  383. * gurgle();
  384. * }
  385. *
  386. * and turn it into this:
  387. *
  388. * for (i = 0; i < n; i++) {
  389. * if (cond) {
  390. * mumble();
  391. * goto done;
  392. * }
  393. * }
  394. * gurgle();
  395. * done:;
  396. *
  397. * But even with this help, the compiler emits pretty dumb code.
  398. *
  399. *****************************************************************************/
  400. STDMETHODIMP
  401. Common_PrivateQueryInterface(PUNK punkPrivate, REFIID riid, PPV ppvObj)
  402. {
  403. PCI pci;
  404. HRESULT hres;
  405. EnterProcR(IUnknown::QueryInterface, (_ "pG", punkPrivate, riid));
  406. pci = thisPunk(punkPrivate);
  407. if (pci) {
  408. if (IsEqualIID(riid, &IID_IUnknown)) {
  409. *ppvObj = pci;
  410. OLE_AddRef(pci->ci_punkOuter);
  411. hres = S_OK;
  412. } else {
  413. UINT ivtbl;
  414. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  415. if (IsEqualIID(riid, ((PCI)(&pci->ci_rgvtbl[ivtbl]))->ci_riid)) {
  416. *ppvObj = pvAddPvCb(pci, ivtbl * sizeof(PV));
  417. OLE_AddRef(pci->ci_punkOuter);
  418. hres = S_OK;
  419. goto exit; /* see "compiler issue" comment above */
  420. }
  421. }
  422. hres = pci->ci_QIHelper(pci, riid, ppvObj);
  423. }
  424. } else {
  425. hres = E_INVALIDARG;
  426. }
  427. exit:;
  428. ExitOleProcPpv(ppvObj);
  429. return hres;
  430. }
  431. /*****************************************************************************
  432. *
  433. * @doc INTERNAL
  434. *
  435. * @func ULONG | Common_PrivateAddRef |
  436. *
  437. * Increment the object refcount.
  438. *
  439. * @parm PUNK | punkPrivate |
  440. *
  441. * The object being addref'd.
  442. *
  443. *****************************************************************************/
  444. STDMETHODIMP_(ULONG)
  445. Common_PrivateAddRef(PUNK punkPrivate)
  446. {
  447. PCI pci;
  448. ULONG ulRef;
  449. EnterProcR(IUnknown::AddRef, (_ "p", punkPrivate));
  450. pci = thisPunk(punkPrivate);
  451. if (pci) {
  452. ulRef = ++pci->ci_cRef;
  453. } else {
  454. ulRef = 0;
  455. }
  456. ExitProcX(ulRef);
  457. return ulRef;
  458. }
  459. /*****************************************************************************
  460. *
  461. * @doc INTERNAL
  462. *
  463. * @func ULONG | Common_PrivateRelease |
  464. *
  465. * Decrement the object refcount.
  466. *
  467. * If the object refcount drops to zero, finalize the object
  468. * and free it, then decrement the dll refcount.
  469. *
  470. * To protect against potential re-entrancy during finalization
  471. * (in case finalization does an artificial
  472. * <f AddRef>/<f Release>), we
  473. * do our own artificial <f AddRef>/<f Release> up front.
  474. *
  475. * @parm PUNK | punkPrivate |
  476. *
  477. * The object being release'd.
  478. *
  479. *****************************************************************************/
  480. STDMETHODIMP_(ULONG)
  481. Common_PrivateRelease(PUNK punkPrivate)
  482. {
  483. PCI pci;
  484. ULONG ulRc;
  485. EnterProcR(IUnknown::Release, (_ "p", punkPrivate));
  486. pci = thisPunk(punkPrivate);
  487. if (pci) {
  488. ulRc = --pci->ci_cRef;
  489. if (ulRc == 0) {
  490. ++pci->ci_cRef;
  491. pci->ci_Finalize(pci);
  492. /* Artificial release is pointless: we're being freed */
  493. FreePv(pvSubPvCb(pci, sizeof(CIN)));
  494. DllRelease();
  495. }
  496. } else {
  497. ulRc = 0;
  498. }
  499. ExitProcX(ulRc);
  500. return ulRc;
  501. }
  502. /*****************************************************************************
  503. *
  504. * @doc INTERNAL
  505. *
  506. * @global IUnknownVtbl * | c_lpvtblPunk |
  507. *
  508. * The special IUnknown object that only the controlling unknown
  509. * knows about.
  510. *
  511. * This is the one that calls the "Real" services. All the normal
  512. * vtbl's go through the controlling unknown (which, if we are
  513. * not aggregated, points to ourselves).
  514. *
  515. *****************************************************************************/
  516. #pragma BEGIN_CONST_DATA
  517. _Secondary_Interface_Begin(CCommon, IUnknown,
  518. (ULONG)(FIELD_OFFSET(CIN, cin_unkPrivate) - cbX(CIN)),
  519. Common_Private)
  520. _Secondary_Interface_End(CCommon, IUnknown)
  521. #pragma END_CONST_DATA
  522. /*****************************************************************************
  523. *
  524. * "Public" IUnknown methods
  525. *
  526. * These simply forward through the controlling unknown.
  527. *
  528. *****************************************************************************/
  529. /*****************************************************************************
  530. *
  531. * @doc INTERNAL
  532. *
  533. * @func HRESULT | Common_QueryInterface |
  534. *
  535. * Forward through the controlling unknown.
  536. *
  537. * @parm PUNK | punk |
  538. *
  539. * The object being queried.
  540. *
  541. * @parm RIID | riid |
  542. *
  543. * The interface being requested.
  544. *
  545. * @parm PPV | ppvObj |
  546. *
  547. * Output pointer.
  548. *
  549. *****************************************************************************/
  550. STDMETHODIMP
  551. Common_QueryInterface(PV pv, REFIID riid, PPV ppvObj)
  552. {
  553. HRESULT hres;
  554. EnterProcR(IUnknown::QueryInterface, (_ "pG", pv, riid));
  555. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  556. PCI pci = _thisPv(pv);
  557. AssertF(pci->ci_punkOuter);
  558. hres = OLE_QueryInterface(pci->ci_punkOuter, riid, ppvObj);
  559. }
  560. ExitOleProcPpv(ppvObj);
  561. return hres;
  562. }
  563. /*****************************************************************************
  564. *
  565. * @doc INTERNAL
  566. *
  567. * @func ULONG | Common_AddRef |
  568. *
  569. * Forward through the controlling unknown.
  570. *
  571. * @parm PUNK | punk |
  572. *
  573. * The object being addref'd.
  574. *
  575. *****************************************************************************/
  576. STDMETHODIMP_(ULONG)
  577. Common_AddRef(PV pv)
  578. {
  579. ULONG ulRef;
  580. HRESULT hres;
  581. EnterProcR(IUnknown::AddRef, (_ "p", pv));
  582. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  583. PCI pci = _thisPv(pv);
  584. ulRef = OLE_AddRef(pci->ci_punkOuter);
  585. } else {
  586. ulRef = 0;
  587. }
  588. ExitProcX(ulRef);
  589. return ulRef;
  590. }
  591. /*****************************************************************************
  592. *
  593. * @doc INTERNAL
  594. *
  595. * @func ULONG | Common_Release |
  596. *
  597. * Forward through the controlling unknown.
  598. *
  599. * @parm PUNK | punk |
  600. *
  601. * Object being release'd.
  602. *
  603. *****************************************************************************/
  604. STDMETHODIMP_(ULONG)
  605. Common_Release(PV pv)
  606. {
  607. ULONG ulRc;
  608. HRESULT hres;
  609. EnterProcR(IUnknown::Release, (_ "p", pv));
  610. if (SUCCEEDED(hres = hresFullValidPitf(pv, 0))) {
  611. PCI pci = _thisPv(pv);
  612. ulRc = OLE_Release(pci->ci_punkOuter);
  613. } else {
  614. ulRc = 0;
  615. }
  616. ExitProcX(ulRc);
  617. return ulRc;
  618. }
  619. /*****************************************************************************
  620. *
  621. * @doc INTERNAL
  622. *
  623. * @func HRESULT | __Common_New |
  624. *
  625. * Create a new object with refcount 1 and the specific vtbl.
  626. * All other fields are zero-initialized. All parameters must
  627. * already be validated.
  628. *
  629. * @parm ULONG | cb |
  630. *
  631. * Size of object. This does not include the hidden bookkeeping
  632. * bytes maintained by the object manager.
  633. *
  634. * @parm PUNK | punkOuter |
  635. *
  636. * Controlling unknown for OLE aggregation. May be 0 to indicate
  637. * that the object is not aggregated.
  638. *
  639. * @parm PV | vtbl |
  640. *
  641. * Pointer to primary vtbl for this object. Note that the
  642. * vtbl declaration macros include other magic goo near the vtbl,
  643. * which we consult in order to create the object.
  644. *
  645. * @parm PPV | ppvObj |
  646. *
  647. * Output pointer.
  648. *
  649. *****************************************************************************/
  650. STDMETHODIMP
  651. __Common_New(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj)
  652. {
  653. HRESULT hres;
  654. EnterProc(__Common_New, (_ "uxx", cb, punkOuter, vtbl));
  655. hres = AllocCbPpv(cb + sizeof(CIN), ppvObj);
  656. if (SUCCEEDED(hres)) {
  657. PCI pciO = (PV)&vtbl;
  658. PCI pci = pvAddPvCb(*ppvObj, sizeof(CIN));
  659. RD(pci->ci_dwSig = ci_dwSignature);
  660. pci->ci_unkPrivate.lpVtbl = Class_Vtbl(CCommon, IUnknown);
  661. if (punkOuter) {
  662. pci->ci_punkOuter = punkOuter;
  663. } else {
  664. pci->ci_punkOuter = &pci->ci_unkPrivate;
  665. }
  666. CopyMemory(pci, pciO->ci_rgvtbl, pciO->ci_cbvtbl);
  667. *ppvObj = pci;
  668. pci->ci_cRef++;
  669. DllAddRef();
  670. hres = S_OK;
  671. }
  672. ExitOleProcPpv(ppvObj);
  673. return hres;
  674. }
  675. /*****************************************************************************
  676. *
  677. * @doc INTERNAL
  678. *
  679. * @func HRESULT | _Common_New_ |
  680. *
  681. * Create a new object with refcount 1 and the specific vtbl.
  682. * All other fields are zero-initialized. This entry point
  683. * validates parameters.
  684. *
  685. * @parm ULONG | cb |
  686. *
  687. * Size of object. This does not include the hidden bookkeeping
  688. * bytes maintained by the object manager.
  689. *
  690. * @parm PUNK | punkOuter |
  691. *
  692. * Controlling unknown for OLE aggregation. May be 0 to indicate
  693. * that the object is not aggregated.
  694. *
  695. * @parm PV | vtbl |
  696. *
  697. * Pointer to primary vtbl for this object. Note that the
  698. * vtbl declaration macros include other magic goo near the vtbl,
  699. * which we consult in order to create the object.
  700. *
  701. * @parm PPV | ppvObj |
  702. *
  703. * Output pointer.
  704. *
  705. *****************************************************************************/
  706. STDMETHODIMP
  707. _Common_New_(ULONG cb, PUNK punkOuter, PV vtbl, PPV ppvObj, LPCSTR pszProc)
  708. {
  709. HRESULT hres;
  710. EnterProc(_Common_New, (_ "uxx", cb, punkOuter, vtbl));
  711. if (SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  712. SUCCEEDED(hres = hresFullValidPdwOut_(ppvObj, pszProc, 3))) {
  713. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  714. }
  715. ExitOleProcPpv(ppvObj);
  716. return hres;
  717. }
  718. /*****************************************************************************
  719. *
  720. * @doc INTERNAL
  721. *
  722. * @func HRESULT | _Common_NewRiid_ |
  723. *
  724. * Create a new object with refcount 1 and the specific vtbl,
  725. * but only if the object supports the indicated interface.
  726. * All other fields are zero-initialized.
  727. *
  728. * If punkOut is nonzero, then the object is being created for
  729. * aggregation. The interface must then be &IID_IUnknown.
  730. *
  731. * Aggregation is used to allow multiple IStillImageXXX interfaces
  732. * to hang off one logical object.
  733. *
  734. * It is assumed that the prototype of the calling function is
  735. *
  736. * foo(PV this, PUNK punkOuter, RIID riid, PPV ppvObj);
  737. *
  738. * @parm ULONG | cb |
  739. *
  740. * Size of object. This does not include the hidden bookkeeping
  741. * bytes maintained by the object manager.
  742. *
  743. * @parm PV | vtbl |
  744. *
  745. * Pointer to primary vtbl for this object. Note that the
  746. * vtbl declaration macros include other magic goo near the vtbl,
  747. * which we consult in order to create the object.
  748. *
  749. * @parm PUNK | punkOuter |
  750. *
  751. * Controlling unknown for OLE aggregation. May be 0 to indicate
  752. * that the object is not aggregated.
  753. *
  754. * @parm RIID | riid |
  755. *
  756. * Interface requested.
  757. *
  758. * @parm PPV | ppvObj |
  759. *
  760. * Output pointer.
  761. *
  762. *****************************************************************************/
  763. STDMETHODIMP
  764. _Common_NewRiid_(ULONG cb, PV vtbl, PUNK punkOuter, RIID riid, PPV ppvObj,
  765. LPCSTR pszProc)
  766. {
  767. HRESULT hres;
  768. EnterProc(Common_NewRiid, (_ "upG", cb, punkOuter, riid));
  769. /*
  770. * Note: __Common_New does not validate punkOuter or ppvObj,
  771. * so we have to. Note also that we validate ppvObj first,
  772. * so that it will be set to zero as soon as possible.
  773. */
  774. if (SUCCEEDED(hres = hresFullValidPdwOut_(ppvObj, pszProc, 3)) &&
  775. SUCCEEDED(hres = hresFullValidPitf0_(punkOuter, pszProc, 1)) &&
  776. SUCCEEDED(hres = hresFullValidRiid_(riid, pszProc, 2))) {
  777. if (fLimpFF(punkOuter, IsEqualIID(riid, &IID_IUnknown))) {
  778. hres = __Common_New(cb, punkOuter, vtbl, ppvObj);
  779. if (SUCCEEDED(hres)) {
  780. /*
  781. * Move to the requested interface if we aren't aggregated.
  782. * Don't do this if aggregated! or we will lose the private
  783. * IUnknown and then the caller will be hosed.
  784. */
  785. if (punkOuter) {
  786. PCI pci = *ppvObj;
  787. *ppvObj = &pci->ci_unkPrivate;
  788. } else {
  789. PUNK punk = *ppvObj;
  790. hres = Common_QueryInterface(punk, riid, ppvObj);
  791. Common_Release(punk);
  792. }
  793. }
  794. } else {
  795. RD(RPF("%s: IID must be IID_IUnknown if created for aggregation",
  796. pszProc));
  797. *ppvObj = 0;
  798. hres = CLASS_E_NOAGGREGATION;
  799. }
  800. }
  801. ExitOleProcPpv(ppvObj);
  802. return hres;
  803. }
  804. /*****************************************************************************
  805. *
  806. * Invoke_Release
  807. *
  808. * Release the object (if there is one) and wipe out the back-pointer.
  809. * Note that we wipe out the value before calling the release, in order
  810. * to ameliorate various weird callback conditions.
  811. *
  812. *****************************************************************************/
  813. void EXTERNAL
  814. Invoke_Release(PPV pv)
  815. {
  816. LPUNKNOWN punk = (PV)pvExchangePpvPv((PPV)pv, (PV)0);
  817. if (punk) {
  818. punk->lpVtbl->Release(punk);
  819. }
  820. }
  821. /*****************************************************************************
  822. *
  823. * @doc INTERNAL
  824. *
  825. * @func HRESULT | hresPvVtbl_ |
  826. *
  827. * Validate that an interface pointer is what it claims to be.
  828. * It must be the object associated with the <p vtbl>.
  829. *
  830. * @parm IN PV | pv |
  831. *
  832. * The thing that claims to be an interface pointer.
  833. *
  834. * @parm IN PV | vtbl |
  835. *
  836. * What it should be, or something equivalent to this.
  837. *
  838. * @returns
  839. *
  840. * Returns <c S_OK> if everything is okay, else
  841. * <c E_INVALIDARG>.
  842. *
  843. *****************************************************************************/
  844. HRESULT EXTERNAL
  845. hresPvVtbl_(PV pv, PV vtbl, LPCSTR s_szProc)
  846. {
  847. PUNK punk = pv;
  848. HRESULT hres;
  849. AssertF(vtbl);
  850. if (SUCCEEDED(hres = hresFullValidReadPdw(punk, 0))) {
  851. #ifdef MAXDEBUG
  852. if (punk->lpVtbl == vtbl) {
  853. hres = S_OK;
  854. } else {
  855. RPF("ERROR %s: arg %d: invalid pointer", s_szProc, 0);
  856. hres = E_INVALIDARG;
  857. }
  858. #else
  859. UINT ivtbl;
  860. PV vtblUnk = punk->lpVtbl;
  861. PCI pci = (PV)&vtbl;
  862. if (pci->ci_lib == 0) {
  863. for (ivtbl = 0; ivtbl * sizeof(PV) < pci->ci_cbvtbl; ivtbl++) {
  864. if (pci->ci_rgvtbl[ivtbl] == vtblUnk) {
  865. hres = S_OK;
  866. goto found;
  867. }
  868. }
  869. hres = E_INVALIDARG;
  870. found:;
  871. } else {
  872. if (punk->lpVtbl == vtbl) {
  873. hres = S_OK;
  874. } else {
  875. hres = E_INVALIDARG;
  876. }
  877. }
  878. #endif
  879. }
  880. return hres;
  881. }