home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / olestrm.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  12KB  |  511 lines

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