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.

2477 lines
63 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: memstm.cpp
  7. //
  8. // Contents: Implementations of IStream and ILockBytes on memory
  9. // (versus the file system)
  10. //
  11. // Classes: CMemStm
  12. // CMemBytes
  13. // CMarshalMemStm
  14. // CMarshalMemBytes
  15. //
  16. // Functions: CreateMemStm
  17. // CloneMemStm
  18. // ReleaseMemStm
  19. // CreateStreamOnHGlobal
  20. // GetHGlobalFromStream
  21. // CMemStmUnMarshal
  22. // CMemBytesUnMarshall
  23. //
  24. // History: dd-mmm-yy Author Comment
  25. // 31-Jan-95 t-ScottH added Dump methods to CMemStm and CMemBytes
  26. // (_DEBUG only)
  27. // added DumpCMemStm and CMemBytes APIs
  28. // 04-Nov-94 ricksa Made CMemStm class multithread safe.
  29. // 24-Jan-94 alexgo first pass at converting to Cairo-style
  30. // memory allocation
  31. // 11-Jan-94 alexgo added VDATEHEAP macros to every function &
  32. // method, fixed compile warnings, removed
  33. // custom marshalling code. Memory streams
  34. // and ILockBytes now use standard
  35. // marshalling.
  36. // 16-Dec-93 alexgo fixed memory reference bugs (bad pointer)
  37. // 02-Dec-93 alexgo 32bit port, implement CMemStm::CopyTo
  38. // 11/22/93 - ChrisWe - replace overloaded ==, != with
  39. // IsEqualIID and IsEqualCLSID
  40. //
  41. // Notes:
  42. //
  43. //--------------------------------------------------------------------------
  44. #include <le2int.h>
  45. #pragma SEG(memstm)
  46. #include <nturtl.h>
  47. #include "memstm.h"
  48. #include "sem.hxx"
  49. #include <reterr.h>
  50. #ifdef _DEBUG
  51. #include "dbgdump.h"
  52. #endif // _DEBUG
  53. NAME_SEG(CMemStm)
  54. ASSERTDATA
  55. // CRefMutexSem implementation
  56. //
  57. // Instances of this class are shared among all CMemStm objects
  58. // cloned from a common CMemStm object, as well as their parent.
  59. //
  60. // This guarantees synchronization between all instances of CMemStm that share common data
  61. CRefMutexSem::CRefMutexSem() : m_lRefs(1)
  62. {
  63. // Note: we begin life with one reference
  64. }
  65. CRefMutexSem* CRefMutexSem::CreateInstance()
  66. {
  67. CRefMutexSem* prefMutexSem = NULL;
  68. prefMutexSem = new CRefMutexSem();
  69. if (prefMutexSem != NULL)
  70. {
  71. if (prefMutexSem->FInit() == FALSE)
  72. {
  73. ASSERT(FALSE);
  74. delete prefMutexSem;
  75. prefMutexSem = NULL;
  76. }
  77. }
  78. return prefMutexSem;
  79. }
  80. BOOL CRefMutexSem::FInit()
  81. {
  82. return m_mxs.FInit();
  83. }
  84. ULONG CRefMutexSem::AddRef()
  85. {
  86. return InterlockedIncrement (&m_lRefs);
  87. }
  88. ULONG CRefMutexSem::Release()
  89. {
  90. LONG lRefs = InterlockedDecrement (&m_lRefs);
  91. if (lRefs == 0)
  92. {
  93. delete this;
  94. }
  95. return lRefs;
  96. }
  97. void CRefMutexSem::RequestCS()
  98. {
  99. m_mxs.Request();
  100. }
  101. void CRefMutexSem::ReleaseCS()
  102. {
  103. m_mxs.Release();
  104. }
  105. const CMutexSem2* CRefMutexSem::GetMutexSem()
  106. {
  107. return &m_mxs;
  108. }
  109. inline CRefMutexAutoLock::CRefMutexAutoLock (CRefMutexSem* pmxs)
  110. {
  111. Win4Assert (pmxs != NULL);
  112. m_pmxs = pmxs;
  113. m_pmxs->RequestCS();
  114. END_CONSTRUCTION (CRefMutexAutoLock);
  115. }
  116. inline CRefMutexAutoLock::~CRefMutexAutoLock()
  117. {
  118. m_pmxs->ReleaseCS();
  119. }
  120. // Shared memory IStream implementation
  121. //
  122. //+-------------------------------------------------------------------------
  123. //
  124. // Member: CMemStm::CMemStm
  125. //
  126. // Synopsis: constructor for memory stream
  127. //
  128. // Arguments: none
  129. //
  130. // History: 20-Dec-94 Rickhi moved from h file
  131. //
  132. //--------------------------------------------------------------------------
  133. CMemStm::CMemStm()
  134. {
  135. m_hMem = NULL;
  136. m_pData = NULL;
  137. m_pos = 0;
  138. m_refs = 0;
  139. m_pmxs = NULL;
  140. }
  141. CMemStm::~CMemStm()
  142. {
  143. if (m_pmxs != NULL)
  144. {
  145. m_pmxs->Release();
  146. }
  147. }
  148. //+-------------------------------------------------------------------------
  149. //
  150. // Member: CMemStm::QueryInterface
  151. //
  152. // Synopsis: retrieves the requested interface
  153. //
  154. // Effects:
  155. //
  156. // Arguments: [iidInterface] -- the requested interface ID
  157. // [ppvObj] -- where to put the interface pointer
  158. //
  159. // Requires:
  160. //
  161. // Returns: NOERROR, E_OUTOFMEMORY, E_NOINTERFACE
  162. //
  163. // Signals:
  164. //
  165. // Modifies:
  166. //
  167. // Derivation: IStream
  168. //
  169. // Algorithm:
  170. //
  171. // History: dd-mmm-yy Author Comment
  172. // 04-Nov-94 ricksa Modified for multithreading
  173. // 11-Jan-94 alexgo removed QI for IMarshal so that
  174. // the standard marshaller is used.
  175. // This is fix marshalling across
  176. // process on 32bit platforms.
  177. // 02-Dec-93 alexgo 32bit port
  178. //
  179. // Notes:
  180. //
  181. //--------------------------------------------------------------------------
  182. #pragma SEG(CMemStm_QueryInterface)
  183. STDMETHODIMP CMemStm::QueryInterface(REFIID iidInterface,
  184. void FAR* FAR* ppvObj)
  185. {
  186. VDATEHEAP();
  187. HRESULT error;
  188. VDATEPTROUT( ppvObj, LPVOID );
  189. *ppvObj = NULL;
  190. VDATEIID( iidInterface );
  191. // Two interfaces supported: IUnknown, IStream
  192. if (m_pData != NULL && (IsEqualIID(iidInterface, IID_IStream) ||
  193. IsEqualIID(iidInterface, IID_ISequentialStream) ||
  194. IsEqualIID(iidInterface, IID_IUnknown)))
  195. {
  196. AddRef(); // A pointer to this object is returned
  197. *ppvObj = this;
  198. error = NOERROR;
  199. }
  200. else
  201. { // Not accessible or unsupported interface
  202. *ppvObj = NULL;
  203. error = ResultFromScode(E_NOINTERFACE);
  204. }
  205. return error;
  206. }
  207. //+-------------------------------------------------------------------------
  208. //
  209. // Member: CMemStm::AddRef
  210. //
  211. // Synopsis: increments the reference count
  212. //
  213. // Effects:
  214. //
  215. // Arguments: void
  216. //
  217. // Requires:
  218. //
  219. // Returns: ULONG -- the new reference count
  220. //
  221. // Signals:
  222. //
  223. // Modifies:
  224. //
  225. // Derivation: IStream
  226. //
  227. // Algorithm:
  228. //
  229. // History: dd-mmm-yy Author Comment
  230. // 02-Dec-93 alexgo 32bit port
  231. // 04-Nov-94 ricksa Modified for multithreading
  232. //
  233. // Notes:
  234. //
  235. //--------------------------------------------------------------------------
  236. #pragma SEG(CMemStm_AddRef)
  237. STDMETHODIMP_(ULONG) CMemStm::AddRef(void)
  238. {
  239. VDATEHEAP();
  240. return InterlockedIncrement((LONG *) &m_refs);
  241. }
  242. //+-------------------------------------------------------------------------
  243. //
  244. // Member: CMemStm::Release
  245. //
  246. // Synopsis: decrements the reference count
  247. //
  248. // Effects: deletes the object when ref count == 0
  249. //
  250. // Arguments: void
  251. //
  252. // Requires:
  253. //
  254. // Returns: ULONG -- the new ref count
  255. //
  256. // Signals:
  257. //
  258. // Modifies:
  259. //
  260. // Derivation: IStream
  261. //
  262. // Algorithm:
  263. //
  264. // History: dd-mmm-yy Author Comment
  265. // 04-Nov-94 ricksa Modified for multithreading
  266. // 16-Dec-93 alexgo added GlobalUnlock of the MEMSTM handle
  267. // 02-Dec-93 alexgo 32bit port
  268. //
  269. // Notes:
  270. //
  271. //--------------------------------------------------------------------------
  272. #pragma SEG(CMemStm_Release)
  273. STDMETHODIMP_(ULONG) CMemStm::Release(void)
  274. {
  275. VDATEHEAP();
  276. // The reason for this here is that there is a race when releasing
  277. // this object. If two threads are trying to release this object
  278. // at the same time, there is a case where the first one dec's
  279. // the ref count & then loses the processor to the second thread.
  280. // This second thread decrements the reference count to 0 and frees
  281. // the memory. The first thread can no longer safely examine the
  282. // internal state of the object.
  283. ULONG ulResult = InterlockedDecrement((LONG *) &m_refs);
  284. if (ulResult == 0)
  285. {
  286. // this MEMSTM handle was GlobalLock'ed in ::Create
  287. // we unlock it here, as we no longer need it.
  288. GlobalUnlock(m_hMem);
  289. ReleaseMemStm(&m_hMem);
  290. delete this;
  291. }
  292. return ulResult;
  293. }
  294. //+-------------------------------------------------------------------------
  295. //
  296. // Member: CMemStm::Read
  297. //
  298. // Synopsis: reads [cb] bytes from the stream
  299. //
  300. // Effects:
  301. //
  302. // Arguments: [pb] -- where to put the data read
  303. // [cb] -- the number of bytes to read
  304. // [pcbRead] -- where to put the actual number of bytes
  305. // read
  306. //
  307. // Requires:
  308. //
  309. // Returns: HRESULT
  310. //
  311. // Signals:
  312. //
  313. // Modifies:
  314. //
  315. // Derivation: IStream
  316. //
  317. // Algorithm: uses xmemcpy
  318. //
  319. // History: dd-mmm-yy Author Comment
  320. // 04-Nov-94 ricksa Modified for multithreading
  321. // 02-Dec-93 alexgo 32bit port
  322. //
  323. // Notes:
  324. //
  325. //--------------------------------------------------------------------------
  326. #pragma SEG(CMemStm_Read)
  327. STDMETHODIMP CMemStm::Read(void HUGEP* pb, ULONG cb, ULONG FAR* pcbRead)
  328. {
  329. VDATEHEAP();
  330. HRESULT error = NOERROR;
  331. ULONG cbRead = cb;
  332. if(cb)
  333. {
  334. VDATEPTROUT( pb, char);
  335. }
  336. // Single thread
  337. CRefMutexAutoLock lck(m_pmxs);
  338. if (pcbRead)
  339. {
  340. VDATEPTROUT( pcbRead, ULONG );
  341. *pcbRead = 0L;
  342. }
  343. // cbRead + m_pos could cause roll-over.
  344. if ( ( (cbRead + m_pos) > m_pData->cb) || ( (cbRead + m_pos) < m_pos) )
  345. {
  346. // Caller is asking for more bytes than we have left
  347. if(m_pData->cb > m_pos)
  348. cbRead = m_pData->cb - m_pos;
  349. else
  350. cbRead = 0;
  351. }
  352. if (cbRead > 0)
  353. {
  354. Assert (m_pData->hGlobal);
  355. BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
  356. m_pData->hGlobal);
  357. if (NULL==pGlobal)
  358. {
  359. LEERROR(1, "GlobalLock Failed!");
  360. return ResultFromScode (STG_E_READFAULT);
  361. }
  362. // overlap is currently considered a bug (see the discussion
  363. // on the Write method
  364. _xmemcpy(pb, pGlobal + m_pos, cbRead);
  365. GlobalUnlock (m_pData->hGlobal);
  366. m_pos += cbRead;
  367. }
  368. if (pcbRead != NULL)
  369. {
  370. *pcbRead = cbRead;
  371. }
  372. return error;
  373. }
  374. //+-------------------------------------------------------------------------
  375. //
  376. // Member: CMemStm::Write
  377. //
  378. // Synopsis: Writes [cb] bytes into the stream
  379. //
  380. // Effects:
  381. //
  382. // Arguments: [pb] -- the bytes to write
  383. // [cb] -- the number of bytes to write
  384. // [pcbWritten] -- where to put the number of bytes written
  385. //
  386. // Requires:
  387. //
  388. // Returns: HRESULT
  389. //
  390. // Signals:
  391. //
  392. // Modifies:
  393. //
  394. // Derivation: IStream
  395. //
  396. // Algorithm: resizes the internal buffer (if needed), then uses xmemcpy
  397. //
  398. // History: dd-mmm-yy Author Comment
  399. // 04-Nov-94 ricksa Modified for multithreading
  400. // 02-Dec-93 alexgo 32bit port, fixed bug dealing with
  401. // 0-byte sized memory
  402. // 06-Dec-93 alexgo handle overlap case.
  403. //
  404. // Notes:
  405. //
  406. //--------------------------------------------------------------------------
  407. #pragma SEG(CMemStm_Write)
  408. STDMETHODIMP CMemStm::Write(void const HUGEP* pb, ULONG cb,
  409. ULONG FAR* pcbWritten)
  410. {
  411. VDATEHEAP();
  412. HRESULT error = NOERROR;
  413. ULONG cbWritten = cb;
  414. ULARGE_INTEGER ularge_integer;
  415. BYTE HUGEP* pGlobal;
  416. if(cb)
  417. {
  418. VDATEPTRIN( pb , char );
  419. }
  420. // Single thread
  421. CRefMutexAutoLock lck(m_pmxs);
  422. if (pcbWritten != NULL)
  423. {
  424. *pcbWritten = 0;
  425. }
  426. if (cbWritten + m_pos > m_pData->cb)
  427. {
  428. ULISet32( ularge_integer, m_pos+cbWritten );
  429. error = SetSize(ularge_integer);
  430. if (error != NOERROR)
  431. {
  432. goto Exit;
  433. }
  434. }
  435. // we don't write anything if 0 bytes are asked for for two
  436. // reasons: 1. optimization, 2. m_pData->hGlobal could be a
  437. // handle to a zero-byte memory block, in which case GlobalLock
  438. // will fail.
  439. if( cbWritten > 0 )
  440. {
  441. pGlobal = (BYTE HUGEP *)GlobalLock (m_pData->hGlobal);
  442. if (NULL==pGlobal)
  443. {
  444. LEERROR(1, "GlobalLock Failed!");
  445. return ResultFromScode (STG_E_WRITEFAULT);
  446. }
  447. // we use memmove here instead of memcpy to handle the
  448. // overlap case. Recall that the app originally gave
  449. // use the memory for the memstm. He could (either through
  450. // a CopyTo or through really strange code), be giving us
  451. // this region to read from, so we have to handle the overlapp
  452. // case. The same argument also applies for Read, but for
  453. // now, we'll consider overlap on Read a bug.
  454. _xmemmove(pGlobal + m_pos, pb, cbWritten);
  455. GlobalUnlock (m_pData->hGlobal);
  456. m_pos += cbWritten;
  457. }
  458. if (pcbWritten != NULL)
  459. {
  460. *pcbWritten = cbWritten;
  461. }
  462. Exit:
  463. return error;
  464. }
  465. //+-------------------------------------------------------------------------
  466. //
  467. // Member: CMemStm::Seek
  468. //
  469. // Synopsis: Moves the internal seek pointer
  470. //
  471. // Effects:
  472. //
  473. // Arguments: [dlibMoveIN] -- the amount to move by
  474. // [dwOrigin] -- flags to control whether seeking is
  475. // relative to the current postion or
  476. // the begging/end.
  477. // [plibNewPosition] -- where to put the new position
  478. //
  479. // Requires:
  480. //
  481. // Returns: HRESULT
  482. //
  483. // Signals:
  484. //
  485. // Modifies:
  486. //
  487. // Derivation: IStream
  488. //
  489. // Algorithm:
  490. //
  491. // History: dd-mmm-yy Author Comment
  492. // 04-Nov-94 ricksa Modified for multithreading
  493. // 02-Dec-93 alexgo 32bit port
  494. //
  495. // Notes:
  496. //
  497. //--------------------------------------------------------------------------
  498. #pragma SEG(CMemStm_Seek)
  499. STDMETHODIMP CMemStm::Seek(LARGE_INTEGER dlibMoveIN, DWORD dwOrigin,
  500. ULARGE_INTEGER FAR* plibNewPosition)
  501. {
  502. VDATEHEAP();
  503. HRESULT error = NOERROR;
  504. LONG dlibMove = dlibMoveIN.LowPart ;
  505. ULONG cbNewPos = dlibMove;
  506. // Single thread
  507. CRefMutexAutoLock lck(m_pmxs);
  508. if (plibNewPosition != NULL)
  509. {
  510. VDATEPTROUT( plibNewPosition, ULONG );
  511. ULISet32(*plibNewPosition, m_pos);
  512. }
  513. switch(dwOrigin)
  514. {
  515. case STREAM_SEEK_SET:
  516. if (dlibMove >= 0)
  517. {
  518. m_pos = dlibMove;
  519. }
  520. else
  521. {
  522. error = ResultFromScode(STG_E_SEEKERROR);
  523. }
  524. break;
  525. case STREAM_SEEK_CUR:
  526. if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pos))
  527. {
  528. m_pos += dlibMove;
  529. }
  530. else
  531. {
  532. error = ResultFromScode(STG_E_SEEKERROR);
  533. }
  534. break;
  535. case STREAM_SEEK_END:
  536. if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pData->cb))
  537. {
  538. m_pos = m_pData->cb + dlibMove;
  539. }
  540. else
  541. {
  542. error = ResultFromScode(STG_E_SEEKERROR);
  543. }
  544. break;
  545. default:
  546. error = ResultFromScode(STG_E_SEEKERROR);
  547. }
  548. if (plibNewPosition != NULL)
  549. {
  550. ULISet32(*plibNewPosition, m_pos);
  551. }
  552. return error;
  553. }
  554. //+-------------------------------------------------------------------------
  555. //
  556. // Member: CMemStm::SetSize
  557. //
  558. // Synopsis: Sets the size of our memory
  559. //
  560. // Effects:
  561. //
  562. // Arguments: [cb] -- the new size
  563. //
  564. // Requires:
  565. //
  566. // Returns: HRESULT
  567. //
  568. // Signals:
  569. //
  570. // Modifies:
  571. //
  572. // Derivation: IStream
  573. //
  574. // Algorithm: calls GlobalRealloc
  575. //
  576. // History: dd-mmm-yy Author Comment
  577. // 04-Nov-94 ricksa Modified for multithreading
  578. // 02-Dec-93 alexgo 32bit port, added assert
  579. //
  580. // Notes:
  581. //
  582. //--------------------------------------------------------------------------
  583. #pragma SEG(CMemStm_SetSize)
  584. STDMETHODIMP CMemStm::SetSize(ULARGE_INTEGER cb)
  585. {
  586. VDATEHEAP();
  587. HANDLE hMemNew;
  588. // Single thread
  589. CRefMutexAutoLock lck(m_pmxs);
  590. // make sure we aren't in overflow conditions.
  591. AssertSz(cb.HighPart == 0,
  592. "MemStream::More than 2^32 bytes asked for");
  593. if (m_pData->cb == cb.LowPart)
  594. {
  595. return NOERROR;
  596. }
  597. hMemNew = GlobalReAlloc(m_pData->hGlobal, max (cb.LowPart,1),
  598. GMEM_SHARE | GMEM_MOVEABLE);
  599. if (hMemNew == NULL)
  600. {
  601. return ResultFromScode (E_OUTOFMEMORY);
  602. }
  603. m_pData->hGlobal = hMemNew;
  604. m_pData->cb = cb.LowPart;
  605. return NOERROR;
  606. }
  607. //+-------------------------------------------------------------------------
  608. //
  609. // Member: CMemStm::CopyTo
  610. //
  611. // Synopsis: Copies data from [this] stream to [pstm]
  612. //
  613. // Effects:
  614. //
  615. // Arguments: [pstm] -- the stream to copy to
  616. // [cb] -- the number of bytes to copy
  617. // [pcbRead] -- where to return the number of bytes read
  618. // [pcbWritten] -- where to return the number of bytes written
  619. //
  620. // Requires:
  621. //
  622. // Returns: HRESULT
  623. //
  624. // Signals:
  625. //
  626. // Modifies:
  627. //
  628. // Derivation: IStream
  629. //
  630. // Algorithm: does an IStream->Write to the given stream
  631. //
  632. // History: dd-mmm-yy Author Comment
  633. // 04-Nov-94 ricksa Modified for multithreading
  634. // 03-Dec-93 alexgo original implementation
  635. //
  636. // Notes: This implementation assumes that the address space
  637. // is not greater than ULARGE_INTEGER.LowPart (which is
  638. // for for 32bit operating systems). 64bit NT may need
  639. // to revisit this code.
  640. //
  641. //--------------------------------------------------------------------------
  642. #pragma SEG(CMemStm_CopyTo)
  643. STDMETHODIMP CMemStm::CopyTo(IStream FAR *pstm, ULARGE_INTEGER cb,
  644. ULARGE_INTEGER FAR * pcbRead, ULARGE_INTEGER FAR * pcbWritten)
  645. {
  646. VDATEHEAP();
  647. ULONG cbRead = cb.LowPart;
  648. ULONG cbWritten = 0;
  649. HRESULT hresult = NOERROR;
  650. // pstm cannot be NULL
  651. VDATEPTRIN(pstm, LPSTREAM);
  652. // Single thread
  653. CRefMutexAutoLock lck(m_pmxs);
  654. // the spec says that if cb is it's maximum value (all bits set,
  655. // since it's unsigned), then we will simply read the copy of
  656. // this stream
  657. if ( ~(cb.LowPart) == 0 && ~(cb.HighPart) == 0 )
  658. {
  659. cbRead = m_pData->cb - m_pos;
  660. }
  661. else if ( cb.HighPart > 0 )
  662. {
  663. // we assume that our memory stream cannot
  664. // be large enough to accomodate very large (>32bit)
  665. // copy to requests. Since this is probably an error
  666. // on the caller's part, we assert.
  667. AssertSz(0, "WARNING: CopyTo request exceeds 32 bits");
  668. // set the Read value to what's left, so that "Ignore"ing
  669. // the assert works properly.
  670. cbRead = m_pData->cb - m_pos;
  671. }
  672. else if ( cbRead + m_pos > m_pData->cb )
  673. {
  674. // more bytes were requested to read than we had left.
  675. // cbRead is set to the amount remaining.
  676. cbRead = m_pData->cb - m_pos;
  677. }
  678. // now write the data to the stream
  679. if ( cbRead > 0 )
  680. {
  681. BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
  682. m_pData->hGlobal);
  683. if( pGlobal == NULL )
  684. {
  685. LEERROR(1, "GlobalLock failed");
  686. return ResultFromScode(STG_E_INSUFFICIENTMEMORY);
  687. }
  688. hresult = pstm->Write(pGlobal + m_pos, cbRead, &cbWritten);
  689. // in the error case, the spec says that the return values
  690. // may be meaningless, so we do not need to do any special
  691. // error handling here
  692. GlobalUnlock(m_pData->hGlobal);
  693. }
  694. // increment our seek pointer and set the out parameters
  695. m_pos += cbRead;
  696. if( pcbRead )
  697. {
  698. ULISet32(*pcbRead, cbRead);
  699. }
  700. if( pcbWritten )
  701. {
  702. ULISet32(*pcbWritten, cbWritten);
  703. }
  704. return hresult;
  705. }
  706. //+-------------------------------------------------------------------------
  707. //
  708. // Member: CMemStm::Commit
  709. //
  710. // Synopsis: Does nothing, no transactions available on memory streams
  711. //
  712. // Effects:
  713. //
  714. // Arguments: [grfCommitFlags]
  715. //
  716. // Requires:
  717. //
  718. // Returns: NOERROR
  719. //
  720. // Signals:
  721. //
  722. // Modifies:
  723. //
  724. // Derivation: IStream
  725. //
  726. // Algorithm:
  727. //
  728. // History: dd-mmm-yy Author Comment
  729. // 03-Dec-93 alexgo 32bit port
  730. //
  731. // Notes:
  732. //
  733. //--------------------------------------------------------------------------
  734. #pragma SEG(CMemStm_Commit)
  735. STDMETHODIMP CMemStm::Commit(DWORD grfCommitFlags)
  736. {
  737. VDATEHEAP();
  738. return NOERROR;
  739. }
  740. //+-------------------------------------------------------------------------
  741. //
  742. // Member: CMemStm::Revert
  743. //
  744. // Synopsis: does nothing, as no transactions are supported on memory
  745. // streams
  746. //
  747. // Effects:
  748. //
  749. // Arguments: void
  750. //
  751. // Requires:
  752. //
  753. // Returns: NOERROR
  754. //
  755. // Signals:
  756. //
  757. // Modifies:
  758. //
  759. // Derivation: IStream
  760. //
  761. // Algorithm:
  762. //
  763. // History: dd-mmm-yy Author Comment
  764. // 03-Dec-93 alexgo 32bit port
  765. //
  766. // Notes:
  767. //
  768. //--------------------------------------------------------------------------
  769. #pragma SEG(CMemStm_Revert)
  770. STDMETHODIMP CMemStm::Revert(void)
  771. {
  772. VDATEHEAP();
  773. return NOERROR;
  774. }
  775. //+-------------------------------------------------------------------------
  776. //
  777. // Member: CMemStm::LockRegion
  778. //
  779. // Synopsis: not supported in OLE2.01
  780. //
  781. // Effects:
  782. //
  783. // Arguments: [libOffset]
  784. // [cb]
  785. // [dwLockType]
  786. //
  787. // Requires:
  788. //
  789. // Returns: STG_E_INVALIDFUNCTION
  790. //
  791. // Signals:
  792. //
  793. // Modifies:
  794. //
  795. // Derivation: IStream
  796. //
  797. // Algorithm:
  798. //
  799. // History: dd-mmm-yy Author Comment
  800. // 03-Dec-93 alexgo 32bit port
  801. //
  802. // Notes:
  803. //
  804. //--------------------------------------------------------------------------
  805. #pragma SEG(CMemStm_LockRegion)
  806. STDMETHODIMP CMemStm::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
  807. DWORD dwLockType)
  808. {
  809. VDATEHEAP();
  810. return ResultFromScode(STG_E_INVALIDFUNCTION);
  811. }
  812. //+-------------------------------------------------------------------------
  813. //
  814. // Member: CMemStm::UnlockRegion
  815. //
  816. // Synopsis: not implemented for OLE2.01
  817. //
  818. // Effects:
  819. //
  820. // Arguments: [libOffset]
  821. // [cb]
  822. // [dwLockType]
  823. //
  824. // Requires:
  825. //
  826. // Returns: STG_E_INVALIDFUNCTION
  827. //
  828. // Signals:
  829. //
  830. // Modifies:
  831. //
  832. // Derivation: IStream
  833. //
  834. // Algorithm:
  835. //
  836. // History: dd-mmm-yy Author Comment
  837. // 03-Dec-93 alexgo 32bit port
  838. //
  839. // Notes:
  840. //
  841. //--------------------------------------------------------------------------
  842. #pragma SEG(CMemStm_UnlockRegion)
  843. STDMETHODIMP CMemStm::UnlockRegion(ULARGE_INTEGER libOffset,
  844. ULARGE_INTEGER cb, DWORD dwLockType)
  845. {
  846. VDATEHEAP();
  847. return ResultFromScode(STG_E_INVALIDFUNCTION);
  848. }
  849. //+-------------------------------------------------------------------------
  850. //
  851. // Member: CMemStm::Stat
  852. //
  853. // Synopsis: Returns info about this stream
  854. //
  855. // Effects:
  856. //
  857. // Arguments: [pstatstg] -- the STATSTG to fill with info
  858. // [statflag] -- status flags, unused
  859. //
  860. // Requires:
  861. //
  862. // Returns: NOERROR, E_INVALIDARG
  863. //
  864. // Signals:
  865. //
  866. // Modifies:
  867. //
  868. // Derivation: IStream
  869. //
  870. // Algorithm:
  871. //
  872. // History: dd-mmm-yy Author Comment
  873. // 03-Dec-93 alexgo 32bit port
  874. // 01-Jun-94 AlexT Set type correctly
  875. //
  876. // Notes:
  877. //
  878. //--------------------------------------------------------------------------
  879. #pragma SEG(CMemStm_Stat)
  880. STDMETHODIMP CMemStm::Stat(STATSTG FAR *pstatstg, DWORD statflag)
  881. {
  882. VDATEHEAP();
  883. VDATEPTROUT( pstatstg, STATSTG );
  884. memset ( pstatstg, 0, sizeof(STATSTG) );
  885. pstatstg->type = STGTY_STREAM;
  886. pstatstg->cbSize.LowPart = m_pData->cb;
  887. return NOERROR;
  888. }
  889. //+-------------------------------------------------------------------------
  890. //
  891. // Member: CMemStm::Clone
  892. //
  893. // Synopsis: creates a new instance of this stream pointing to the
  894. // same data at the same position (same seek pointer)
  895. //
  896. // Effects:
  897. //
  898. // Arguments: [ppstm] -- where to put the new CMemStm pointer
  899. //
  900. // Requires:
  901. //
  902. // Returns: NOERROR, E_OUTOFMEMORY
  903. //
  904. // Signals:
  905. //
  906. // Modifies:
  907. //
  908. // Derivation: IStream
  909. //
  910. // Algorithm:
  911. //
  912. // History: dd-mmm-yy Author Comment
  913. // 03-Dec-93 alexgo 32bit port
  914. //
  915. // Notes:
  916. //
  917. //--------------------------------------------------------------------------
  918. #pragma SEG(CMemStm_Clone)
  919. STDMETHODIMP CMemStm::Clone(IStream FAR * FAR *ppstm)
  920. {
  921. VDATEHEAP();
  922. CMemStm FAR* pCMemStm;
  923. VDATEPTROUT (ppstm, LPSTREAM);
  924. *ppstm = pCMemStm = CMemStm::Create(m_hMem, m_pmxs);
  925. if (pCMemStm == NULL)
  926. {
  927. return ResultFromScode(E_OUTOFMEMORY);
  928. }
  929. pCMemStm->m_pos = m_pos;
  930. return NOERROR;
  931. }
  932. //+-------------------------------------------------------------------------
  933. //
  934. // Member: CMemStm::Create
  935. //
  936. // Synopsis: Creates a new CMemStm. [hMem] must be a handle to a MEMSTM
  937. // block.
  938. //
  939. // Effects:
  940. //
  941. // Arguments: [hMem] -- handle to a MEMSTM block
  942. //
  943. // Requires:
  944. //
  945. // Returns: CMemStm *
  946. //
  947. // Signals:
  948. //
  949. // Modifies:
  950. //
  951. // Derivation:
  952. //
  953. // Algorithm:
  954. //
  955. // History: dd-mmm-yy Author Comment
  956. // 15-Dec-93 alexgo fixed memory access bug
  957. // 03-Dec-93 alexgo 32bit port
  958. // 20-Sep-2000 mfeingol Added Mutex inheritance
  959. //
  960. // Notes:
  961. //
  962. //--------------------------------------------------------------------------
  963. #pragma SEG(CMemStm_Create)
  964. STDSTATICIMP_(CMemStm FAR*) CMemStm::Create(HANDLE hMem, CRefMutexSem* pmxs)
  965. {
  966. VDATEHEAP();
  967. CMemStm FAR* pCMemStm = NULL;
  968. struct MEMSTM FAR* pData;
  969. pData = (MEMSTM FAR*) GlobalLock(hMem);
  970. if (pData != NULL)
  971. {
  972. pCMemStm = new CMemStm;
  973. if (pCMemStm != NULL)
  974. {
  975. // Initialize CMemStm
  976. pCMemStm->m_hMem = hMem;
  977. InterlockedIncrement ((LPLONG) &(pCMemStm->m_pData = pData)->cRef); // AddRefMemStm
  978. pCMemStm->m_refs = 1;
  979. pCMemStm->m_dwSig = STREAM_SIG;
  980. if (pmxs != NULL)
  981. {
  982. // Addref the input
  983. pmxs->AddRef();
  984. }
  985. else
  986. {
  987. // Create a new mutex (implicit addref)
  988. pmxs = CRefMutexSem::CreateInstance();
  989. }
  990. if (pmxs != NULL)
  991. {
  992. // Give the CMemStm a mutex
  993. pCMemStm->m_pmxs = pmxs;
  994. }
  995. else
  996. {
  997. // uh-oh, low on memory
  998. delete pCMemStm;
  999. pCMemStm = NULL;
  1000. GlobalUnlock(hMem);
  1001. }
  1002. }
  1003. else
  1004. {
  1005. // uh-oh, low on memory
  1006. GlobalUnlock(hMem);
  1007. }
  1008. }
  1009. // we do *not* unlock the memory now, the memstm structure should
  1010. // be locked for the lifetime of any CMemStm's that refer to it.
  1011. // when the CMemStm is destroyed, we will release our lock on
  1012. // hMem.
  1013. return pCMemStm;
  1014. }
  1015. //+-------------------------------------------------------------------------
  1016. //
  1017. // Member: CMemStm::Dump, public (_DEBUG only)
  1018. //
  1019. // Synopsis: return a string containing the contents of the data members
  1020. //
  1021. // Effects:
  1022. //
  1023. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  1024. // [ulFlag] - flag determining prefix of all newlines of the
  1025. // out character array (default is 0 - no prefix)
  1026. // [nIndentLevel] - will add a indent prefix after the other prefix
  1027. // for ALL newlines (including those with no prefix)
  1028. //
  1029. // Requires:
  1030. //
  1031. // Returns: HRESULT
  1032. //
  1033. // Signals:
  1034. //
  1035. // Modifies: [ppsz] - argument
  1036. //
  1037. // Derivation:
  1038. //
  1039. // Algorithm: use dbgstream to create a string containing information on the
  1040. // content of data structures
  1041. //
  1042. // History: dd-mmm-yy Author Comment
  1043. // 20-Jan-95 t-ScottH author
  1044. //
  1045. // Notes:
  1046. //
  1047. //--------------------------------------------------------------------------
  1048. #ifdef _DEBUG
  1049. HRESULT CMemStm::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  1050. {
  1051. int i;
  1052. char *pszPrefix;
  1053. char *pszMEMSTM;
  1054. char *pszCMutexSem;
  1055. dbgstream dstrPrefix;
  1056. dbgstream dstrDump(400);
  1057. // determine prefix of newlines
  1058. if ( ulFlag & DEB_VERBOSE )
  1059. {
  1060. dstrPrefix << this << " _VB ";
  1061. }
  1062. // determine indentation prefix for all newlines
  1063. for (i = 0; i < nIndentLevel; i++)
  1064. {
  1065. dstrPrefix << DUMPTAB;
  1066. }
  1067. pszPrefix = dstrPrefix.str();
  1068. // put data members in stream
  1069. dstrDump << pszPrefix << "Impl. Signature = " << m_dwSig << endl;
  1070. dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
  1071. dstrDump << pszPrefix << "Seek pointer = " << m_pos << endl;
  1072. dstrDump << pszPrefix << "Memory handle = " << m_hMem << endl;
  1073. if (m_pData != NULL)
  1074. {
  1075. pszMEMSTM = DumpMEMSTM(m_pData, ulFlag, nIndentLevel + 1);
  1076. dstrDump << pszPrefix << "MEMSTM:" << endl;
  1077. dstrDump << pszMEMSTM;
  1078. CoTaskMemFree(pszMEMSTM);
  1079. }
  1080. else
  1081. {
  1082. dstrDump << pszPrefix << "MEMSTM = " << m_pData << endl;
  1083. }
  1084. pszCMutexSem = DumpCMutexSem ((CMutexSem2*) m_pmxs->GetMutexSem());
  1085. dstrDump << pszPrefix << "Mutex = " << pszCMutexSem << endl;
  1086. CoTaskMemFree(pszCMutexSem);
  1087. // cleanup and provide pointer to character array
  1088. *ppszDump = dstrDump.str();
  1089. if (*ppszDump == NULL)
  1090. {
  1091. *ppszDump = UtDupStringA(szDumpErrorMessage);
  1092. }
  1093. CoTaskMemFree(pszPrefix);
  1094. return NOERROR;
  1095. }
  1096. #endif // _DEBUG
  1097. //+-------------------------------------------------------------------------
  1098. //
  1099. // Function: DumpCMemStm, public (_DEBUG only)
  1100. //
  1101. // Synopsis: calls the CMemStm::Dump method, takes care of errors and
  1102. // returns the zero terminated string
  1103. //
  1104. // Effects:
  1105. //
  1106. // Arguments: [pMS] - pointer to CMemStm
  1107. // [ulFlag] - flag determining prefix of all newlines of the
  1108. // out character array (default is 0 - no prefix)
  1109. // [nIndentLevel] - will add a indent prefix after the other prefix
  1110. // for ALL newlines (including those with no prefix)
  1111. //
  1112. // Requires:
  1113. //
  1114. // Returns: character array of structure dump or error (null terminated)
  1115. //
  1116. // Signals:
  1117. //
  1118. // Modifies:
  1119. //
  1120. // Algorithm:
  1121. //
  1122. // History: dd-mmm-yy Author Comment
  1123. // 20-Jan-95 t-ScottH author
  1124. //
  1125. // Notes:
  1126. //
  1127. //--------------------------------------------------------------------------
  1128. #ifdef _DEBUG
  1129. char *DumpCMemStm(CMemStm *pMS, ULONG ulFlag, int nIndentLevel)
  1130. {
  1131. HRESULT hresult;
  1132. char *pszDump;
  1133. if (pMS == NULL)
  1134. {
  1135. return UtDupStringA(szDumpBadPtr);
  1136. }
  1137. hresult = pMS->Dump(&pszDump, ulFlag, nIndentLevel);
  1138. if (hresult != NOERROR)
  1139. {
  1140. CoTaskMemFree(pszDump);
  1141. return DumpHRESULT(hresult);
  1142. }
  1143. return pszDump;
  1144. }
  1145. #endif // _DEBUG
  1146. //+-------------------------------------------------------------------------
  1147. //
  1148. // Function: CreateMemStm
  1149. //
  1150. // Synopsis: Allocates memory and creates a CMemStm for it.
  1151. //
  1152. // Effects:
  1153. //
  1154. // Arguments: [cb] -- the number of bytes to allocate
  1155. // [phMem] -- where to put a handle to the MEMSTM structure
  1156. //
  1157. // Requires:
  1158. //
  1159. // Returns: LPSTREAM to the CMemStream
  1160. //
  1161. // Signals:
  1162. //
  1163. // Modifies:
  1164. //
  1165. // Algorithm:
  1166. //
  1167. // History: dd-mmm-yy Author Comment
  1168. // 03-Dec-93 alexgo 32bit port
  1169. //
  1170. // Notes: phMem must be free'd with ReleaseMemStm (because of ref
  1171. // counting and the nested handle)
  1172. //
  1173. //--------------------------------------------------------------------------
  1174. #pragma SEG(CreateMemStm)
  1175. STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem)
  1176. {
  1177. VDATEHEAP();
  1178. HANDLE h;
  1179. LPSTREAM pstm = NULL;
  1180. if (phMem)
  1181. {
  1182. *phMem = NULL;
  1183. }
  1184. h = GlobalAlloc (GMEM_SHARE | GMEM_MOVEABLE, cb);
  1185. if (NULL==h)
  1186. {
  1187. return NULL;
  1188. }
  1189. if (CreateStreamOnHGlobal (h, TRUE, &pstm) != NOERROR)
  1190. {
  1191. GlobalFree(h); // COM+ 22886
  1192. return NULL;
  1193. }
  1194. if (phMem)
  1195. {
  1196. // retrieve handle from just-created CMemStm
  1197. *phMem = ((CMemStm FAR*)pstm)->m_hMem;
  1198. // use pointer to bump ref count
  1199. Assert(((CMemStm FAR*)pstm)->m_pData != NULL);
  1200. InterlockedIncrement ((LPLONG) &((CMemStm FAR*)pstm)->m_pData->cRef); // AddRefMemStm
  1201. }
  1202. return pstm;
  1203. }
  1204. //+-------------------------------------------------------------------------
  1205. //
  1206. // Function: CloneMemStm
  1207. //
  1208. // Synopsis: Clones a memory stream
  1209. //
  1210. // Effects:
  1211. //
  1212. // Arguments: [hMem] -- a handle to the MEMSTM block
  1213. //
  1214. // Requires:
  1215. //
  1216. // Returns: LPSTREAM
  1217. //
  1218. // Signals:
  1219. //
  1220. // Modifies:
  1221. //
  1222. // Algorithm:
  1223. //
  1224. // History: dd-mmm-yy Author Comment
  1225. // 05-Dec-93 alexgo 32bit port
  1226. //
  1227. // Notes:
  1228. //
  1229. //--------------------------------------------------------------------------
  1230. #pragma SEG(CloneMemStm)
  1231. STDAPI_(LPSTREAM) CloneMemStm(HANDLE hMem)
  1232. {
  1233. VDATEHEAP();
  1234. return CMemStm::Create(hMem, NULL); // Create the stream
  1235. }
  1236. //+-------------------------------------------------------------------------
  1237. //
  1238. // Function: ReleaseMemStm
  1239. //
  1240. // Synopsis: Releases the memory used by a MEMSTM structure (including
  1241. // the nested handle)
  1242. //
  1243. // Effects:
  1244. //
  1245. // Arguments: [phMem] -- pointer the MEMSTM handle
  1246. // [fInternalOnly] -- if TRUE, then only the actual memory
  1247. // that MEMSTM refers to is freed
  1248. // (not the MEMSTM structure itself)
  1249. //
  1250. // Requires:
  1251. //
  1252. // Returns: void
  1253. //
  1254. // Signals:
  1255. //
  1256. // Modifies: sets *phMem to NULL on success
  1257. //
  1258. // Algorithm:
  1259. //
  1260. // History: dd-mmm-yy Author Comment
  1261. // 05-Dec-93 alexgo 32bit port and fixed bad memory access
  1262. // bug
  1263. //
  1264. // Notes: REVIEW32: look at taking out the second argument
  1265. //
  1266. //--------------------------------------------------------------------------
  1267. #pragma SEG(ReleaseMemStm)
  1268. STDAPI_(void) ReleaseMemStm (LPHANDLE phMem, BOOL fInternalOnly)
  1269. {
  1270. VDATEHEAP();
  1271. struct MEMSTM FAR* pData;
  1272. pData = (MEMSTM FAR*) GlobalLock(*phMem);
  1273. // check for NULL pointer in case handle got freed already
  1274. // decrement ref count and free if no refs left
  1275. if (pData != NULL && InterlockedDecrement ((LPLONG) &pData->cRef) == 0)
  1276. {
  1277. if (pData->fDeleteOnRelease)
  1278. {
  1279. Verify (0==GlobalFree (pData->hGlobal));
  1280. }
  1281. if (!fInternalOnly)
  1282. {
  1283. GlobalUnlock(*phMem);
  1284. Verify (0==GlobalFree(*phMem));
  1285. goto End;
  1286. }
  1287. }
  1288. GlobalUnlock(*phMem);
  1289. End:
  1290. *phMem = NULL;
  1291. }
  1292. //+-------------------------------------------------------------------------
  1293. //
  1294. // Function: CreateStreamOnHGlobal
  1295. //
  1296. // Synopsis: Creates a CMemStm from the given hGlobal (if [hGlobal] is
  1297. // NULL, we allocate a zero byte one)
  1298. //
  1299. // Effects:
  1300. //
  1301. // Arguments: [hGlobal] -- the memory
  1302. // [fDeleteOnRelease] -- whether the memory should be
  1303. // release on delete
  1304. // [ppstm] -- where to put the stream
  1305. //
  1306. // Requires:
  1307. //
  1308. // Returns: HRESULT
  1309. //
  1310. // Signals:
  1311. //
  1312. // Modifies:
  1313. //
  1314. // Algorithm:
  1315. //
  1316. // History: dd-mmm-yy Author Comment
  1317. // 11-Jan-93 alexgo removed initialization of cbSize to -1
  1318. // to fix compile warning
  1319. // 05-Dec-93 alexgo 32bit port
  1320. //
  1321. // Notes:
  1322. //
  1323. //--------------------------------------------------------------------------
  1324. #pragma SEG(CreateStreamOnHGlobal)
  1325. STDAPI CreateStreamOnHGlobal(HANDLE hGlobal, BOOL fDeleteOnRelease,
  1326. LPSTREAM FAR* ppstm)
  1327. {
  1328. OLETRACEIN((API_CreateStreamOnHGlobal, PARAMFMT("hGlobal= %h, fDeleteOnRelease= %B, ppstm= %p"),
  1329. hGlobal, fDeleteOnRelease, ppstm));
  1330. VDATEHEAP();
  1331. HANDLE hMem = NULL;
  1332. struct MEMSTM FAR* pData = NULL;
  1333. LPSTREAM pstm = NULL;
  1334. DWORD cbSize;
  1335. BOOL fAllocated = FALSE;
  1336. HRESULT hresult;
  1337. VDATEPTROUT_LABEL (ppstm, LPSTREAM, SafeExit, hresult);
  1338. *ppstm = NULL;
  1339. if (NULL==hGlobal)
  1340. {
  1341. hGlobal = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, 0);
  1342. if (hGlobal == NULL)
  1343. {
  1344. goto FreeMem;
  1345. }
  1346. cbSize = 0;
  1347. fAllocated = TRUE;
  1348. }
  1349. else
  1350. {
  1351. cbSize = (ULONG) GlobalSize (hGlobal);
  1352. // Is there a way to verify a zero-sized handle?
  1353. // we currently do no verification for them
  1354. if (cbSize!=0)
  1355. {
  1356. // verify validity of passed-in handle
  1357. if (NULL==GlobalLock(hGlobal))
  1358. {
  1359. // bad handle
  1360. hresult = ResultFromScode (E_INVALIDARG);
  1361. goto SafeExit;
  1362. }
  1363. GlobalUnlock (hGlobal);
  1364. }
  1365. }
  1366. hMem = GlobalAlloc (GMEM_SHARE | GMEM_MOVEABLE, sizeof (MEMSTM));
  1367. if (hMem == NULL)
  1368. {
  1369. goto FreeMem;
  1370. }
  1371. pData = (MEMSTM FAR*) GlobalLock(hMem);
  1372. if (pData == NULL)
  1373. {
  1374. GlobalUnlock(hMem);
  1375. goto FreeMem;
  1376. }
  1377. pData->cRef = 0;
  1378. pData->cb = cbSize;
  1379. pData->fDeleteOnRelease = fDeleteOnRelease;
  1380. pData->hGlobal = hGlobal;
  1381. GlobalUnlock(hMem);
  1382. pstm = CMemStm::Create(hMem, NULL);
  1383. if (pstm == NULL)
  1384. {
  1385. goto FreeMem;
  1386. }
  1387. *ppstm = pstm;
  1388. CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)ppstm);
  1389. hresult = NOERROR;
  1390. goto SafeExit;
  1391. FreeMem:
  1392. if (hGlobal && fAllocated)
  1393. {
  1394. Verify(0==GlobalFree(hGlobal));
  1395. }
  1396. if (hMem)
  1397. {
  1398. Verify(0==GlobalFree(hMem));
  1399. }
  1400. LEERROR(1, "Out of memory!");
  1401. hresult = ResultFromScode(E_OUTOFMEMORY);
  1402. SafeExit:
  1403. OLETRACEOUT((API_CreateStreamOnHGlobal, hresult));
  1404. return hresult;
  1405. }
  1406. //+-------------------------------------------------------------------------
  1407. //
  1408. // Function: GetHGlobalFromStream
  1409. //
  1410. // Synopsis: Retrieves the HGLOBAL to the memory from the given stream
  1411. // pointer (must be a pointer to a CMemByte structure)
  1412. //
  1413. // Effects:
  1414. //
  1415. // Arguments: [pstm] -- pointer to the CMemByte
  1416. // [phglobal] -- where to put the hglobal
  1417. //
  1418. // Requires:
  1419. //
  1420. // Returns: HRESULT (E_INVALIDARG, E_OUTOFMEMORY, NOERROR)
  1421. //
  1422. // Signals:
  1423. //
  1424. // Modifies:
  1425. //
  1426. // Algorithm:
  1427. //
  1428. // History: dd-mmm-yy Author Comment
  1429. // 05-Dec-93 alexgo 32bit port
  1430. //
  1431. // Notes:
  1432. //
  1433. //--------------------------------------------------------------------------
  1434. #pragma SEG(GetHGlobalFromStream)
  1435. STDAPI GetHGlobalFromStream(LPSTREAM pstm, HGLOBAL FAR* phglobal)
  1436. {
  1437. OLETRACEIN((API_GetHGlobalFromStream, PARAMFMT("pstm= %p, phglobal= %p"),
  1438. pstm, phglobal));
  1439. VDATEHEAP();
  1440. HRESULT hresult;
  1441. CMemStm FAR* pCMemStm;
  1442. MEMSTM FAR* pMem;
  1443. VDATEIFACE_LABEL (pstm, errRtn, hresult);
  1444. VDATEPTROUT_LABEL(phglobal, HANDLE, errRtn, hresult);
  1445. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pstm);
  1446. pCMemStm = (CMemStm FAR*) pstm;
  1447. if (!IsValidReadPtrIn (&(pCMemStm->m_dwSig), sizeof(ULONG))
  1448. || pCMemStm->m_dwSig != STREAM_SIG)
  1449. {
  1450. // we were passed someone else's implementation of ILockBytes
  1451. hresult = ResultFromScode (E_INVALIDARG);
  1452. goto errRtn;
  1453. }
  1454. pMem= pCMemStm->m_pData;
  1455. if (NULL==pMem)
  1456. {
  1457. LEERROR(1, "Out of memory!");
  1458. hresult = ResultFromScode (E_OUTOFMEMORY);
  1459. goto errRtn;
  1460. }
  1461. Assert (pMem->cb <= GlobalSize (pMem->hGlobal));
  1462. Verify (*phglobal = pMem->hGlobal);
  1463. hresult = NOERROR;
  1464. errRtn:
  1465. OLETRACEOUT((API_GetHGlobalFromStream, hresult));
  1466. return hresult;
  1467. }
  1468. //////////////////////////////////////////////////////////////////////////
  1469. //
  1470. // Shared memory ILockBytes implementation
  1471. //
  1472. //+-------------------------------------------------------------------------
  1473. //
  1474. // Member: CMemBytes::QueryInterface
  1475. //
  1476. // Synopsis: returns the requested interface pointer
  1477. //
  1478. // Effects: a CMarshalMemBytes will be created if IID_IMarshal is
  1479. // requested
  1480. //
  1481. // Arguments: [iidInterface] -- the requested interface ID
  1482. // [ppvObj] -- where to put the interface pointer
  1483. //
  1484. // Requires:
  1485. //
  1486. // Returns: NOERROR, E_OUTOFMEMORY, E_NOINTERFACE
  1487. //
  1488. // Signals:
  1489. //
  1490. // Modifies:
  1491. //
  1492. // Derivation: ILockBytes
  1493. //
  1494. // Algorithm:
  1495. //
  1496. // History: dd-mmm-yy Author Comment
  1497. // 11-Jan-94 alexgo removed QI for IMarshal so that
  1498. // the standard marshaller will be used.
  1499. // This is to enable correct operation on
  1500. // 32bit platforms.
  1501. // 05-Dec-93 alexgo 32bit port
  1502. //
  1503. // Notes:
  1504. //
  1505. //--------------------------------------------------------------------------
  1506. #pragma SEG(CMemBytes_QueryInterface)
  1507. STDMETHODIMP CMemBytes::QueryInterface(REFIID iidInterface,
  1508. void FAR* FAR* ppvObj)
  1509. {
  1510. VDATEHEAP();
  1511. HRESULT error;
  1512. VDATEPTROUT( ppvObj, LPVOID );
  1513. *ppvObj = NULL;
  1514. VDATEIID( iidInterface );
  1515. if (m_pData != NULL && (IsEqualIID(iidInterface, IID_ILockBytes) ||
  1516. IsEqualIID(iidInterface, IID_IUnknown)))
  1517. {
  1518. InterlockedIncrement ((LPLONG) &m_refs); // A pointer to this object is returned
  1519. *ppvObj = this;
  1520. error = NOERROR;
  1521. }
  1522. else
  1523. {
  1524. *ppvObj = NULL;
  1525. error = ResultFromScode(E_NOINTERFACE);
  1526. }
  1527. return error;
  1528. }
  1529. //+-------------------------------------------------------------------------
  1530. //
  1531. // Member: CMemBytes::AddRef
  1532. //
  1533. // Synopsis: Incrememts the reference count
  1534. //
  1535. // Effects:
  1536. //
  1537. // Arguments: void
  1538. //
  1539. // Requires:
  1540. //
  1541. // Returns: ULONG -- the new reference count
  1542. //
  1543. // Signals:
  1544. //
  1545. // Modifies:
  1546. //
  1547. // Derivation: ILockBytes
  1548. //
  1549. // Algorithm:
  1550. //
  1551. // History: dd-mmm-yy Author Comment
  1552. // 05-Dec-93 alexgo 32bit port
  1553. //
  1554. // Notes:
  1555. //
  1556. //--------------------------------------------------------------------------
  1557. STDMETHODIMP_(ULONG) CMemBytes::AddRef(void)
  1558. {
  1559. VDATEHEAP();
  1560. return InterlockedIncrement ((LPLONG) &m_refs);
  1561. }
  1562. //+-------------------------------------------------------------------------
  1563. //
  1564. // Member: CMemBytes::Release
  1565. //
  1566. // Synopsis: decrements the reference count
  1567. //
  1568. // Effects:
  1569. //
  1570. // Arguments: void
  1571. //
  1572. // Requires:
  1573. //
  1574. // Returns: ULONG -- the new reference count
  1575. //
  1576. // Signals:
  1577. //
  1578. // Modifies:
  1579. //
  1580. // Derivation: ILockBytes
  1581. //
  1582. // Algorithm:
  1583. //
  1584. // History: dd-mmm-yy Author Comment
  1585. // 16-Dec-93 alexgo added GlobalUnlock to match the Global
  1586. // Lock in Create
  1587. // 05-Dec-93 alexgo 32bit port
  1588. //
  1589. // Notes:
  1590. //
  1591. //--------------------------------------------------------------------------
  1592. STDMETHODIMP_(ULONG) CMemBytes::Release(void)
  1593. {
  1594. VDATEHEAP();
  1595. ULONG ulRefs = InterlockedDecrement ((LPLONG) &m_refs);
  1596. if (ulRefs != 0)
  1597. {
  1598. return ulRefs;
  1599. }
  1600. // GlobalUnlock the m_hMem that we GlobalLocke'd in Create
  1601. GlobalUnlock(m_hMem);
  1602. ReleaseMemStm(&m_hMem);
  1603. delete this;
  1604. return 0;
  1605. }
  1606. //+-------------------------------------------------------------------------
  1607. //
  1608. // Member: CMemBytes::ReadAt
  1609. //
  1610. // Synopsis: reads [cb] bytes from starting position [ulOffset]
  1611. //
  1612. // Effects:
  1613. //
  1614. // Arguments: [ulOffset] -- the offset to start reading from
  1615. // [pb] -- where to put the data
  1616. // [cb] -- the number of bytes to read
  1617. // [pcbRead] -- where to put the number of bytes actually
  1618. // read
  1619. //
  1620. // Requires:
  1621. //
  1622. // Returns: HRESULT
  1623. //
  1624. // Signals:
  1625. //
  1626. // Modifies:
  1627. //
  1628. // Derivation: ILockBytes
  1629. //
  1630. // Algorithm: just calls xmemcpy
  1631. //
  1632. // History: dd-mmm-yy Author Comment
  1633. // 05-Dec-93 alexgo 32bit port
  1634. //
  1635. // Notes:
  1636. //
  1637. //--------------------------------------------------------------------------
  1638. #pragma SEG(CMemBytes_ReadAt)
  1639. STDMETHODIMP CMemBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP* pb,
  1640. ULONG cb, ULONG FAR* pcbRead)
  1641. {
  1642. VDATEHEAP();
  1643. HRESULT error = NOERROR;
  1644. ULONG cbRead = cb;
  1645. VDATEPTROUT( pb, char );
  1646. // make sure we don't offset out of the address space!
  1647. AssertSz(ulOffset.HighPart == 0,
  1648. "CMemBytes: offset greater than 2^32");
  1649. if (pcbRead)
  1650. {
  1651. *pcbRead = 0L;
  1652. }
  1653. if (cbRead + ulOffset.LowPart > m_pData->cb)
  1654. {
  1655. if (ulOffset.LowPart > m_pData->cb)
  1656. {
  1657. // the offset overruns the size of the memory
  1658. cbRead = 0;
  1659. }
  1660. else
  1661. {
  1662. // just read what's left
  1663. cbRead = m_pData->cb - ulOffset.LowPart;
  1664. }
  1665. }
  1666. if (cbRead > 0)
  1667. {
  1668. BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
  1669. m_pData->hGlobal);
  1670. if (NULL==pGlobal)
  1671. {
  1672. LEERROR(1, "GlobalLock failed!");
  1673. return ResultFromScode (STG_E_READFAULT);
  1674. }
  1675. _xmemcpy(pb, pGlobal + ulOffset.LowPart, cbRead);
  1676. GlobalUnlock (m_pData->hGlobal);
  1677. }
  1678. if (pcbRead != NULL)
  1679. {
  1680. *pcbRead = cbRead;
  1681. }
  1682. return error;
  1683. }
  1684. //+-------------------------------------------------------------------------
  1685. //
  1686. // Member: CMemBytes::WriteAt
  1687. //
  1688. // Synopsis: writes [cb] bytes at [ulOffset] in the stream
  1689. //
  1690. // Effects:
  1691. //
  1692. // Arguments: [ulOffset] -- the offset at which to start writing
  1693. // [pb] -- the buffer to read from
  1694. // [cb] -- the number of bytes to write
  1695. // [pcbWritten] -- where to put the number of bytes written
  1696. //
  1697. // Requires:
  1698. //
  1699. // Returns: HRESULT
  1700. //
  1701. // Signals:
  1702. //
  1703. // Modifies:
  1704. //
  1705. // Derivation: ILockBytes
  1706. //
  1707. // Algorithm:
  1708. //
  1709. // History: dd-mmm-yy Author Comment
  1710. // 05-Dec-93 alexgo 32bit port
  1711. //
  1712. // Notes:
  1713. //
  1714. //--------------------------------------------------------------------------
  1715. #pragma SEG(CMemBytes_WriteAt)
  1716. STDMETHODIMP CMemBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP* pb,
  1717. ULONG cb, ULONG FAR* pcbWritten)
  1718. {
  1719. VDATEHEAP();
  1720. HRESULT error = NOERROR;
  1721. ULONG cbWritten = cb;
  1722. BYTE HUGEP* pGlobal;
  1723. VDATEPTRIN( pb, char );
  1724. // make sure the offset doesn't go beyond our address space!
  1725. AssertSz(ulOffset.HighPart == 0, "WriteAt, offset greater than 2^32");
  1726. if (pcbWritten)
  1727. {
  1728. *pcbWritten = 0;
  1729. }
  1730. if (cbWritten + ulOffset.LowPart > m_pData->cb)
  1731. {
  1732. ULARGE_INTEGER ularge_integer;
  1733. ULISet32( ularge_integer, ulOffset.LowPart + cbWritten);
  1734. error = SetSize( ularge_integer );
  1735. if (error != NOERROR)
  1736. {
  1737. goto Exit;
  1738. }
  1739. }
  1740. // CMemBytes does not allow zero-sized memory handles
  1741. pGlobal = (BYTE HUGEP *)GlobalLock (m_pData->hGlobal);
  1742. if (NULL==pGlobal)
  1743. {
  1744. LEERROR(1, "GlobalLock failed!");
  1745. return ResultFromScode (STG_E_WRITEFAULT);
  1746. }
  1747. _xmemcpy(pGlobal + ulOffset.LowPart, pb, cbWritten);
  1748. GlobalUnlock (m_pData->hGlobal);
  1749. if (pcbWritten != NULL)
  1750. {
  1751. *pcbWritten = cbWritten;
  1752. }
  1753. Exit:
  1754. return error;
  1755. }
  1756. //+-------------------------------------------------------------------------
  1757. //
  1758. // Member: CMemBytes::Flush
  1759. //
  1760. // Synopsis: Flushes internal state to disk
  1761. // Not needed for memory ILockBytes
  1762. //
  1763. // Effects:
  1764. //
  1765. // Arguments: void
  1766. //
  1767. // Requires:
  1768. //
  1769. // Returns: NOERROR
  1770. //
  1771. // Signals:
  1772. //
  1773. // Modifies:
  1774. //
  1775. // Derivation: ILockBytes
  1776. //
  1777. // Algorithm:
  1778. //
  1779. // History: dd-mmm-yy Author Comment
  1780. // 05-Dec-93 alexgo 32bit port
  1781. //
  1782. // Notes:
  1783. //
  1784. //--------------------------------------------------------------------------
  1785. #pragma SEG(CMemBytes_Flush)
  1786. STDMETHODIMP CMemBytes::Flush(void)
  1787. {
  1788. VDATEHEAP();
  1789. return NOERROR;
  1790. }
  1791. //+-------------------------------------------------------------------------
  1792. //
  1793. // Member: CMemBytes::SetSize
  1794. //
  1795. // Synopsis: Sets the size of the memory buffer
  1796. //
  1797. // Effects:
  1798. //
  1799. // Arguments: [cb] -- the new size
  1800. //
  1801. // Requires:
  1802. //
  1803. // Returns: NOERROR, E_OUTOFMEMORY
  1804. //
  1805. // Signals:
  1806. //
  1807. // Modifies:
  1808. //
  1809. // Derivation: ILockBytes
  1810. //
  1811. // Algorithm:
  1812. //
  1813. // History: dd-mmm-yy Author Comment
  1814. // 05-Dec-93 alexgo 32bit port
  1815. //
  1816. // Notes:
  1817. //
  1818. //--------------------------------------------------------------------------
  1819. #pragma SEG(CMemBytes_SetSize)
  1820. STDMETHODIMP CMemBytes::SetSize(ULARGE_INTEGER cb)
  1821. {
  1822. VDATEHEAP();
  1823. HANDLE hMemNew;
  1824. AssertSz(cb.HighPart == 0,
  1825. "SetSize: trying to set to more than 2^32 bytes");
  1826. if (m_pData->cb == cb.LowPart)
  1827. {
  1828. return NOERROR;
  1829. }
  1830. hMemNew = GlobalReAlloc(m_pData->hGlobal, max (cb.LowPart, 1),
  1831. GMEM_SHARE | GMEM_MOVEABLE);
  1832. if (hMemNew == NULL)
  1833. {
  1834. return ResultFromScode(E_OUTOFMEMORY);
  1835. }
  1836. m_pData->hGlobal = hMemNew;
  1837. m_pData->cb = cb.LowPart;
  1838. return NOERROR;
  1839. }
  1840. //+-------------------------------------------------------------------------
  1841. //
  1842. // Member: CMemBytes::LockRegion
  1843. //
  1844. // Synopsis: Locks a region. Since only we have access to the memory,
  1845. // nothing needs to be done (note that the *app* also may
  1846. // access, but there's not much we can do about that)
  1847. //
  1848. // Effects:
  1849. //
  1850. // Arguments: [libOffset] -- offset to start with
  1851. // [cb] -- the number of bytes in the locked region
  1852. // [dwLockType] -- the type of lock to use
  1853. //
  1854. // Requires:
  1855. //
  1856. // Returns: NOERROR
  1857. //
  1858. // Signals:
  1859. //
  1860. // Modifies:
  1861. //
  1862. // Derivation: ILockBytes
  1863. //
  1864. // Algorithm:
  1865. //
  1866. // History: dd-mmm-yy Author Comment
  1867. // 05-Dec-93 alexgo 32bit port
  1868. //
  1869. // Notes:
  1870. //
  1871. //--------------------------------------------------------------------------
  1872. #pragma SEG(CMemBytes_LockRegion)
  1873. STDMETHODIMP CMemBytes::LockRegion(ULARGE_INTEGER libOffset,
  1874. ULARGE_INTEGER cb, DWORD dwLockType)
  1875. {
  1876. VDATEHEAP();
  1877. return NOERROR;
  1878. }
  1879. //+-------------------------------------------------------------------------
  1880. //
  1881. // Member: CMemBytes::UnlockRegion
  1882. //
  1883. // Synopsis: Unlocks a region; since only we have access to the memory,
  1884. // nothing needs to be done.
  1885. //
  1886. // Effects:
  1887. //
  1888. // Arguments: [libOffset] -- the offset to start with
  1889. // [cb] -- the number of bytes in the region
  1890. // [dwLockType] -- the lock type
  1891. //
  1892. // Requires:
  1893. //
  1894. // Returns: NOERROR
  1895. //
  1896. // Signals:
  1897. //
  1898. // Modifies:
  1899. //
  1900. // Derivation: ILockBytes
  1901. //
  1902. // Algorithm:
  1903. //
  1904. // History: dd-mmm-yy Author Comment
  1905. // 05-Dec-93 alexgo 32bit port
  1906. //
  1907. // Notes:
  1908. //
  1909. //--------------------------------------------------------------------------
  1910. #pragma SEG(CMemBytes_UnlockRegion)
  1911. STDMETHODIMP CMemBytes::UnlockRegion(ULARGE_INTEGER libOffset,
  1912. ULARGE_INTEGER cb, DWORD dwLockType)
  1913. {
  1914. VDATEHEAP();
  1915. return NOERROR;
  1916. }
  1917. //+-------------------------------------------------------------------------
  1918. //
  1919. // Member: CMemBytes::Stat
  1920. //
  1921. // Synopsis: returns status information
  1922. //
  1923. // Effects:
  1924. //
  1925. // Arguments: [pstatstg] -- where to put the status info
  1926. // [statflag] -- status flags (ignored)
  1927. //
  1928. // Requires:
  1929. //
  1930. // Returns: NOERROR, E_INVALIDARG
  1931. //
  1932. // Signals:
  1933. //
  1934. // Modifies:
  1935. //
  1936. // Derivation: ILockBytes
  1937. //
  1938. // Algorithm:
  1939. //
  1940. // History: dd-mmm-yy Author Comment
  1941. // 05-Dec-93 alexgo 32bit port
  1942. // 01-Jun-94 AlexT Set type correctly
  1943. //
  1944. // Notes:
  1945. //
  1946. //--------------------------------------------------------------------------
  1947. #pragma SEG(CMemBytes_Stat)
  1948. STDMETHODIMP CMemBytes::Stat(STATSTG FAR *pstatstg, DWORD statflag)
  1949. {
  1950. VDATEHEAP();
  1951. VDATEPTROUT( pstatstg, STATSTG );
  1952. memset ( pstatstg, 0, sizeof(STATSTG) );
  1953. pstatstg->type = STGTY_LOCKBYTES;
  1954. pstatstg->cbSize.LowPart = m_pData->cb;
  1955. return NOERROR;
  1956. }
  1957. //+-------------------------------------------------------------------------
  1958. //
  1959. // Member: CMemBytes::Create
  1960. //
  1961. // Synopsis: Creates an instance of CMemBytes
  1962. //
  1963. // Effects:
  1964. //
  1965. // Arguments: [hMem] -- handle to the memory (must be a MEMSTM block)
  1966. //
  1967. // Requires:
  1968. //
  1969. // Returns: CMemBytes *
  1970. //
  1971. // Signals:
  1972. //
  1973. // Modifies:
  1974. //
  1975. // Derivation:
  1976. //
  1977. // Algorithm:
  1978. //
  1979. // History: dd-mmm-yy Author Comment
  1980. // 16-Dec-93 alexgo fixed bad pointer bug (took out
  1981. // GlobalUnlock)
  1982. // 05-Dec-93 alexgo 32bit port
  1983. //
  1984. // Notes:
  1985. //
  1986. //--------------------------------------------------------------------------
  1987. #pragma SEG(CMemBytes_Create)
  1988. STDSTATICIMP_(CMemBytes FAR*) CMemBytes::Create(HANDLE hMem)
  1989. {
  1990. VDATEHEAP();
  1991. CMemBytes FAR* pCMemBytes = NULL;
  1992. struct MEMSTM FAR* pData;
  1993. pData = (MEMSTM FAR*) GlobalLock(hMem);
  1994. if (pData != NULL)
  1995. {
  1996. Assert (pData->hGlobal);
  1997. pCMemBytes = new CMemBytes;
  1998. if (pCMemBytes != NULL)
  1999. {
  2000. // Initialize CMemBytes
  2001. pCMemBytes->m_dwSig = LOCKBYTE_SIG;
  2002. pCMemBytes->m_hMem = hMem;
  2003. InterlockedIncrement ((LPLONG) &(pCMemBytes->m_pData = pData)->cRef); // AddRefMemStm
  2004. pCMemBytes->m_refs = 1;
  2005. CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_ILockBytes,
  2006. (IUnknown **)&pCMemBytes);
  2007. }
  2008. else
  2009. {
  2010. // uh-oh, low on memory
  2011. GlobalUnlock(hMem);
  2012. }
  2013. }
  2014. // we don't GlobalUnlock(hMem) until we destory this CMemBytes
  2015. return pCMemBytes;
  2016. }
  2017. //+-------------------------------------------------------------------------
  2018. //
  2019. // Member: CMemBytes::Dump, public (_DEBUG only)
  2020. //
  2021. // Synopsis: return a string containing the contents of the data members
  2022. //
  2023. // Effects:
  2024. //
  2025. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  2026. // [ulFlag] - flag determining prefix of all newlines of the
  2027. // out character array (default is 0 - no prefix)
  2028. // [nIndentLevel] - will add a indent prefix after the other prefix
  2029. // for ALL newlines (including those with no prefix)
  2030. //
  2031. // Requires:
  2032. //
  2033. // Returns: HRESULT
  2034. //
  2035. // Signals:
  2036. //
  2037. // Modifies: [ppsz] - argument
  2038. //
  2039. // Derivation:
  2040. //
  2041. // Algorithm: use dbgstream to create a string containing information on the
  2042. // content of data structures
  2043. //
  2044. // History: dd-mmm-yy Author Comment
  2045. // 20-Jan-95 t-ScottH author
  2046. //
  2047. // Notes:
  2048. //
  2049. //--------------------------------------------------------------------------
  2050. #ifdef _DEBUG
  2051. HRESULT CMemBytes::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  2052. {
  2053. int i;
  2054. char *pszPrefix;
  2055. char *pszMEMSTM;
  2056. dbgstream dstrPrefix;
  2057. dbgstream dstrDump(400);
  2058. // determine prefix of newlines
  2059. if ( ulFlag & DEB_VERBOSE )
  2060. {
  2061. dstrPrefix << this << " _VB ";
  2062. }
  2063. // determine indentation prefix for all newlines
  2064. for (i = 0; i < nIndentLevel; i++)
  2065. {
  2066. dstrPrefix << DUMPTAB;
  2067. }
  2068. pszPrefix = dstrPrefix.str();
  2069. // put data members in stream
  2070. dstrDump << pszPrefix << "Impl. Signature = " << m_dwSig << endl;
  2071. dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
  2072. dstrDump << pszPrefix << "Memory handle = " << m_hMem << endl;
  2073. if (m_pData != NULL)
  2074. {
  2075. pszMEMSTM = DumpMEMSTM(m_pData, ulFlag, nIndentLevel + 1);
  2076. dstrDump << pszPrefix << "MEMSTM:" << endl;
  2077. dstrDump << pszMEMSTM;
  2078. CoTaskMemFree(pszMEMSTM);
  2079. }
  2080. else
  2081. {
  2082. dstrDump << pszPrefix << "MEMSTM = " << m_pData << endl;
  2083. }
  2084. // cleanup and provide pointer to character array
  2085. *ppszDump = dstrDump.str();
  2086. if (*ppszDump == NULL)
  2087. {
  2088. *ppszDump = UtDupStringA(szDumpErrorMessage);
  2089. }
  2090. CoTaskMemFree(pszPrefix);
  2091. return NOERROR;
  2092. }
  2093. #endif // _DEBUG
  2094. //+-------------------------------------------------------------------------
  2095. //
  2096. // Function: DumpCMemBytes, public (_DEBUG only)
  2097. //
  2098. // Synopsis: calls the CMemBytes::Dump method, takes care of errors and
  2099. // returns the zero terminated string
  2100. //
  2101. // Effects:
  2102. //
  2103. // Arguments: [pMB] - pointer to CMemBytes
  2104. // [ulFlag] - flag determining prefix of all newlines of the
  2105. // out character array (default is 0 - no prefix)
  2106. // [nIndentLevel] - will add a indent prefix after the other prefix
  2107. // for ALL newlines (including those with no prefix)
  2108. //
  2109. // Requires:
  2110. //
  2111. // Returns: character array of structure dump or error (null terminated)
  2112. //
  2113. // Signals:
  2114. //
  2115. // Modifies:
  2116. //
  2117. // Algorithm:
  2118. //
  2119. // History: dd-mmm-yy Author Comment
  2120. // 20-Jan-95 t-ScottH author
  2121. //
  2122. // Notes:
  2123. //
  2124. //--------------------------------------------------------------------------
  2125. #ifdef _DEBUG
  2126. char *DumpCMemBytes(CMemBytes *pMB, ULONG ulFlag, int nIndentLevel)
  2127. {
  2128. HRESULT hresult;
  2129. char *pszDump;
  2130. if (pMB == NULL)
  2131. {
  2132. return UtDupStringA(szDumpBadPtr);
  2133. }
  2134. hresult = pMB->Dump(&pszDump, ulFlag, nIndentLevel);
  2135. if (hresult != NOERROR)
  2136. {
  2137. CoTaskMemFree(pszDump);
  2138. return DumpHRESULT(hresult);
  2139. }
  2140. return pszDump;
  2141. }
  2142. #endif // _DEBUG