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.

837 lines
19 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. pchstm.h
  5. Abstract:
  6. This file contains the implementations of various stream objects
  7. Revision History:
  8. created derekm 01/19/00
  9. ******************************************************************************/
  10. #include "stdafx.h"
  11. #include "pfstm.h"
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CPFStreamFile- construct / destruct
  14. // **************************************************************************
  15. CPFStreamFile::CPFStreamFile(void)
  16. {
  17. m_hFile = INVALID_HANDLE_VALUE;
  18. m_dwAccess = 0;
  19. }
  20. // **************************************************************************
  21. CPFStreamFile::~CPFStreamFile(void)
  22. {
  23. this->Close();
  24. }
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CPFStreamFile- non interface
  27. // **************************************************************************
  28. HRESULT CPFStreamFile::Open(LPCWSTR szFile, DWORD dwAccess,
  29. DWORD dwDisposition, DWORD dwSharing)
  30. {
  31. USE_TRACING("CPFStreamFile::Open(szFile)");
  32. HRESULT hr = NOERROR;
  33. HANDLE hFile = INVALID_HANDLE_VALUE;
  34. VALIDATEPARM(hr, (szFile == NULL));
  35. if (FAILED(hr))
  36. goto done;
  37. hFile = ::CreateFileW(szFile, dwAccess, dwSharing, NULL, dwDisposition,
  38. FILE_ATTRIBUTE_NORMAL, NULL);
  39. TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE))
  40. if (FAILED(hr))
  41. goto done;
  42. this->Close();
  43. m_hFile = hFile;
  44. m_dwAccess = dwAccess;
  45. hFile = INVALID_HANDLE_VALUE;
  46. done:
  47. if (hFile != INVALID_HANDLE_VALUE)
  48. CloseHandle(hFile);
  49. return hr;
  50. }
  51. // **************************************************************************
  52. HRESULT CPFStreamFile::Open(HANDLE hFile, DWORD dwAccess)
  53. {
  54. USE_TRACING("CPFStreamFile::Open(hFile)");
  55. HRESULT hr = NOERROR;
  56. HANDLE hFileNew = INVALID_HANDLE_VALUE;
  57. VALIDATEPARM(hr, (hFile == INVALID_HANDLE_VALUE || hFile == NULL));
  58. if (FAILED(hr))
  59. goto done;
  60. TESTBOOL(hr, DuplicateHandle(GetCurrentProcess(), hFile,
  61. GetCurrentProcess(), &hFileNew, dwAccess,
  62. FALSE, 0));
  63. if (FAILED(hr))
  64. goto done;
  65. this->Close();
  66. m_hFile = hFileNew;
  67. m_dwAccess = dwAccess;
  68. hFileNew = INVALID_HANDLE_VALUE;
  69. done:
  70. if (hFileNew != INVALID_HANDLE_VALUE)
  71. CloseHandle(hFileNew);
  72. return hr;
  73. }
  74. // **************************************************************************
  75. HRESULT CPFStreamFile::Close(void)
  76. {
  77. USE_TRACING("CPFStreamFile::Close");
  78. if (m_hFile != INVALID_HANDLE_VALUE)
  79. {
  80. CloseHandle(m_hFile);
  81. m_hFile = INVALID_HANDLE_VALUE;
  82. }
  83. return NOERROR;
  84. }
  85. /////////////////////////////////////////////////////////////////////////////
  86. // CPFStreamFile- ISequentialStream
  87. // **************************************************************************
  88. STDMETHODIMP CPFStreamFile::Read(void *pv, ULONG cb, ULONG *pcbRead)
  89. {
  90. USE_TRACING("CPFStreamFile::Read");
  91. HRESULT hr = NOERROR;
  92. DWORD cbRead;
  93. if (pv == NULL || m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
  94. {
  95. hr = STG_E_INVALIDPOINTER;
  96. goto done;
  97. }
  98. if (pcbRead != NULL)
  99. *pcbRead = 0;
  100. if (ReadFile(m_hFile, pv, cb, &cbRead, NULL) == FALSE)
  101. {
  102. if (GetLastError() == ERROR_ACCESS_DENIED)
  103. hr = STG_E_ACCESSDENIED;
  104. else
  105. hr = S_FALSE;
  106. goto done;
  107. }
  108. if (cbRead == 0 && cb != 0)
  109. {
  110. hr = S_FALSE;
  111. goto done;
  112. }
  113. if (pcbRead != NULL)
  114. *pcbRead = cbRead;
  115. done:
  116. return hr;
  117. }
  118. // **************************************************************************
  119. STDMETHODIMP CPFStreamFile::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
  120. {
  121. USE_TRACING("CPFStreamFile::Write");
  122. HRESULT hr = NOERROR;
  123. DWORD cbWritten;
  124. if (pv == NULL || m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
  125. {
  126. hr = STG_E_INVALIDPOINTER;
  127. goto done;
  128. }
  129. if ((m_dwAccess & GENERIC_WRITE) == 0)
  130. {
  131. hr = STG_E_WRITEFAULT;
  132. goto done;
  133. }
  134. if (pcbWritten != NULL)
  135. *pcbWritten = 0;
  136. if (WriteFile(m_hFile, pv, cb, &cbWritten, NULL) == FALSE)
  137. {
  138. switch(GetLastError())
  139. {
  140. case ERROR_DISK_FULL:
  141. hr = STG_E_MEDIUMFULL;
  142. break;
  143. case ERROR_ACCESS_DENIED:
  144. hr = STG_E_ACCESSDENIED;
  145. break;
  146. default:
  147. hr = STG_E_CANTSAVE;
  148. }
  149. goto done;
  150. }
  151. if (pcbWritten != NULL)
  152. *pcbWritten = cbWritten;
  153. done:
  154. return hr;
  155. }
  156. /////////////////////////////////////////////////////////////////////////////
  157. // CPFStreamFile- IStream
  158. // **************************************************************************
  159. STDMETHODIMP CPFStreamFile::Seek(LARGE_INTEGER libMove, DWORD dwOrigin,
  160. ULARGE_INTEGER *plibNewPosition)
  161. {
  162. USE_TRACING("CPFStreamFile::Seek");
  163. HRESULT hr = NOERROR;
  164. LONG dwHigh, dwLow;
  165. if (m_hFile == INVALID_HANDLE_VALUE || m_hFile == NULL)
  166. {
  167. hr = STG_E_INVALIDPOINTER;
  168. goto done;
  169. }
  170. if (plibNewPosition != NULL)
  171. {
  172. plibNewPosition->HighPart = 0;
  173. plibNewPosition->LowPart = 0;
  174. }
  175. switch(dwOrigin)
  176. {
  177. default:
  178. case STREAM_SEEK_CUR:
  179. dwOrigin = FILE_CURRENT;
  180. break;
  181. case STREAM_SEEK_SET:
  182. dwOrigin = FILE_BEGIN;
  183. break;
  184. case STREAM_SEEK_END:
  185. dwOrigin = FILE_END;
  186. break;
  187. }
  188. TESTBOOL(hr, SetFilePointerEx(m_hFile, libMove,
  189. (LARGE_INTEGER *)plibNewPosition, dwOrigin));
  190. if (FAILED(hr))
  191. {
  192. hr = STG_E_INVALIDFUNCTION;
  193. goto done;
  194. }
  195. done:
  196. return hr;
  197. }
  198. // **************************************************************************
  199. STDMETHODIMP CPFStreamFile::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  200. {
  201. USE_TRACING("CPFStreamFile::Seek");
  202. BY_HANDLE_FILE_INFORMATION fi;
  203. HRESULT hr = NOERROR;
  204. if (pstatstg == NULL || m_hFile == INVALID_HANDLE_VALUE ||
  205. m_hFile == NULL)
  206. {
  207. hr = STG_E_INVALIDPOINTER;
  208. goto done;
  209. }
  210. if (GetFileInformationByHandle(m_hFile, &fi) == FALSE)
  211. {
  212. hr = STG_E_ACCESSDENIED;
  213. goto done;
  214. }
  215. pstatstg->pwcsName = NULL;
  216. pstatstg->type = STGTY_STREAM;
  217. pstatstg->cbSize.HighPart = fi.nFileSizeHigh;
  218. pstatstg->cbSize.LowPart = fi.nFileSizeLow;
  219. pstatstg->mtime = fi.ftCreationTime;
  220. pstatstg->ctime = fi.ftLastAccessTime;
  221. pstatstg->atime = fi.ftLastWriteTime;
  222. pstatstg->clsid = CLSID_NULL;
  223. pstatstg->grfMode = 0;
  224. pstatstg->grfLocksSupported = 0;
  225. pstatstg->grfStateBits = 0;
  226. pstatstg->reserved = 0;
  227. done:
  228. return hr;
  229. }
  230. // **************************************************************************
  231. STDMETHODIMP CPFStreamFile::Clone(IStream **ppstm)
  232. {
  233. USE_TRACING("CPFStreamFile::Clone");
  234. CPFStreamFile *pstm = NULL;
  235. HRESULT hr = NOERROR;
  236. if (ppstm == NULL)
  237. {
  238. hr = STG_E_INVALIDPOINTER;
  239. goto done;
  240. }
  241. // Create a new stream object.
  242. pstm = CPFStreamFile::CreateInstance();
  243. if (pstm == NULL)
  244. {
  245. hr = STG_E_INSUFFICIENTMEMORY;
  246. goto done;
  247. }
  248. pstm->AddRef();
  249. // intialize it
  250. hr = pstm->Open(m_hFile, m_dwAccess);
  251. if (FAILED(hr))
  252. {
  253. hr = STG_E_INVALIDPOINTER;
  254. goto done;
  255. }
  256. // need to hand back the IStream interface, so...
  257. hr = pstm->QueryInterface(IID_IStream, (LPVOID *)ppstm);
  258. _ASSERT(SUCCEEDED(hr));
  259. pstm = NULL;
  260. done:
  261. if (pstm != NULL)
  262. pstm->Release();
  263. return hr;
  264. }
  265. /////////////////////////////////////////////////////////////////////////////
  266. // CPFStreamMem- construct / destruct
  267. // **************************************************************************
  268. CPFStreamMem::CPFStreamMem(void)
  269. {
  270. m_pvData = NULL;
  271. m_pvPtr = NULL;
  272. m_cb = 0;
  273. m_cbRead = 0;
  274. m_cbGrow = 0;
  275. }
  276. // **************************************************************************
  277. CPFStreamMem::~CPFStreamMem(void)
  278. {
  279. this->Clean();
  280. }
  281. /////////////////////////////////////////////////////////////////////////////
  282. // CPFStreamMem- non interface
  283. // **************************************************************************
  284. HRESULT CPFStreamMem::Init(DWORD cbStart, DWORD cbGrowBy)
  285. {
  286. USE_TRACING("CPFStreamMem::Init");
  287. HRESULT hr = NOERROR;
  288. LPVOID pvNew = NULL;
  289. // if the user passes us -1 for either of these, he means 'use default',
  290. // which is the system page size...
  291. if (cbStart == (DWORD)-1 || cbGrowBy == (DWORD)-1)
  292. {
  293. SYSTEM_INFO si;
  294. ZeroMemory(&si, sizeof(si));
  295. GetSystemInfo(&si);
  296. if (cbStart == (DWORD)-1)
  297. cbStart = si.dwPageSize;
  298. if (cbGrowBy == (DWORD)-1)
  299. cbGrowBy = si.dwPageSize;
  300. }
  301. if (cbStart > 0)
  302. {
  303. pvNew = MyAlloc(cbStart);
  304. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  305. if (FAILED(hr))
  306. goto done;
  307. }
  308. this->Clean();
  309. m_pvData = pvNew;
  310. m_pvPtr = pvNew;
  311. m_cb = cbStart;
  312. m_cbWrite = 0;
  313. m_cbGrow = cbGrowBy;
  314. pvNew = NULL;
  315. done:
  316. if (pvNew != NULL)
  317. MyFree(pvNew);
  318. return hr;
  319. }
  320. // **************************************************************************
  321. HRESULT CPFStreamMem::InitBinBlob(LPVOID pv, DWORD cb, DWORD cbGrow)
  322. {
  323. USE_TRACING("CPFStreamMem::InitBinBlob");
  324. HRESULT hr = NOERROR;
  325. LPVOID pvNew = NULL;
  326. VALIDATEPARM(hr, (pv == NULL));
  327. if (FAILED(hr))
  328. goto done;
  329. if (cb == 0)
  330. goto done;
  331. pvNew = MyAlloc(cb);
  332. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  333. if (FAILED(hr))
  334. goto done;
  335. CopyMemory(pvNew, pv, cb);
  336. this->Clean();
  337. m_pvData = pvNew;
  338. m_pvPtr = pvNew;
  339. m_cb = cb;
  340. m_cbWrite = cb;
  341. m_cbGrow = cbGrow;
  342. pvNew = NULL;
  343. done:
  344. if (pvNew != NULL)
  345. MyFree(pvNew);
  346. return hr;
  347. }
  348. // **************************************************************************
  349. HRESULT CPFStreamMem::InitTextBlob(LPCWSTR wsz, DWORD cch, BOOL fConvertToANSI)
  350. {
  351. USE_TRACING("CPFStreamMem::InitTextBlob(LPCWSTR)");
  352. HRESULT hr = NOERROR;
  353. LPVOID pvNew = NULL;
  354. DWORD cb;
  355. VALIDATEPARM(hr, (wsz == NULL));
  356. if (FAILED(hr))
  357. goto done;
  358. if (cch == 0)
  359. goto done;
  360. if (fConvertToANSI)
  361. {
  362. cb = WideCharToMultiByte(CP_ACP, 0, wsz, -1, NULL, 0, NULL, NULL);
  363. TESTBOOL(hr, (cb != 0));
  364. if (FAILED(hr))
  365. goto done;
  366. pvNew = MyAlloc(cb);
  367. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  368. if (FAILED(hr))
  369. goto done;
  370. if (WideCharToMultiByte(CP_ACP, 0, wsz, -1, (LPSTR)pvNew, cb, NULL,
  371. NULL) == 0)
  372. TESTBOOL(hr, (cb != 0));
  373. if (FAILED(hr))
  374. goto done;
  375. }
  376. else
  377. {
  378. // assume cch does NOT include the NULL terminator, so gotta add 1
  379. cb = (cch + 1) * sizeof(WCHAR);
  380. pvNew = MyAlloc(cb);
  381. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  382. if (FAILED(hr))
  383. goto done;
  384. CopyMemory(pvNew, wsz, cb);
  385. }
  386. this->Clean();
  387. m_pvData = pvNew;
  388. m_pvPtr = pvNew;
  389. m_cb = cb;
  390. m_cbWrite = cb;
  391. m_cbGrow = 0;
  392. pvNew = NULL;
  393. done:
  394. if (pvNew != NULL)
  395. MyFree(pvNew);
  396. return hr;
  397. }
  398. // **************************************************************************
  399. HRESULT CPFStreamMem::InitTextBlob(LPCSTR sz, DWORD cch, BOOL fConvertToWCHAR)
  400. {
  401. USE_TRACING("CPFStreamMem::InitTextBlob(LPCSTR)");
  402. HRESULT hr = NOERROR;
  403. LPVOID pvNew = NULL;
  404. DWORD cb;
  405. VALIDATEPARM(hr, (sz == NULL));
  406. if (FAILED(hr))
  407. goto done;
  408. if (cch == 0)
  409. goto done;
  410. if (fConvertToWCHAR)
  411. {
  412. cb = MultiByteToWideChar(CP_ACP, 0, sz, -1, NULL, 0);
  413. TESTBOOL(hr, (cb != 0));
  414. if (FAILED(hr))
  415. goto done;
  416. pvNew = MyAlloc(cb);
  417. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  418. if (FAILED(hr))
  419. goto done;
  420. cb = MultiByteToWideChar(CP_ACP, 0, sz, -1, (LPWSTR)pvNew, cb);
  421. TESTBOOL(hr, (cb != 0));
  422. if (FAILED(hr))
  423. goto done;
  424. }
  425. else
  426. {
  427. // assume cch does NOT include the NULL terminator, so gotta add 1
  428. cb = cch + 1;
  429. pvNew = MyAlloc(cb);
  430. VALIDATEEXPR(hr, (pvNew == NULL), E_OUTOFMEMORY);
  431. if (FAILED(hr))
  432. goto done;
  433. CopyMemory(pvNew, sz, cb);
  434. }
  435. this->Clean();
  436. m_pvData = pvNew;
  437. m_pvPtr = pvNew;
  438. m_cb = cb;
  439. m_cbWrite = cb;
  440. m_cbGrow = 0;
  441. pvNew = NULL;
  442. done:
  443. if (pvNew != NULL)
  444. MyFree(pvNew);
  445. return hr;
  446. }
  447. // **************************************************************************
  448. HRESULT CPFStreamMem::Clean(void)
  449. {
  450. USE_TRACING("CPFStreamMem::Clean");
  451. if (m_pvData != NULL)
  452. {
  453. MyFree(m_pvData);
  454. m_pvData = NULL;
  455. m_pvPtr = NULL;
  456. m_cb = 0;
  457. m_cbRead = 0;
  458. m_cbWrite = 0;
  459. m_cbGrow = 0;
  460. }
  461. return NOERROR;
  462. }
  463. /////////////////////////////////////////////////////////////////////////////
  464. // CPFStreamMem- ISequentialStream
  465. // **************************************************************************
  466. STDMETHODIMP CPFStreamMem::Read(void *pv, ULONG cb, ULONG *pcbRead)
  467. {
  468. USE_TRACING("CPFStreamMem::Read");
  469. HRESULT hr = NOERROR;
  470. DWORD cbRead;
  471. if (pv == NULL || m_pvPtr == NULL)
  472. {
  473. hr = STG_E_INVALIDPOINTER;
  474. goto done;
  475. }
  476. if (pcbRead != NULL)
  477. *pcbRead = 0;
  478. if (m_cbRead >= m_cbWrite)
  479. {
  480. hr = S_FALSE;
  481. goto done;
  482. }
  483. if (m_cbRead + cb > m_cbWrite)
  484. cbRead = m_cbWrite - m_cbRead;
  485. else
  486. cbRead = cb;
  487. CopyMemory(pv, m_pvPtr, cbRead);
  488. m_pvPtr = (LPVOID)((BYTE *)m_pvPtr + cbRead);
  489. m_cbRead += cbRead;
  490. if (pcbRead != NULL)
  491. *pcbRead = cbRead;
  492. done:
  493. return hr;
  494. }
  495. // **************************************************************************
  496. STDMETHODIMP CPFStreamMem::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
  497. {
  498. USE_TRACING("CPFStreamMem::Write");
  499. HRESULT hr = NOERROR;
  500. if (pv == NULL)
  501. {
  502. hr = STG_E_INVALIDPOINTER;
  503. goto done;
  504. }
  505. if (pcbWritten != NULL)
  506. *pcbWritten = 0;
  507. if (m_cbRead + cb > m_cb)
  508. {
  509. if (m_cbGrow > 0)
  510. {
  511. LPVOID pvNew = NULL, pvPtr;
  512. DWORD cbNew;
  513. cbNew = MyMax(m_cb + m_cbGrow, m_cbRead + cb);
  514. if (m_pvData == NULL)
  515. {
  516. pvNew = MyAlloc(cbNew);
  517. pvPtr = pvNew;
  518. }
  519. else
  520. {
  521. pvNew = MyReAlloc(m_pvData, cbNew);
  522. pvPtr = (LPVOID)((BYTE *)m_pvPtr + m_cbRead);
  523. }
  524. VALIDATEEXPR(hr, (pvNew == NULL), STG_E_MEDIUMFULL);
  525. if (FAILED(hr))
  526. goto done;
  527. m_pvData = pvNew;
  528. m_pvPtr = pvPtr;
  529. }
  530. else
  531. {
  532. hr = STG_E_MEDIUMFULL;
  533. goto done;
  534. }
  535. }
  536. CopyMemory(m_pvPtr, pv, cb);
  537. m_pvPtr = (LPVOID)((BYTE *)m_pvPtr + cb);
  538. m_cbRead += cb;
  539. if (m_cbRead > m_cbWrite)
  540. m_cbWrite = m_cbRead;
  541. if (pcbWritten != NULL)
  542. *pcbWritten = cb;
  543. done:
  544. return hr;
  545. }
  546. /////////////////////////////////////////////////////////////////////////////
  547. // CPFStreamFile- IStream
  548. // **************************************************************************
  549. STDMETHODIMP CPFStreamMem::Seek(LARGE_INTEGER libMove, DWORD dwOrigin,
  550. ULARGE_INTEGER *plibNewPosition)
  551. {
  552. USE_TRACING("CPFStreamMem::Seek");
  553. HRESULT hr = NOERROR;
  554. LPVOID pvNew;
  555. DWORD cbNew;
  556. if (m_pvPtr == NULL)
  557. {
  558. hr = STG_E_INVALIDPOINTER;
  559. goto done;
  560. }
  561. if (plibNewPosition != NULL)
  562. {
  563. plibNewPosition->HighPart = 0;
  564. plibNewPosition->LowPart = 0;
  565. }
  566. if (libMove.HighPart != 0 && libMove.HighPart != (DWORD)-1)
  567. {
  568. hr = STG_E_INVALIDFUNCTION;
  569. goto done;
  570. }
  571. switch(dwOrigin)
  572. {
  573. default:
  574. case STREAM_SEEK_CUR:
  575. pvNew = (LPVOID)((BYTE *)m_pvPtr + libMove.LowPart);
  576. cbNew = m_cbRead + libMove.LowPart;
  577. break;
  578. case STREAM_SEEK_SET:
  579. pvNew = (LPVOID)((BYTE *)m_pvData + libMove.LowPart);
  580. cbNew = libMove.LowPart;
  581. break;
  582. case STREAM_SEEK_END:
  583. pvNew = (LPVOID)(((BYTE *)m_pvData + m_cbWrite) - libMove.LowPart);
  584. cbNew = m_cbWrite - libMove.LowPart;
  585. break;
  586. }
  587. if (pvNew < m_pvData || cbNew > m_cbWrite)
  588. {
  589. hr = STG_E_INVALIDFUNCTION;
  590. goto done;
  591. }
  592. m_pvPtr = pvNew;
  593. m_cbRead = cbNew;
  594. if (plibNewPosition != NULL)
  595. plibNewPosition->LowPart = cbNew;
  596. done:
  597. return hr;
  598. }
  599. // **************************************************************************
  600. STDMETHODIMP CPFStreamMem::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  601. {
  602. USE_TRACING("CPFStreamMem::Stat");
  603. HRESULT hr = NOERROR;
  604. if (pstatstg == NULL || m_pvData == NULL)
  605. {
  606. hr = STG_E_INVALIDPOINTER;
  607. goto done;
  608. }
  609. ZeroMemory(pstatstg, sizeof(STATSTG));
  610. pstatstg->type = STGTY_STREAM;
  611. pstatstg->cbSize.LowPart = m_cbWrite;
  612. done:
  613. return hr;
  614. }
  615. // **************************************************************************
  616. STDMETHODIMP CPFStreamMem::Clone(IStream **ppstm)
  617. {
  618. USE_TRACING("CPFStreamMem::Clone");
  619. CPFStreamMem *pstm = NULL;
  620. HRESULT hr;
  621. if (ppstm == NULL)
  622. {
  623. hr = STG_E_INVALIDPOINTER;
  624. goto done;
  625. }
  626. // Create a new stream object.
  627. pstm = CPFStreamMem::CreateInstance();
  628. if (pstm == NULL)
  629. {
  630. hr = STG_E_INSUFFICIENTMEMORY;
  631. goto done;
  632. }
  633. pstm->AddRef();
  634. // intialize it
  635. hr = pstm->InitBinBlob(m_pvData, m_cbWrite);
  636. if (FAILED(hr))
  637. {
  638. hr = STG_E_INVALIDPOINTER;
  639. goto done;
  640. }
  641. // need to hand back the IStream interface, so...
  642. hr = pstm->QueryInterface(IID_IStream, (LPVOID *)ppstm);
  643. _ASSERT(SUCCEEDED(hr));
  644. pstm = NULL;
  645. done:
  646. if (pstm != NULL)
  647. pstm->Release();
  648. return hr;
  649. }