olestrm.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_OLE_SEG
  12. #pragma code_seg(AFX_OLE_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define new DEBUG_NEW
  19. /////////////////////////////////////////////////////////////////////////////
  20. // COleStreamFile implementation
  21. COleStreamFile::COleStreamFile(LPSTREAM lpStream)
  22. {
  23. m_lpStream = lpStream;
  24. m_strStorageName.Empty();
  25. if (m_lpStream != NULL)
  26. {
  27. USES_CONVERSION;
  28. STATSTG statstg;
  29. if (m_lpStream->Stat(&statstg, 0) == S_OK)
  30. {
  31. if (statstg.pwcsName != NULL)
  32. {
  33. TCHAR szTemp[_MAX_PATH];
  34. AfxFullPath(szTemp, OLE2CT(statstg.pwcsName));
  35. CoTaskMemFree(statstg.pwcsName);
  36. m_strStorageName = szTemp;
  37. }
  38. }
  39. }
  40. }
  41. COleStreamFile::~COleStreamFile()
  42. {
  43. if (m_lpStream != NULL && m_bCloseOnDelete)
  44. {
  45. Close();
  46. ASSERT(m_lpStream == NULL);
  47. }
  48. }
  49. LPSTREAM COleStreamFile::Detach()
  50. {
  51. LPSTREAM lpStream = m_lpStream;
  52. m_lpStream = NULL; // detach and transfer ownership of m_lpStream
  53. return lpStream;
  54. }
  55. void COleStreamFile::Attach(LPSTREAM lpStream)
  56. {
  57. ASSERT(m_lpStream == NULL); // already attached to an LPSTREAM?
  58. ASSERT(lpStream != NULL);
  59. m_lpStream = lpStream;
  60. m_bCloseOnDelete = FALSE;
  61. }
  62. /////////////////////////////////////////////////////////////////////////////
  63. // OLE streams helper
  64. HRESULT AFXAPI _AfxReadFromStream(LPSTREAM pStream, void* lpBuf, UINT nCount, DWORD& nRead)
  65. {
  66. if (nCount == 0)
  67. {
  68. nRead = 0;
  69. return S_OK;
  70. }
  71. ASSERT(AfxIsValidAddress(lpBuf, nCount));
  72. ASSERT(pStream != NULL);
  73. // read from the stream
  74. SCODE sc = pStream->Read(lpBuf, nCount, &nRead);
  75. return ResultFromScode(sc);
  76. }
  77. /////////////////////////////////////////////////////////////////////////////
  78. // OLE CFileException helpers
  79. void AFXAPI _AfxFillOleFileException(CFileException* pError, SCODE sc)
  80. {
  81. ASSERT(pError != NULL);
  82. ASSERT(FAILED(sc));
  83. int cause; // portable CFileException.m_cause
  84. // error codes 255 or less are DOS/Win32 error codes
  85. if (SCODE_SEVERITY(sc) == SEVERITY_ERROR &&
  86. SCODE_FACILITY(sc) == FACILITY_STORAGE &&
  87. SCODE_CODE(sc) < 0x100)
  88. {
  89. ASSERT(SCODE_CODE(sc) != 0);
  90. // throw an exception matching to the DOS error
  91. // (NOTE: only the DOS error part of the SCODE becomes m_lOsError)
  92. cause = CFileException::OsErrorToException(SCODE_CODE(sc));
  93. sc = (SCODE)SCODE_CODE(sc);
  94. }
  95. else
  96. {
  97. // attempt some conversion of storage specific error codes to generic
  98. // CFileException causes...
  99. switch (sc)
  100. {
  101. case STG_E_INUSE:
  102. case STG_E_SHAREREQUIRED:
  103. cause = CFileException::sharingViolation;
  104. break;
  105. case STG_E_NOTCURRENT:
  106. case STG_E_REVERTED:
  107. case STG_E_CANTSAVE:
  108. case STG_E_OLDFORMAT:
  109. case STG_E_OLDDLL:
  110. cause = CFileException::generic;
  111. break;
  112. default:
  113. cause = CFileException::generic;
  114. break;
  115. }
  116. }
  117. // fill in pError
  118. pError->m_cause = cause;
  119. pError->m_lOsError = (LONG)sc;
  120. }
  121. void AFXAPI _AfxThrowOleFileException(SCODE sc)
  122. {
  123. // ignore non-failure codes
  124. if (!FAILED(sc))
  125. return;
  126. // otherwise, construct and exception and throw it
  127. CFileException e;
  128. _AfxFillOleFileException(&e, sc);
  129. AfxThrowFileException(e.m_cause, e.m_lOsError);
  130. }
  131. /////////////////////////////////////////////////////////////////////////////
  132. // COleStreamFile Attributes
  133. BOOL COleStreamFile::GetStatus(CFileStatus& rStatus) const
  134. {
  135. USES_CONVERSION;
  136. ASSERT_VALID(this);
  137. ASSERT(m_lpStream != NULL);
  138. // get status of the stream
  139. STATSTG statstg;
  140. if (m_lpStream->Stat(&statstg, 0) != S_OK)
  141. return FALSE;
  142. // map to CFileStatus struct
  143. rStatus.m_mtime = CTime(statstg.mtime);
  144. rStatus.m_ctime = CTime(statstg.ctime);
  145. rStatus.m_atime = CTime(statstg.atime);
  146. ASSERT(statstg.cbSize.HighPart == 0);
  147. rStatus.m_size = statstg.cbSize.LowPart;
  148. rStatus.m_attribute = 0;
  149. rStatus.m_szFullName[0] = '\0';
  150. if (statstg.pwcsName != NULL)
  151. {
  152. // name was returned -- copy and free it
  153. lstrcpyn(rStatus.m_szFullName, OLE2CT(statstg.pwcsName),
  154. _countof(rStatus.m_szFullName));
  155. CoTaskMemFree(statstg.pwcsName);
  156. }
  157. return TRUE;
  158. }
  159. const CString COleStreamFile::GetStorageName() const
  160. {
  161. ASSERT_VALID(this);
  162. return m_strStorageName;
  163. }
  164. DWORD COleStreamFile::GetPosition() const
  165. {
  166. ASSERT_VALID(this);
  167. ASSERT(m_lpStream != NULL);
  168. ULARGE_INTEGER liPosition;
  169. LARGE_INTEGER liZero; LISet32(liZero, 0);
  170. SCODE sc = m_lpStream->Seek(liZero, STREAM_SEEK_CUR, &liPosition);
  171. if (sc != S_OK)
  172. _AfxThrowOleFileException(sc);
  173. ASSERT(liPosition.HighPart == 0);
  174. return liPosition.LowPart;
  175. }
  176. /////////////////////////////////////////////////////////////////////////////
  177. // COleStreamFile Operations
  178. BOOL COleStreamFile::OpenStream(LPSTORAGE lpStorage, LPCTSTR lpszStreamName,
  179. DWORD nOpenFlags, CFileException* pError)
  180. {
  181. USES_CONVERSION;
  182. ASSERT_VALID(this);
  183. ASSERT(m_lpStream == NULL);
  184. ASSERT(lpStorage != NULL);
  185. ASSERT(AfxIsValidString(lpszStreamName));
  186. ASSERT(pError == NULL ||
  187. AfxIsValidAddress(pError, sizeof(CFileException)));
  188. SCODE sc = lpStorage->OpenStream(T2COLE(lpszStreamName), NULL, nOpenFlags, 0,
  189. &m_lpStream);
  190. if (FAILED(sc) && pError != NULL)
  191. _AfxFillOleFileException(pError, sc);
  192. ASSERT(FAILED(sc) || m_lpStream != NULL);
  193. return !FAILED(sc);
  194. }
  195. BOOL COleStreamFile::CreateStream(LPSTORAGE lpStorage, LPCTSTR lpszStreamName,
  196. DWORD nOpenFlags, CFileException* pError)
  197. {
  198. USES_CONVERSION;
  199. ASSERT_VALID(this);
  200. ASSERT(m_lpStream == NULL);
  201. ASSERT(lpStorage != NULL);
  202. ASSERT(AfxIsValidString(lpszStreamName));
  203. ASSERT(pError == NULL ||
  204. AfxIsValidAddress(pError, sizeof(CFileException)));
  205. STATSTG statstg;
  206. if (lpStorage->Stat(&statstg, 0) == S_OK)
  207. {
  208. if (statstg.pwcsName != NULL)
  209. {
  210. TCHAR szTemp[_MAX_PATH];
  211. AfxFullPath(szTemp, OLE2CT(statstg.pwcsName));
  212. CoTaskMemFree(statstg.pwcsName);
  213. m_strStorageName = szTemp;
  214. }
  215. }
  216. SCODE sc = lpStorage->CreateStream(T2COLE(lpszStreamName), nOpenFlags,
  217. 0, 0, &m_lpStream);
  218. if (FAILED(sc) && pError != NULL)
  219. _AfxFillOleFileException(pError, sc);
  220. ASSERT(FAILED(sc) || m_lpStream != NULL);
  221. return !FAILED(sc);
  222. }
  223. BOOL COleStreamFile::CreateMemoryStream(CFileException* pError)
  224. {
  225. ASSERT_VALID(this);
  226. ASSERT(pError == NULL ||
  227. AfxIsValidAddress(pError, sizeof(CFileException)));
  228. SCODE sc = CreateStreamOnHGlobal(NULL, TRUE, &m_lpStream);
  229. if (FAILED(sc) && pError != NULL)
  230. _AfxFillOleFileException(pError, sc);
  231. ASSERT(FAILED(sc) || m_lpStream != NULL);
  232. return !FAILED(sc);
  233. }
  234. /////////////////////////////////////////////////////////////////////////////
  235. // COleStreamFile Overrides
  236. CFile* COleStreamFile::Duplicate() const
  237. {
  238. ASSERT_VALID(this);
  239. ASSERT(m_lpStream != NULL);
  240. LPSTREAM lpStream;
  241. SCODE sc = m_lpStream->Clone(&lpStream);
  242. if (FAILED(sc))
  243. _AfxThrowOleFileException(sc);
  244. ASSERT(lpStream != NULL);
  245. COleStreamFile* pFile = NULL;
  246. TRY
  247. {
  248. // attempt to create the stream
  249. pFile = new COleStreamFile(lpStream);
  250. pFile->m_bCloseOnDelete = m_bCloseOnDelete;
  251. }
  252. CATCH_ALL(e)
  253. {
  254. // cleanup cloned stream
  255. lpStream->Release();
  256. THROW_LAST();
  257. }
  258. END_CATCH_ALL
  259. ASSERT(pFile != NULL);
  260. return pFile;
  261. }
  262. LONG COleStreamFile::Seek(LONG lOff, UINT nFrom)
  263. {
  264. ASSERT_VALID(this);
  265. ASSERT(m_lpStream != NULL);
  266. ASSERT(STREAM_SEEK_SET == begin);
  267. ASSERT(STREAM_SEEK_CUR == current);
  268. ASSERT(STREAM_SEEK_END == end);
  269. ULARGE_INTEGER liNewPosition;
  270. LARGE_INTEGER liOff;
  271. LISet32(liOff, lOff);
  272. SCODE sc = m_lpStream->Seek(liOff, nFrom, &liNewPosition);
  273. if (sc != S_OK)
  274. _AfxThrowOleFileException(sc);
  275. ASSERT(liNewPosition.HighPart == 0);
  276. return liNewPosition.LowPart;
  277. }
  278. void COleStreamFile::SetLength(DWORD dwNewLen)
  279. {
  280. ASSERT_VALID(this);
  281. ASSERT(m_lpStream != NULL);
  282. ULARGE_INTEGER liNewLen;
  283. ULISet32(liNewLen, dwNewLen);
  284. SCODE sc = m_lpStream->SetSize(liNewLen);
  285. if (sc != S_OK)
  286. _AfxThrowOleFileException(sc);
  287. }
  288. DWORD COleStreamFile::GetLength() const
  289. {
  290. ASSERT_VALID(this);
  291. ASSERT(m_lpStream != NULL);
  292. // get status of the stream
  293. STATSTG statstg;
  294. SCODE sc = m_lpStream->Stat(&statstg, STATFLAG_NONAME);
  295. if (sc != S_OK)
  296. _AfxThrowOleFileException(sc);
  297. // map to CFileStatus struct
  298. ASSERT(statstg.cbSize.HighPart == 0);
  299. return statstg.cbSize.LowPart;
  300. }
  301. UINT COleStreamFile::Read(void* lpBuf, UINT nCount)
  302. {
  303. ASSERT_VALID(this);
  304. ASSERT(m_lpStream != NULL);
  305. DWORD dwBytesRead;
  306. HRESULT hr = _AfxReadFromStream(m_lpStream, lpBuf, nCount, dwBytesRead);
  307. if (hr != S_OK)
  308. _AfxThrowOleFileException(hr);
  309. // always return number of bytes read
  310. return (UINT)dwBytesRead;
  311. }
  312. void COleStreamFile::Write(const void* lpBuf, UINT nCount)
  313. {
  314. ASSERT_VALID(this);
  315. ASSERT(m_lpStream != NULL);
  316. if (nCount == 0)
  317. return;
  318. ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));
  319. // write to the stream
  320. DWORD dwBytesWritten;
  321. SCODE sc = m_lpStream->Write(lpBuf, nCount, &dwBytesWritten);
  322. if (sc != S_OK)
  323. _AfxThrowOleFileException(sc);
  324. // if no error, all bytes should have been written
  325. ASSERT((UINT)dwBytesWritten == nCount);
  326. }
  327. void COleStreamFile::LockRange(DWORD dwPos, DWORD dwCount)
  328. {
  329. ASSERT_VALID(this);
  330. ASSERT(m_lpStream != NULL);
  331. // convert parameters to long integers
  332. ULARGE_INTEGER liPos;
  333. ULISet32(liPos, dwPos);
  334. ULARGE_INTEGER liCount;
  335. ULISet32(liCount, dwCount);
  336. // then lock the region
  337. SCODE sc = m_lpStream->LockRegion(liPos, liCount, LOCK_EXCLUSIVE);
  338. if (sc != S_OK)
  339. _AfxThrowOleFileException(sc);
  340. }
  341. void COleStreamFile::UnlockRange(DWORD dwPos, DWORD dwCount)
  342. {
  343. ASSERT_VALID(this);
  344. ASSERT(m_lpStream != NULL);
  345. // convert parameters to long integers
  346. ULARGE_INTEGER liPos;
  347. ULISet32(liPos, dwPos);
  348. ULARGE_INTEGER liCount;
  349. ULISet32(liCount, dwCount);
  350. // then lock the region
  351. SCODE sc = m_lpStream->UnlockRegion(liPos, liCount, LOCK_EXCLUSIVE);
  352. if (sc != S_OK)
  353. _AfxThrowOleFileException(sc);
  354. }
  355. void COleStreamFile::Abort()
  356. {
  357. ASSERT_VALID(this);
  358. if (m_lpStream != NULL)
  359. {
  360. m_lpStream->Revert();
  361. RELEASE(m_lpStream);
  362. }
  363. m_strStorageName.Empty();
  364. }
  365. void COleStreamFile::Flush()
  366. {
  367. ASSERT_VALID(this);
  368. ASSERT(m_lpStream != NULL);
  369. // commit will return an error only if the stream is transacted
  370. SCODE sc = m_lpStream->Commit(0);
  371. if (sc != S_OK)
  372. _AfxThrowOleFileException(sc);
  373. }
  374. void COleStreamFile::Close()
  375. {
  376. ASSERT_VALID(this);
  377. if (m_lpStream != NULL)
  378. {
  379. // commit the stream via Flush (which can be overriden)
  380. Flush();
  381. RELEASE(m_lpStream);
  382. }
  383. m_strStorageName.Empty();
  384. }
  385. IStream* COleStreamFile::GetStream() const
  386. {
  387. return m_lpStream;
  388. }
  389. /////////////////////////////////////////////////////////////////////////////
  390. // COleStreamFile diagnostics
  391. #ifdef _DEBUG
  392. void COleStreamFile::AssertValid() const
  393. {
  394. CFile::AssertValid();
  395. }
  396. void COleStreamFile::Dump(CDumpContext& dc) const
  397. {
  398. CFile::Dump(dc);
  399. dc << "m_lpStream = " << m_lpStream;
  400. dc << "m_strStorageName = \"" << m_strStorageName;
  401. dc << "\"\n";
  402. }
  403. #endif
  404. ////////////////////////////////////////////////////////////////////////////
  405. #ifdef AFX_INIT_SEG
  406. #pragma code_seg(AFX_INIT_SEG)
  407. #endif
  408. IMPLEMENT_DYNAMIC(COleStreamFile, CFile)
  409. ////////////////////////////////////////////////////////////////////////////