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.

1475 lines
36 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File:
  4. // daholder.cpp
  5. //
  6. // Contents:
  7. // concrete implementation of IDataAdviseHolder, a helper
  8. // class for OLE server implementors
  9. //
  10. // Classes:
  11. // CDAHolder
  12. //
  13. // Functions:
  14. // CreateDataAdviseHolder
  15. //
  16. // History:
  17. // 01/20/95 - t-ScottH- added Dump methods to CDAHolder and
  18. // CEnumSTATDATA classes
  19. // added DumpCDAHolder & DumpCEnumSTATDATA APIs
  20. // put class definitions in header file daholder.h
  21. // 03/09/94 - AlexGo - fixed bugs with the enumerator and
  22. // disconnecting of bad advise sinks
  23. // 01/24/94 - AlexGo - first pass at conversion to Cairo-style
  24. // memory allocation
  25. // 01/11/94 - AlexGo - added VDATEHEAP macros to all functions and
  26. // methods
  27. // 12/09/93 - ChrisWe - fix test for error code after CoGetMalloc()
  28. // in CDAHolder::Advise
  29. // 11/22/93 - ChrisWe - replace overloaded ==, != with
  30. // IsEqualIID and IsEqualCLSID
  31. // 10/29/93 - ChrisWe - file inspection and cleanup
  32. //
  33. //-----------------------------------------------------------------------------
  34. #include <le2int.h>
  35. #include "daholder.h"
  36. #ifdef _DEBUG
  37. #include "dbgdump.h"
  38. #endif // _DEBUG
  39. #pragma SEG(daholder)
  40. NAME_SEG(DaHolder)
  41. ASSERTDATA
  42. //+----------------------------------------------------------------------------
  43. //
  44. // Function:
  45. // CreateDataAdviseHolder, public
  46. //
  47. // Synopsis:
  48. // Creates an instance of the CDAHolder class
  49. //
  50. // Arguments:
  51. // [ppDAHolder] -- pointer to where to return the created
  52. // IDataAdviseHolder instance
  53. //
  54. // Returns:
  55. // E_OUTOFMEMORY, S_OK
  56. //
  57. // Notes:
  58. //
  59. // History:
  60. // 10/29/93 - ChrisWe - file inspection and cleanup
  61. //
  62. //-----------------------------------------------------------------------------
  63. #pragma SEG(CreateDataAdviseHolder)
  64. STDAPI CreateDataAdviseHolder(IDataAdviseHolder FAR* FAR* ppDAHolder)
  65. {
  66. OLETRACEIN((API_CreateDataAdviseHolder, PARAMFMT("ppDAHolder= %p"), ppDAHolder));
  67. VDATEHEAP();
  68. VDATEPTROUT(ppDAHolder, IDataAdviseHolder*);
  69. *ppDAHolder = new FAR CDAHolder(); // task memory; use MEMCTX_TASK below
  70. CALLHOOKOBJECTCREATE(*ppDAHolder ? NOERROR : E_OUTOFMEMORY,
  71. CLSID_NULL,
  72. IID_IDataAdviseHolder,
  73. (IUnknown **)ppDAHolder);
  74. HRESULT hr;
  75. hr = *ppDAHolder ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
  76. OLETRACEOUT((API_CreateDataAdviseHolder, hr));
  77. return hr;
  78. }
  79. //+----------------------------------------------------------------------------
  80. //
  81. // Member:
  82. // CDAHolder::CDAHolder, public
  83. //
  84. // Synopsis:
  85. // constructor
  86. //
  87. // Effects:
  88. // returns with reference count set to 1
  89. //
  90. // Arguments:
  91. // none
  92. //
  93. // Notes:
  94. //
  95. // History:
  96. // 10/29/93 - ChrisWe - file inspection and cleanup
  97. //
  98. //-----------------------------------------------------------------------------
  99. #pragma SEG(CDAHolder_ctor)
  100. CDAHolder::CDAHolder() : CSafeRefCount(NULL)
  101. {
  102. VDATEHEAP();
  103. // set reference count
  104. SafeAddRef();
  105. // connections run from [1..infinity)
  106. m_dwConnection = 1;
  107. // there are no STATDATA entries yet
  108. m_iSize = 0;
  109. m_pSD = NULL;
  110. GET_A5();
  111. }
  112. //+----------------------------------------------------------------------------
  113. //
  114. // Member:
  115. // CDAHolder::~CDAHolder, private
  116. //
  117. // Synopsis:
  118. // destructor
  119. //
  120. // Effects:
  121. // frees resources associated with the CDAHolder
  122. //
  123. // Notes:
  124. //
  125. // History:
  126. // 10/29/93 - ChrisWe - file inspection and cleanup
  127. //
  128. //-----------------------------------------------------------------------------
  129. CDAHolder::~CDAHolder()
  130. {
  131. VDATEHEAP();
  132. int iData; // counts array entries as we scan the array
  133. STATDATA FAR *pSD; // used to scan the array of STATDATA
  134. // release the array, if we've allocated it
  135. // REVIEW: If we want to be really safe, we should release
  136. // the stat data's either before or after our destructor.
  137. // The release of the advise sinks in the statdata elements
  138. // could possible result in us being re-entered (a potential
  139. // awkward state for the middle of a class destructor).
  140. // However, since nobody should be accesssing the advise
  141. // holder if we get to the destructor (since the reference
  142. // count would have to be zero), we are going to bag on
  143. // this modification for Daytona RC1.
  144. if (m_pSD)
  145. {
  146. for(pSD = m_pSD, iData = 0; iData < m_iSize; ++pSD, ++iData)
  147. UtReleaseStatData(pSD);
  148. PubMemFree(m_pSD);
  149. }
  150. }
  151. //+----------------------------------------------------------------------------
  152. //
  153. // Member:
  154. // CDAHolder::QueryInterface, public
  155. //
  156. // Synopsis:
  157. // implements IUnknown::QueryInterface
  158. //
  159. // Arguments:
  160. // [iid] -- IID of the desired interface
  161. // [ppv] -- pointer to a location to return the interface at
  162. //
  163. // Returns:
  164. // E_NOINTERFACE, S_OK
  165. //
  166. // Notes:
  167. //
  168. // History:
  169. // 10/29/93 - ChrisWe - file inspection and cleanup
  170. //
  171. //-----------------------------------------------------------------------------
  172. #pragma SEG(CDAHolder_QueryInterface)
  173. STDMETHODIMP CDAHolder::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  174. {
  175. VDATEHEAP();
  176. M_PROLOG(this);
  177. if (IsEqualIID(iid, IID_IUnknown) ||
  178. IsEqualIID(iid, IID_IDataAdviseHolder))
  179. {
  180. *ppv = (IDataAdviseHolder FAR *)this;
  181. AddRef();
  182. return NOERROR;
  183. }
  184. *ppv = NULL;
  185. return ReportResult(0, E_NOINTERFACE, 0, 0);
  186. }
  187. //+----------------------------------------------------------------------------
  188. //
  189. // Member:
  190. // CDAHolder::AddRef, public
  191. //
  192. // Synopsis:
  193. // implements IUnknown::AddRef
  194. //
  195. // Arguments:
  196. // none
  197. //
  198. // Notes:
  199. //
  200. // History:
  201. // 10/29/93 - ChrisWe - file inspection and cleanup
  202. //
  203. //-----------------------------------------------------------------------------
  204. #pragma SEG(CDAHolder_AddRef)
  205. STDMETHODIMP_(ULONG) CDAHolder::AddRef()
  206. {
  207. VDATEHEAP();
  208. M_PROLOG(this);
  209. return SafeAddRef();
  210. }
  211. //+----------------------------------------------------------------------------
  212. //
  213. // Member:
  214. // CDAHolder::Release, public
  215. //
  216. // Synopsis:
  217. // implementa IUnknown::Release
  218. //
  219. // Arguments:
  220. // none
  221. //
  222. // Notes:
  223. //
  224. // History:
  225. // 10/29/93 - ChrisWe - file inspection and cleanup
  226. //
  227. //-----------------------------------------------------------------------------
  228. #pragma SEG(CDAHolder_Release)
  229. STDMETHODIMP_(ULONG) CDAHolder::Release()
  230. {
  231. VDATEHEAP();
  232. M_PROLOG(this);
  233. return SafeRelease();
  234. }
  235. //+----------------------------------------------------------------------------
  236. //
  237. // Member:
  238. // CDAHolder::Advise, public
  239. //
  240. // Synopsis:
  241. // Add a new advise sink to the list of advise sinks
  242. // managed by the data advise holder, and which will be notified
  243. // if a change is indicated using other IDataAdviseHolder
  244. // methods. A data format is specified, and new data will be
  245. // sent to the sink in that format, when a change occurs.
  246. //
  247. // Arguments:
  248. // [pDataObject] -- the source data object that presentations
  249. // should be taken from if an advise is to occur
  250. // immediately
  251. // [pFetc] -- The data format the advise sink is interested in
  252. // [advf] -- control flags
  253. // [pAdvSink] -- the advise sink being registered
  254. // [pdwConnection] -- a token that can be used to identify the
  255. // advise sink later on
  256. //
  257. // Returns:
  258. // E_OUTOFMEMORY, S_OK
  259. //
  260. // Notes:
  261. //
  262. // History:
  263. // 10/29/93 - ChrisWe - file inspection and cleanup
  264. // 08/02/94 - AlexGo - stabilized
  265. //
  266. //-----------------------------------------------------------------------------
  267. #pragma SEG(CDAHolder_Advise)
  268. STDMETHODIMP CDAHolder::Advise(LPDATAOBJECT pDataObj, FORMATETC FAR* pFetc,
  269. DWORD advf, IAdviseSink FAR* pAdvSink,
  270. DWORD FAR* pdwConnection)
  271. {
  272. VDATEHEAP();
  273. M_PROLOG(this);
  274. int iSDScan; // index of the scan of SD array entries
  275. int iSDFree; // index of first free SD entry, or (-1)
  276. STATDATA FAR *pSD; // scans across the array of STATDATA entries
  277. if( IsZombie() )
  278. {
  279. return ResultFromScode(CO_E_RELEASED);
  280. }
  281. CStabilize stabilize((CSafeRefCount *)this);
  282. if (pDataObj)
  283. VDATEIFACE(pDataObj);
  284. VDATEPTRIN(pFetc, FORMATETC);
  285. VDATEIFACE(pAdvSink);
  286. if (!HasValidLINDEX(pFetc))
  287. {
  288. return(DV_E_LINDEX);
  289. }
  290. // Validate where to return the connection.
  291. if (pdwConnection)
  292. {
  293. VDATEPTRIN(pdwConnection, DWORD);
  294. // Default to error case
  295. *pdwConnection = 0;
  296. }
  297. // scan and remove all unconnected advise sinks
  298. for(iSDFree = (-1), pSD = m_pSD, iSDScan = 0; iSDScan < m_iSize;
  299. ++pSD, ++iSDScan)
  300. {
  301. // REVIEW, why do we have to go polling these?
  302. if (!pSD->pAdvSink || !IsValidInterface(pSD->pAdvSink))
  303. {
  304. // not valid, don't try to release
  305. pSD->pAdvSink = NULL;
  306. goto RemoveBadSD;
  307. }
  308. else if (!CoIsHandlerConnected(pSD->pAdvSink))
  309. {
  310. // sink no longer connected, release
  311. RemoveBadSD:
  312. // release any data. UtReleaseStatData will
  313. // zero out the statdata structure.
  314. UtReleaseStatData(pSD);
  315. }
  316. // if we're still looking for a free entry, note if this one
  317. // is free
  318. if ((iSDFree == (-1)) && (pSD->dwConnection == 0))
  319. iSDFree = iSDScan;
  320. }
  321. // should we send the data immediately?
  322. if (advf & ADVF_PRIMEFIRST)
  323. {
  324. // We are not going to honor ADVF_PRIMEFIRST if pDataObj is
  325. // NULL, even when ADVF_NODATA is specfied. We want it to be
  326. // this way so that the apps which don't have any data at
  327. // startup time, could pass in NULL for pDataObject and
  328. // prevent us from sending any OnDataChange() notification.
  329. // Later when they have the data avaliable they can call
  330. // SendOnDataChange. (SRINIK)
  331. if (pDataObj)
  332. {
  333. STGMEDIUM stgmed;
  334. stgmed.tymed = TYMED_NULL;
  335. stgmed.pUnkForRelease = NULL;
  336. if (advf & ADVF_NODATA)
  337. {
  338. // don't sent data, send only the notification
  339. pAdvSink->OnDataChange(pFetc, &stgmed);
  340. }
  341. else
  342. {
  343. // get data from object and send it to sink
  344. if (pDataObj->GetData(pFetc,
  345. &stgmed) == NOERROR)
  346. {
  347. pAdvSink->OnDataChange(pFetc, &stgmed);
  348. ReleaseStgMedium(&stgmed);
  349. }
  350. }
  351. // if we only have to advise once, we've done so, and
  352. // needn't make an entry in the advise array
  353. if (advf & ADVF_ONLYONCE)
  354. return NOERROR;
  355. }
  356. }
  357. // remove the ADVF_PRIMEFIRST from flags.
  358. advf &= (~ADVF_PRIMEFIRST);
  359. // find a free list entry we can use, if we haven't got one
  360. if (iSDFree == (-1))
  361. {
  362. HRESULT hr;
  363. // REVIEW, can we share array reallocation code with
  364. // oaholder.cpp? Why can't we just use realloc?
  365. // didn't find any free array entries above; since that
  366. // scanned the whole array, have to allocate new entries
  367. // here
  368. pSD = (STATDATA FAR *)PubMemAlloc(sizeof(STATDATA)*(m_iSize+
  369. CDAHOLDER_GROWBY));
  370. if (pSD == NULL)
  371. hr = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  372. else
  373. {
  374. // copy the old data over, if any, and free it
  375. if (m_pSD)
  376. {
  377. _xmemcpy((void FAR *)pSD, (void FAR *)m_pSD,
  378. sizeof(STATDATA)*m_iSize);
  379. PubMemFree(m_pSD);
  380. }
  381. // initialize newly allocated memory
  382. _xmemset((void FAR *)(pSD+m_iSize), 0,
  383. sizeof(STATDATA)*CDAHOLDER_GROWBY);
  384. // this is the index of the first free element
  385. iSDFree = m_iSize;
  386. // set up the STATDATA array
  387. m_pSD = pSD;
  388. m_iSize += CDAHOLDER_GROWBY;
  389. hr = NOERROR;
  390. }
  391. if (hr != NOERROR)
  392. {
  393. return(hr);
  394. }
  395. }
  396. // if we got here, we can add the new entry, and its index is iSDFree
  397. // point at the new element
  398. pSD = m_pSD+iSDFree;
  399. // Let the advise get added to the list
  400. UtCopyFormatEtc(pFetc, &pSD->formatetc);
  401. pSD->advf = advf;
  402. pAdvSink->AddRef();
  403. pSD->pAdvSink = pAdvSink;
  404. pSD->dwConnection = m_dwConnection++;
  405. // return connection if user requested it
  406. if (pdwConnection)
  407. *pdwConnection = pSD->dwConnection;
  408. return NOERROR;
  409. }
  410. //+----------------------------------------------------------------------------
  411. //
  412. // Member:
  413. // CDAHolder::Unadvise, public
  414. //
  415. // Synopsis:
  416. // removes the advise sink specified from the list of those
  417. // registered to receive notifications from this data advise
  418. // holder
  419. //
  420. // Arguments:
  421. // [dwConnection] -- token that identifies which advise sink
  422. // to remove; this will have come from Advise().
  423. //
  424. // Returns:
  425. // OLE_E_NOCONNECTION, S_OK
  426. //
  427. // Notes:
  428. //
  429. // History:
  430. // 10/29/93 - ChrisWe - file inspection and cleanup
  431. //
  432. //-----------------------------------------------------------------------------
  433. #pragma SEG(CDAHolder_Unadvise)
  434. STDMETHODIMP CDAHolder::Unadvise(DWORD dwConnection)
  435. {
  436. VDATEHEAP();
  437. M_PROLOG(this);
  438. int iData; // index into the STATDATA array
  439. STATDATA FAR *pSD; // pointer into the STATDATA array
  440. // protect this against being released via a circular reference
  441. CStabilize stabilize((CSafeRefCount *)this);
  442. for (pSD = m_pSD, iData = 0; iData < m_iSize; ++pSD, ++iData)
  443. {
  444. // is this the entry we're looking for?
  445. if (pSD->dwConnection == dwConnection)
  446. {
  447. // release resources for the entry. UtReleaseStatData
  448. // will zero the statdata.
  449. UtReleaseStatData(pSD);
  450. return NOERROR;
  451. }
  452. }
  453. // if we found what we were looking for in the loop, we'd return
  454. // from there, and never get here. Since we didn't, it must be
  455. // that there's no such connection
  456. return ReportResult(0, OLE_E_NOCONNECTION, 0, 0);
  457. }
  458. //+----------------------------------------------------------------------------
  459. //
  460. // Member:
  461. // CDAHolder::SendOnDataChange, public
  462. //
  463. // Synopsis:
  464. // Send an OnDataChange notification to all advise sinks
  465. // registered with this data advise holder.
  466. //
  467. // Arguments:
  468. // [pDataObject] -- the data object to get data from to send
  469. // to the advise sinks
  470. // [dwReserved] --
  471. // [advf] -- control flags
  472. //
  473. // Returns:
  474. // S_OK
  475. //
  476. // Notes:
  477. // More than one advise sink may be interested in obtaining
  478. // data in the same format. It may be expensive for the data
  479. // object to create copies of the data in requested formats.
  480. // Therefore, when a change is signalled, the data formats
  481. // are cached. As each advise sink is to be notified, we
  482. // check to see if the format it is requesting has already been
  483. // gotten from the data object (with GetData().) If it has,
  484. // then we simply send that copy again. If not, we get the
  485. // new format, and add that to the cache.
  486. //
  487. // History:
  488. // 10/29/93 - ChrisWe - file inspection and cleanup
  489. //
  490. //-----------------------------------------------------------------------------
  491. #pragma SEG(CDAHolder_SendOnDataChange)
  492. STDMETHODIMP CDAHolder::SendOnDataChange(IDataObject FAR* pDataObject,
  493. DWORD dwReserved, DWORD advf)
  494. {
  495. VDATEHEAP();
  496. A5_PROLOG(this);
  497. HRESULT hresult = NOERROR; // error status so far
  498. UINT cFetcTotal; // maximum number of formats we will cache
  499. UINT cFetcGotten; // the actual number of formats in the cache
  500. UINT cFetc; // the index of the format in the cache under consideration
  501. FORMATETC FAR* rgFetc; // a record of the cached presentations
  502. STGMEDIUM FAR* rgStgmed; // the cached data presentations
  503. UINT cStatData; // a counter for the STATDATA array elements
  504. STATDATA FAR *pSD; // a pointer into the array of STATDATA elements
  505. VDATEIFACE(pDataObject);
  506. // in the worst case, every advise sink has requested a unique
  507. // data format, and we won't get any duplicates. This means that
  508. // we will wind up caching all of them.
  509. cFetcTotal = m_iSize;
  510. // if there are no entries, there's nothing to do
  511. if (cFetcTotal == 0)
  512. return NOERROR;
  513. // some advise sinks may use these notifications to change their
  514. // requested notifications; due to possible circular references,
  515. // this could to lead to a release of this holder. Protect against
  516. // this here; this is released after most work is done, towards the
  517. // end of this function
  518. CStabilize stabilize((CSafeRefCount *)this);
  519. // alloc rgFetc and rgStgmed to accomodate all the cache entries
  520. // if either fails to be allocated, we quit
  521. rgFetc = (FORMATETC FAR *)PubMemAlloc(cFetcTotal * sizeof(FORMATETC));
  522. rgStgmed = (STGMEDIUM FAR *)PubMemAlloc(cFetcTotal * sizeof(STGMEDIUM));
  523. if (rgFetc == NULL || rgStgmed == NULL)
  524. {
  525. hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  526. goto FreeExit;
  527. }
  528. // zero out STDMEDIUM entries
  529. _xmemset((void FAR *)rgStgmed, 0, sizeof(STGMEDIUM)*cFetcTotal);
  530. // ensure we have the right data and send to each advise sink
  531. // note the loop is bounded by cFetcTotal, preventing additional
  532. // sinks from being notified, if they are registered during these
  533. // notifications. cStatData is not used in the loop body, so it
  534. // counts down
  535. for (cFetcGotten = 0, pSD = m_pSD, cStatData = cFetcTotal;
  536. cStatData; ++pSD, --cStatData)
  537. {
  538. // if this slot is not in use, skip it
  539. if (!pSD->dwConnection)
  540. continue;
  541. // if the sink is not interested in presentation data,
  542. // proceed to notify it immediately, unless this notification
  543. // is announcing the termination of the source
  544. if ((pSD->advf & ADVF_NODATA) &&
  545. !(advf & ADVF_DATAONSTOP))
  546. {
  547. STGMEDIUM stgmed;
  548. // don't sent data; use format from collection
  549. // and null STGMEDIUM.
  550. // REVIEW, should this be done once, up above?
  551. stgmed.tymed = TYMED_NULL;
  552. stgmed.pUnkForRelease = NULL;
  553. pSD->pAdvSink->OnDataChange(&pSD->formatetc, &stgmed);
  554. // REVIEW, what does this do for NULL?
  555. // if nothing, we can share a stdmedNULL, as above
  556. ReleaseStgMedium(&stgmed);
  557. // clean up at end of loop
  558. goto DataSent;
  559. }
  560. // if the sink is interested in data at the time of
  561. // termination, and the source is not terminating, OR, the
  562. // sink is not interested in data at the time of termination,
  563. // and we are terminating, skip this sink, and proceed
  564. if ((pSD->advf & ADVF_DATAONSTOP) !=
  565. (advf & ADVF_DATAONSTOP))
  566. continue;
  567. // check the requested format against the list of formats
  568. // for which we've already retrieved the presentation data.
  569. // if there is a match, proceed to send that data immediately
  570. // from here on in this loop body, cFetc is the index of the
  571. // data presentation to send to the current sink
  572. // REVIEW PERF: this is an n-squared algorithm;
  573. // we check the array of cached presentations for each
  574. // advise sink
  575. for (cFetc = 0; cFetc < cFetcGotten; ++cFetc)
  576. {
  577. // if match, continue outer loop
  578. if (UtCompareFormatEtc(&rgFetc[cFetc],
  579. &pSD->formatetc) == UTCMPFETC_EQ)
  580. goto SendThisOne;
  581. }
  582. // if we get here, we have not already fetched presentation
  583. // data that matches the requested format
  584. // init FORMATETC (copy of needed one)
  585. // STDMEDIUM was initialized after its allocation to all NULL
  586. rgFetc[cFetcGotten] = pSD->formatetc;
  587. // get the data in the requested format from the data object
  588. // REVIEW: assume STGMEDIUM untouched if error
  589. // (i.e., still null)
  590. hresult = pDataObject->GetData(&rgFetc[cFetcGotten],
  591. &rgStgmed[cFetcGotten]);
  592. // REVIEW, what is this checking?
  593. AssertOutStgmedium(hresult, &rgStgmed[cFetcGotten]);
  594. // the presentation to send is the newly cached one
  595. // there is now one more entry in the cache array
  596. cFetc = cFetcGotten++;
  597. SendThisOne:
  598. // when we get here, rgFetc[cFetc] is the format to send to the
  599. // current advise sink
  600. // send change notification with requested data
  601. // The advise sink could have disappeared in the meantime
  602. // (if the the GetData call above resulted in an Unadvise,
  603. // for example), so we must validate the pAdvSInk first.
  604. // pSD will remain a valid regardless, and the advise
  605. // flags will have been zero'd, so it is safe to proceed
  606. // through the loop without "continue"ing.
  607. if (pSD->pAdvSink)
  608. {
  609. pSD->pAdvSink->OnDataChange(&rgFetc[cFetc],
  610. &rgStgmed[cFetc]);
  611. }
  612. DataSent:
  613. // When we get here, something has been sent, possibly
  614. // an empty storage medium
  615. // if the sink requested to only be notified once, we
  616. // can free it here
  617. if (pSD->advf & ADVF_ONLYONCE)
  618. {
  619. // free the stat data. UtReleaseStatData will
  620. // zero the statdata, thus marking the connection
  621. // as invalid.
  622. UtReleaseStatData(pSD);
  623. }
  624. }
  625. // free all stgmeds retrieved; FORMATETC.ptd was not allocated
  626. for (cFetc = 0; cFetc < cFetcGotten; ++cFetc)
  627. ReleaseStgMedium(&rgStgmed[cFetc]);
  628. hresult = NOERROR;
  629. FreeExit:
  630. if (rgFetc != NULL)
  631. PubMemFree(rgFetc);
  632. if (rgStgmed != NULL)
  633. PubMemFree(rgStgmed);
  634. RESTORE_A5();
  635. return hresult;
  636. }
  637. //+-------------------------------------------------------------------------
  638. //
  639. // Member: CDAHolder::Dump, public (_DEBUG only)
  640. //
  641. // Synopsis: return a string containing the contents of the data members
  642. //
  643. // Effects:
  644. //
  645. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  646. // [ulFlag] - flag determining prefix of all newlines of the
  647. // out character array (default is 0 - no prefix)
  648. // [nIndentLevel] - will add a indent prefix after the other prefix
  649. // for ALL newlines (including those with no prefix)
  650. //
  651. // Requires:
  652. //
  653. // Returns: HRESULT
  654. //
  655. // Signals:
  656. //
  657. // Modifies: [ppsz] - argument
  658. //
  659. // Derivation:
  660. //
  661. // Algorithm: use dbgstream to create a string containing information on the
  662. // content of data structures
  663. //
  664. // History: dd-mmm-yy Author Comment
  665. // 20-Jan-95 t-ScottH author
  666. //
  667. // Notes:
  668. //
  669. //--------------------------------------------------------------------------
  670. #ifdef _DEBUG
  671. HRESULT CDAHolder::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  672. {
  673. int i;
  674. char *pszPrefix;
  675. char *pszCSafeRefCount;
  676. char *pszSTATDATA;
  677. dbgstream dstrPrefix;
  678. dbgstream dstrDump(1000);
  679. // determine prefix of newlines
  680. if ( ulFlag & DEB_VERBOSE )
  681. {
  682. dstrPrefix << this << " _VB ";
  683. }
  684. // determine indentation prefix for all newlines
  685. for (i = 0; i < nIndentLevel; i++)
  686. {
  687. dstrPrefix << DUMPTAB;
  688. }
  689. pszPrefix = dstrPrefix.str();
  690. // put data members in stream
  691. dstrDump << pszPrefix << "Next Connection ID = " << m_dwConnection << endl;
  692. dstrDump << pszPrefix << "No. of STATDATA elements = " << m_iSize << endl;
  693. for (i = 0; i < m_iSize; i++)
  694. {
  695. pszSTATDATA = DumpSTATDATA( &m_pSD[i], ulFlag, nIndentLevel + 1) ;
  696. dstrDump << pszPrefix << "STATDATA element: " << i << endl;
  697. dstrDump << pszSTATDATA;
  698. CoTaskMemFree(pszSTATDATA);
  699. }
  700. // clean up and provide pointer to character array
  701. *ppszDump = dstrDump.str();
  702. if (*ppszDump == NULL)
  703. {
  704. *ppszDump = UtDupStringA(szDumpErrorMessage);
  705. }
  706. CoTaskMemFree(pszPrefix);
  707. return NOERROR;
  708. }
  709. #endif //_DEBUG
  710. //+-------------------------------------------------------------------------
  711. //
  712. // Function: DumpCDAHolder, public (_DEBUG only)
  713. //
  714. // Synopsis: calls the CDAHolder::Dump method, takes care of errors and
  715. // returns the zero terminated string
  716. //
  717. // Effects:
  718. //
  719. // Arguments: [pIDAH] - pointer to IDAHolder (which we cast to CDAHolder)
  720. // [ulFlag] - flag determining prefix of all newlines of the
  721. // out character array (default is 0 - no prefix)
  722. // [nIndentLevel] - will add a indent prefix after the other prefix
  723. // for ALL newlines (including those with no prefix)
  724. //
  725. // Requires:
  726. //
  727. // Returns: character array of structure dump or error (null terminated)
  728. //
  729. // Signals:
  730. //
  731. // Modifies:
  732. //
  733. // Algorithm:
  734. //
  735. // History: dd-mmm-yy Author Comment
  736. // 20-Jan-95 t-ScottH author
  737. //
  738. // Notes:
  739. //
  740. // This API !!REQUIRES!! that class CDAHolder inherits from IDataAdviseHolder
  741. // first in order that we can pass in a parameter as a pointer to an
  742. // IDataAdviseHolder and then cast it to a CDAHolder.
  743. //
  744. //--------------------------------------------------------------------------
  745. #ifdef _DEBUG
  746. char *DumpCDAHolder(IDataAdviseHolder *pIDAH, ULONG ulFlag, int nIndentLevel)
  747. {
  748. HRESULT hresult;
  749. char *pszDump;
  750. if (pIDAH == NULL)
  751. {
  752. return UtDupStringA(szDumpBadPtr);
  753. }
  754. CDAHolder *pCDAH = (CDAHolder *)pIDAH;
  755. hresult = pCDAH->Dump(&pszDump, ulFlag, nIndentLevel);
  756. if (hresult != NOERROR)
  757. {
  758. CoTaskMemFree(pszDump);
  759. return DumpHRESULT(hresult);
  760. }
  761. return pszDump;
  762. }
  763. #endif // _DEBUG
  764. //+----------------------------------------------------------------------------
  765. //
  766. // Member:
  767. // CEnumSTATDATA::CEnumSTATDATA, public
  768. //
  769. // Synopsis:
  770. // constructor
  771. //
  772. // Effects:
  773. // sets reference count to 1
  774. //
  775. // Arguments:
  776. // none
  777. //
  778. // Notes:
  779. //
  780. // History:
  781. // 10/29/93 - ChrisWe - file inspection and cleanup
  782. //
  783. //-----------------------------------------------------------------------------
  784. #pragma SEG(CEnumSTATDATA_ctor)
  785. CEnumSTATDATA::CEnumSTATDATA(CDAHolder FAR* pHolder, int iDataStart)
  786. {
  787. VDATEHEAP();
  788. GET_A5();
  789. // set reference count
  790. m_refs = 1;
  791. // first element to examine for return
  792. m_iDataEnum = iDataStart;
  793. // initialize pointer to holder, and addref, so it doesn't go
  794. // away while enumerator is alive
  795. (m_pHolder = pHolder)->AddRef();
  796. }
  797. //+----------------------------------------------------------------------------
  798. //
  799. // Member:
  800. // CDAHolder::~CDAHolder, private
  801. //
  802. // Synopsis:
  803. // destructor
  804. //
  805. // Notes:
  806. //
  807. // History:
  808. // 10/29/93 - ChrisWe - file inspection and cleanup
  809. //
  810. //-----------------------------------------------------------------------------
  811. #pragma SEG(CEnumSTATDATA_dtor)
  812. CEnumSTATDATA::~CEnumSTATDATA()
  813. {
  814. VDATEHEAP();
  815. M_PROLOG(this);
  816. m_pHolder->Release();
  817. }
  818. //+----------------------------------------------------------------------------
  819. //
  820. // Member:
  821. // CEnumSTATDATA::QueryInterface, public
  822. //
  823. // Synopsis:
  824. // implements IUnknown::QueryInterface
  825. //
  826. // Arguments:
  827. // [iid] -- IID of the desired interface
  828. // [ppv] -- pointer to a location to return the interface at
  829. //
  830. // Returns:
  831. // E_NOINTERFACE, S_OK
  832. //
  833. // Notes:
  834. //
  835. // History:
  836. // 10/29/93 - ChrisWe - file inspection and cleanup
  837. //
  838. //-----------------------------------------------------------------------------
  839. #pragma SEG(CEnumSTATDATA_QueryInterface)
  840. STDMETHODIMP CEnumSTATDATA::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  841. {
  842. VDATEHEAP();
  843. M_PROLOG(this);
  844. if (IsEqualIID(iid, IID_IUnknown) ||
  845. IsEqualIID(iid, IID_IEnumSTATDATA))
  846. {
  847. *ppv = (IEnumSTATDATA FAR *)this;
  848. AddRef();
  849. return NOERROR;
  850. }
  851. *ppv = NULL;
  852. return ReportResult(0, E_NOINTERFACE, 0, 0);
  853. }
  854. //+----------------------------------------------------------------------------
  855. //
  856. // Member:
  857. // CEnumSTATDATA::AddRef, public
  858. //
  859. // Synopsis:
  860. // implements IUnknown::AddRef
  861. //
  862. // Arguments:
  863. // none
  864. //
  865. // Notes:
  866. //
  867. // History:
  868. // 10/29/93 - ChrisWe - file inspection and cleanup
  869. //
  870. //-----------------------------------------------------------------------------
  871. #pragma SEG(CEnumSTATDATA_AddRef)
  872. STDMETHODIMP_(ULONG) CEnumSTATDATA::AddRef()
  873. {
  874. VDATEHEAP();
  875. M_PROLOG(this);
  876. return ++m_refs;
  877. }
  878. //+----------------------------------------------------------------------------
  879. //
  880. // Member:
  881. // CEnumSTATDATA::Release, public
  882. //
  883. // Synopsis:
  884. // implementa IUnknown::Release
  885. //
  886. // Arguments:
  887. // none
  888. //
  889. // Notes:
  890. //
  891. // History:
  892. // 10/29/93 - ChrisWe - file inspection and cleanup
  893. //
  894. //-----------------------------------------------------------------------------
  895. #pragma SEG(CEnumSTATDATA_Release)
  896. STDMETHODIMP_(ULONG) CEnumSTATDATA::Release()
  897. {
  898. VDATEHEAP();
  899. M_PROLOG(this);
  900. if (--m_refs == 0)
  901. {
  902. delete this;
  903. return 0;
  904. }
  905. return m_refs;
  906. }
  907. //+----------------------------------------------------------------------------
  908. //
  909. // Member:
  910. // CEnumSTATDATA::Next, public
  911. //
  912. // Synopsis:
  913. // implements IEnumSTATDATA::Next()
  914. //
  915. // Effects:
  916. //
  917. // Arguments:
  918. // [celt] -- number of elements requested on this call
  919. // [rgelt] -- pointer to an array of STATDATAs where copies of
  920. // the elements can be returned
  921. // [pceltFectched] -- a pointer to where to return the number of
  922. // elements actually fetched. May be NULL
  923. //
  924. // Returns:
  925. // S_FALSE, S_OK
  926. //
  927. // Notes:
  928. //
  929. // History:
  930. // 03/09/94 - AlexGo - the enumerator no longer enumerates
  931. // "empty" statdata's in the m_pSD array.
  932. // 11/01/93 - ChrisWe - file inspection and cleanup
  933. //
  934. //-----------------------------------------------------------------------------
  935. #pragma SEG(CEnumSTATDATA_Next)
  936. STDMETHODIMP CEnumSTATDATA::Next(ULONG celt, STATDATA FAR *rgelt,
  937. ULONG FAR* pceltFetched)
  938. {
  939. VDATEHEAP();
  940. M_PROLOG(this);
  941. UINT ielt; // count of the number of elements fetched so far
  942. for (ielt = 0; (ielt < celt) && (m_iDataEnum < m_pHolder->m_iSize);
  943. m_iDataEnum++)
  944. {
  945. if( m_pHolder->m_pSD[m_iDataEnum].dwConnection != 0)
  946. {
  947. ielt++;
  948. // copy all bits; AddRef and copy DVTARGETDEVICE
  949. // separately
  950. UtCopyStatData(&m_pHolder->m_pSD[m_iDataEnum],
  951. rgelt++);
  952. }
  953. }
  954. // return number of elements fetched, if required
  955. if (pceltFetched)
  956. *pceltFetched = ielt;
  957. // no error, if exactly the requested number of elements was fetched
  958. return ielt == celt ? NOERROR : ReportResult(0, S_FALSE, 0, 0);
  959. }
  960. //+----------------------------------------------------------------------------
  961. //
  962. // Member:
  963. // CDAHolder::Skip, public
  964. //
  965. // Synopsis:
  966. // implements IEnumSTATDATA::Skip
  967. //
  968. // Arguments:
  969. // [celt] -- the number of elements in the collection to skip
  970. // over
  971. //
  972. // Returns:
  973. // S_FALSE, S_OK
  974. //
  975. // Notes:
  976. //
  977. // History:
  978. // 11/01/93 - ChrisWe - file inspection and cleanup
  979. //
  980. //-----------------------------------------------------------------------------
  981. #pragma SEG(CEnumSTATDATA_Skip)
  982. STDMETHODIMP CEnumSTATDATA::Skip(ULONG celt)
  983. {
  984. VDATEHEAP();
  985. M_PROLOG(this);
  986. STATDATA FAR *pSD; // scans over the array of STATDATA entries
  987. // if the enumeration would take us off the end of the array
  988. // mark the enumeration as complete
  989. if (m_iDataEnum + celt > (ULONG)m_pHolder->m_iSize)
  990. {
  991. m_iDataEnum = m_pHolder->m_iSize;
  992. return ReportResult(0, S_FALSE, 0, 0);
  993. }
  994. // skip over valid entries in the array, counting down until
  995. // we don't have to skip over any more, or until we get to
  996. // the end of the array
  997. for(pSD = m_pHolder->m_pSD+m_iDataEnum;
  998. celt && (m_iDataEnum < m_pHolder->m_iSize);
  999. ++m_iDataEnum)
  1000. {
  1001. // if the connection is valid, count it as a skipped
  1002. // enumerated item
  1003. if (pSD->dwConnection != 0)
  1004. --celt;
  1005. }
  1006. // if we could skip them all, indicate by non-error return
  1007. if (celt == 0)
  1008. return(NOERROR);
  1009. return(ReportResult(0, S_FALSE, 0, 0));
  1010. }
  1011. //+----------------------------------------------------------------------------
  1012. //
  1013. // Member:
  1014. // CDAHolder::Reset, public
  1015. //
  1016. // Synopsis:
  1017. // implements IEnumSTATDATA::Reset
  1018. //
  1019. // Arguments:
  1020. // none
  1021. //
  1022. // Returns:
  1023. // S_OK
  1024. //
  1025. // Notes:
  1026. //
  1027. // History:
  1028. // 11/01/93 - ChrisWe - file inspection and cleanup
  1029. //
  1030. //-----------------------------------------------------------------------------
  1031. #pragma SEG(CEnumSTATDATA_Reset)
  1032. STDMETHODIMP CEnumSTATDATA::Reset()
  1033. {
  1034. VDATEHEAP();
  1035. M_PROLOG(this);
  1036. // move back to the beginning of the STATDATA array
  1037. m_iDataEnum = 0;
  1038. return NOERROR;
  1039. }
  1040. //+----------------------------------------------------------------------------
  1041. //
  1042. // Member:
  1043. // CDAHolder::Clone, public
  1044. //
  1045. // Synopsis:
  1046. // implements IEnumSTATDATA::Clone
  1047. //
  1048. // Arguments:
  1049. // none
  1050. //
  1051. // Returns:
  1052. // E_OUTOFMEMORY, S_OK
  1053. //
  1054. // Notes:
  1055. //
  1056. // History:
  1057. // 11/01/93 - ChrisWe - file inspection and cleanup
  1058. //
  1059. //-----------------------------------------------------------------------------
  1060. #pragma SEG(CEnumSTATDATA_Clone)
  1061. STDMETHODIMP CEnumSTATDATA::Clone(LPENUMSTATDATA FAR* ppenum)
  1062. {
  1063. VDATEHEAP();
  1064. M_PROLOG(this);
  1065. *ppenum = new FAR CEnumSTATDATA(m_pHolder, m_iDataEnum);
  1066. return *ppenum ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
  1067. }
  1068. //+----------------------------------------------------------------------------
  1069. //
  1070. // Member:
  1071. // CDAHolder::EnumAdvise, public
  1072. //
  1073. // Synopsis:
  1074. // implements IDataAdviseHolder::EnumAdvise
  1075. //
  1076. // Effects:
  1077. // creates an enumerator for the registered advise sinks
  1078. //
  1079. // Arguments:
  1080. // [ppenumAdvise] -- a pointer to where to return the enumerator
  1081. //
  1082. // Returns:
  1083. // E_OUTOFMEMORY, S_OK
  1084. //
  1085. // Notes:
  1086. //
  1087. // History:
  1088. // 11/01/93 - ChrisWe - file inspection and cleanup
  1089. //
  1090. //-----------------------------------------------------------------------------
  1091. #pragma SEG(CDAHolder_EnumAdvise)
  1092. STDMETHODIMP CDAHolder::EnumAdvise(IEnumSTATDATA FAR* FAR* ppenumAdvise)
  1093. {
  1094. VDATEHEAP();
  1095. M_PROLOG(this);
  1096. VDATEPTROUT(ppenumAdvise, IEnumSTATDATA FAR*);
  1097. // REVIEW, memory leak if bad ppenumAdvise pointer
  1098. *ppenumAdvise = new FAR CEnumSTATDATA(this, 0);
  1099. return *ppenumAdvise ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
  1100. }
  1101. //+-------------------------------------------------------------------------
  1102. //
  1103. // Member: CEnumSTATDATA::Dump, public (_DEBUG only)
  1104. //
  1105. // Synopsis: return a string containing the contents of the data members
  1106. //
  1107. // Effects:
  1108. //
  1109. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  1110. // [ulFlag] - flag determining prefix of all newlines of the
  1111. // out character array (default is 0 - no prefix)
  1112. // [nIndentLevel] - will add a indent prefix after the other prefix
  1113. // for ALL newlines (including those with no prefix)
  1114. //
  1115. // Requires:
  1116. //
  1117. // Returns: HRESULT
  1118. //
  1119. // Signals:
  1120. //
  1121. // Modifies: [ppsz] - argument
  1122. //
  1123. // Derivation:
  1124. //
  1125. // Algorithm: use dbgstream to create a string containing information on the
  1126. // content of data structures
  1127. //
  1128. // History: dd-mmm-yy Author Comment
  1129. // 20-Jan-95 t-ScottH author
  1130. //
  1131. // Notes:
  1132. //
  1133. //--------------------------------------------------------------------------
  1134. #ifdef _DEBUG
  1135. HRESULT CEnumSTATDATA::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  1136. {
  1137. int i;
  1138. char *pszPrefix;
  1139. char *pszDAH;
  1140. dbgstream dstrPrefix;
  1141. dbgstream dstrDump(1000);
  1142. // determine prefix of newlines
  1143. if ( ulFlag & DEB_VERBOSE )
  1144. {
  1145. dstrPrefix << this << " _VB ";
  1146. }
  1147. // determine indentation prefix for all newlines
  1148. for (i = 0; i < nIndentLevel; i++)
  1149. {
  1150. dstrPrefix << DUMPTAB;
  1151. }
  1152. pszPrefix = dstrPrefix.str();
  1153. // put data members in stream
  1154. dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
  1155. dstrDump << pszPrefix << "Index to next element = " << m_iDataEnum << endl;
  1156. if (m_pHolder != NULL)
  1157. {
  1158. pszDAH = DumpCDAHolder(m_pHolder, ulFlag, nIndentLevel + 1);
  1159. dstrDump << pszPrefix << "Data Advise Holder: " << endl;
  1160. dstrDump << pszDAH;
  1161. CoTaskMemFree(pszDAH);
  1162. }
  1163. else
  1164. {
  1165. dstrDump << pszPrefix << "pCDAHolder = " << m_pHolder << endl;
  1166. }
  1167. // cleanup and provide pointer to character array
  1168. *ppszDump = dstrDump.str();
  1169. if (*ppszDump == NULL)
  1170. {
  1171. *ppszDump = UtDupStringA(szDumpErrorMessage);
  1172. }
  1173. CoTaskMemFree(pszPrefix);
  1174. return NOERROR;
  1175. }
  1176. #endif // _DEBUG
  1177. //+-------------------------------------------------------------------------
  1178. //
  1179. // Function: DumpCEnumSTATDATA, public (_DEBUG only)
  1180. //
  1181. // Synopsis: calls the CEnumSTATDATA::Dump method, takes care of errors and
  1182. // returns the zero terminated string
  1183. //
  1184. // Effects:
  1185. //
  1186. // Arguments: [pESD] - pointer to CEnumSTATDATA
  1187. // [ulFlag] - flag determining prefix of all newlines of the
  1188. // out character array (default is 0 - no prefix)
  1189. // [nIndentLevel] - will add a indent prefix after the other prefix
  1190. // for ALL newlines (including those with no prefix)
  1191. //
  1192. // Requires:
  1193. //
  1194. // Returns: character array of structure dump or error (null terminated)
  1195. //
  1196. // Signals:
  1197. //
  1198. // Modifies:
  1199. //
  1200. // Algorithm:
  1201. //
  1202. // History: dd-mmm-yy Author Comment
  1203. // 20-Jan-95 t-ScottH author
  1204. //
  1205. // Notes:
  1206. //
  1207. //--------------------------------------------------------------------------
  1208. #ifdef _DEBUG
  1209. char *DumpCEnumSTATDATA(CEnumSTATDATA *pESD, ULONG ulFlag, int nIndentLevel)
  1210. {
  1211. HRESULT hresult;
  1212. char *pszDump;
  1213. if (pESD == NULL)
  1214. {
  1215. return UtDupStringA(szDumpBadPtr);
  1216. }
  1217. hresult = pESD->Dump(&pszDump, ulFlag, nIndentLevel);
  1218. if (hresult != NOERROR)
  1219. {
  1220. CoTaskMemFree(pszDump);
  1221. return DumpHRESULT(hresult);
  1222. }
  1223. return pszDump;
  1224. }
  1225. #endif // _DEBUG