// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFX_OLE_SEG #pragma code_seg(AFX_OLE_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// // COleStreamFile implementation COleStreamFile::COleStreamFile(LPSTREAM lpStream) { m_lpStream = lpStream; m_strStorageName.Empty(); if (m_lpStream != NULL) { USES_CONVERSION; STATSTG statstg; if (m_lpStream->Stat(&statstg, 0) == S_OK) { if (statstg.pwcsName != NULL) { TCHAR szTemp[_MAX_PATH]; AfxFullPath(szTemp, OLE2CT(statstg.pwcsName)); CoTaskMemFree(statstg.pwcsName); m_strStorageName = szTemp; } } } } COleStreamFile::~COleStreamFile() { if (m_lpStream != NULL && m_bCloseOnDelete) { Close(); ASSERT(m_lpStream == NULL); } } LPSTREAM COleStreamFile::Detach() { LPSTREAM lpStream = m_lpStream; m_lpStream = NULL; // detach and transfer ownership of m_lpStream return lpStream; } void COleStreamFile::Attach(LPSTREAM lpStream) { ASSERT(m_lpStream == NULL); // already attached to an LPSTREAM? ASSERT(lpStream != NULL); m_lpStream = lpStream; m_bCloseOnDelete = FALSE; } ///////////////////////////////////////////////////////////////////////////// // OLE streams helper HRESULT AFXAPI _AfxReadFromStream(LPSTREAM pStream, void* lpBuf, UINT nCount, DWORD& nRead) { if (nCount == 0) { nRead = 0; return S_OK; } ASSERT(AfxIsValidAddress(lpBuf, nCount)); ASSERT(pStream != NULL); // read from the stream SCODE sc = pStream->Read(lpBuf, nCount, &nRead); return ResultFromScode(sc); } ///////////////////////////////////////////////////////////////////////////// // OLE CFileException helpers void AFXAPI _AfxFillOleFileException(CFileException* pError, SCODE sc) { ASSERT(pError != NULL); ASSERT(FAILED(sc)); int cause; // portable CFileException.m_cause // error codes 255 or less are DOS/Win32 error codes if (SCODE_SEVERITY(sc) == SEVERITY_ERROR && SCODE_FACILITY(sc) == FACILITY_STORAGE && SCODE_CODE(sc) < 0x100) { ASSERT(SCODE_CODE(sc) != 0); // throw an exception matching to the DOS error // (NOTE: only the DOS error part of the SCODE becomes m_lOsError) cause = CFileException::OsErrorToException(SCODE_CODE(sc)); sc = (SCODE)SCODE_CODE(sc); } else { // attempt some conversion of storage specific error codes to generic // CFileException causes... switch (sc) { case STG_E_INUSE: case STG_E_SHAREREQUIRED: cause = CFileException::sharingViolation; break; case STG_E_NOTCURRENT: case STG_E_REVERTED: case STG_E_CANTSAVE: case STG_E_OLDFORMAT: case STG_E_OLDDLL: cause = CFileException::generic; break; default: cause = CFileException::generic; break; } } // fill in pError pError->m_cause = cause; pError->m_lOsError = (LONG)sc; } void AFXAPI _AfxThrowOleFileException(SCODE sc) { // ignore non-failure codes if (!FAILED(sc)) return; // otherwise, construct and exception and throw it CFileException e; _AfxFillOleFileException(&e, sc); AfxThrowFileException(e.m_cause, e.m_lOsError); } ///////////////////////////////////////////////////////////////////////////// // COleStreamFile Attributes BOOL COleStreamFile::GetStatus(CFileStatus& rStatus) const { USES_CONVERSION; ASSERT_VALID(this); ASSERT(m_lpStream != NULL); // get status of the stream STATSTG statstg; if (m_lpStream->Stat(&statstg, 0) != S_OK) return FALSE; // map to CFileStatus struct rStatus.m_mtime = CTime(statstg.mtime); rStatus.m_ctime = CTime(statstg.ctime); rStatus.m_atime = CTime(statstg.atime); ASSERT(statstg.cbSize.HighPart == 0); rStatus.m_size = statstg.cbSize.LowPart; rStatus.m_attribute = 0; rStatus.m_szFullName[0] = '\0'; if (statstg.pwcsName != NULL) { // name was returned -- copy and free it lstrcpyn(rStatus.m_szFullName, OLE2CT(statstg.pwcsName), _countof(rStatus.m_szFullName)); CoTaskMemFree(statstg.pwcsName); } return TRUE; } const CString COleStreamFile::GetStorageName() const { ASSERT_VALID(this); return m_strStorageName; } DWORD COleStreamFile::GetPosition() const { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); ULARGE_INTEGER liPosition; LARGE_INTEGER liZero; LISet32(liZero, 0); SCODE sc = m_lpStream->Seek(liZero, STREAM_SEEK_CUR, &liPosition); if (sc != S_OK) _AfxThrowOleFileException(sc); ASSERT(liPosition.HighPart == 0); return liPosition.LowPart; } ///////////////////////////////////////////////////////////////////////////// // COleStreamFile Operations BOOL COleStreamFile::OpenStream(LPSTORAGE lpStorage, LPCTSTR lpszStreamName, DWORD nOpenFlags, CFileException* pError) { USES_CONVERSION; ASSERT_VALID(this); ASSERT(m_lpStream == NULL); ASSERT(lpStorage != NULL); ASSERT(AfxIsValidString(lpszStreamName)); ASSERT(pError == NULL || AfxIsValidAddress(pError, sizeof(CFileException))); SCODE sc = lpStorage->OpenStream(T2COLE(lpszStreamName), NULL, nOpenFlags, 0, &m_lpStream); if (FAILED(sc) && pError != NULL) _AfxFillOleFileException(pError, sc); ASSERT(FAILED(sc) || m_lpStream != NULL); return !FAILED(sc); } BOOL COleStreamFile::CreateStream(LPSTORAGE lpStorage, LPCTSTR lpszStreamName, DWORD nOpenFlags, CFileException* pError) { USES_CONVERSION; ASSERT_VALID(this); ASSERT(m_lpStream == NULL); ASSERT(lpStorage != NULL); ASSERT(AfxIsValidString(lpszStreamName)); ASSERT(pError == NULL || AfxIsValidAddress(pError, sizeof(CFileException))); STATSTG statstg; if (lpStorage->Stat(&statstg, 0) == S_OK) { if (statstg.pwcsName != NULL) { TCHAR szTemp[_MAX_PATH]; AfxFullPath(szTemp, OLE2CT(statstg.pwcsName)); CoTaskMemFree(statstg.pwcsName); m_strStorageName = szTemp; } } SCODE sc = lpStorage->CreateStream(T2COLE(lpszStreamName), nOpenFlags, 0, 0, &m_lpStream); if (FAILED(sc) && pError != NULL) _AfxFillOleFileException(pError, sc); ASSERT(FAILED(sc) || m_lpStream != NULL); return !FAILED(sc); } BOOL COleStreamFile::CreateMemoryStream(CFileException* pError) { ASSERT_VALID(this); ASSERT(pError == NULL || AfxIsValidAddress(pError, sizeof(CFileException))); SCODE sc = CreateStreamOnHGlobal(NULL, TRUE, &m_lpStream); if (FAILED(sc) && pError != NULL) _AfxFillOleFileException(pError, sc); ASSERT(FAILED(sc) || m_lpStream != NULL); return !FAILED(sc); } ///////////////////////////////////////////////////////////////////////////// // COleStreamFile Overrides CFile* COleStreamFile::Duplicate() const { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); LPSTREAM lpStream; SCODE sc = m_lpStream->Clone(&lpStream); if (FAILED(sc)) _AfxThrowOleFileException(sc); ASSERT(lpStream != NULL); COleStreamFile* pFile = NULL; TRY { // attempt to create the stream pFile = new COleStreamFile(lpStream); pFile->m_bCloseOnDelete = m_bCloseOnDelete; } CATCH_ALL(e) { // cleanup cloned stream lpStream->Release(); THROW_LAST(); } END_CATCH_ALL ASSERT(pFile != NULL); return pFile; } LONG COleStreamFile::Seek(LONG lOff, UINT nFrom) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); ASSERT(STREAM_SEEK_SET == begin); ASSERT(STREAM_SEEK_CUR == current); ASSERT(STREAM_SEEK_END == end); ULARGE_INTEGER liNewPosition; LARGE_INTEGER liOff; LISet32(liOff, lOff); SCODE sc = m_lpStream->Seek(liOff, nFrom, &liNewPosition); if (sc != S_OK) _AfxThrowOleFileException(sc); ASSERT(liNewPosition.HighPart == 0); return liNewPosition.LowPart; } void COleStreamFile::SetLength(DWORD dwNewLen) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); ULARGE_INTEGER liNewLen; ULISet32(liNewLen, dwNewLen); SCODE sc = m_lpStream->SetSize(liNewLen); if (sc != S_OK) _AfxThrowOleFileException(sc); } DWORD COleStreamFile::GetLength() const { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); // get status of the stream STATSTG statstg; SCODE sc = m_lpStream->Stat(&statstg, STATFLAG_NONAME); if (sc != S_OK) _AfxThrowOleFileException(sc); // map to CFileStatus struct ASSERT(statstg.cbSize.HighPart == 0); return statstg.cbSize.LowPart; } UINT COleStreamFile::Read(void* lpBuf, UINT nCount) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); DWORD dwBytesRead; HRESULT hr = _AfxReadFromStream(m_lpStream, lpBuf, nCount, dwBytesRead); if (hr != S_OK) _AfxThrowOleFileException(hr); // always return number of bytes read return (UINT)dwBytesRead; } void COleStreamFile::Write(const void* lpBuf, UINT nCount) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); if (nCount == 0) return; ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE)); // write to the stream DWORD dwBytesWritten; SCODE sc = m_lpStream->Write(lpBuf, nCount, &dwBytesWritten); if (sc != S_OK) _AfxThrowOleFileException(sc); // if no error, all bytes should have been written ASSERT((UINT)dwBytesWritten == nCount); } void COleStreamFile::LockRange(DWORD dwPos, DWORD dwCount) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); // convert parameters to long integers ULARGE_INTEGER liPos; ULISet32(liPos, dwPos); ULARGE_INTEGER liCount; ULISet32(liCount, dwCount); // then lock the region SCODE sc = m_lpStream->LockRegion(liPos, liCount, LOCK_EXCLUSIVE); if (sc != S_OK) _AfxThrowOleFileException(sc); } void COleStreamFile::UnlockRange(DWORD dwPos, DWORD dwCount) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); // convert parameters to long integers ULARGE_INTEGER liPos; ULISet32(liPos, dwPos); ULARGE_INTEGER liCount; ULISet32(liCount, dwCount); // then lock the region SCODE sc = m_lpStream->UnlockRegion(liPos, liCount, LOCK_EXCLUSIVE); if (sc != S_OK) _AfxThrowOleFileException(sc); } void COleStreamFile::Abort() { ASSERT_VALID(this); if (m_lpStream != NULL) { m_lpStream->Revert(); RELEASE(m_lpStream); } m_strStorageName.Empty(); } void COleStreamFile::Flush() { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); // commit will return an error only if the stream is transacted SCODE sc = m_lpStream->Commit(0); if (sc != S_OK) _AfxThrowOleFileException(sc); } void COleStreamFile::Close() { ASSERT_VALID(this); if (m_lpStream != NULL) { // commit the stream via Flush (which can be overriden) Flush(); RELEASE(m_lpStream); } m_strStorageName.Empty(); } IStream* COleStreamFile::GetStream() const { return m_lpStream; } ///////////////////////////////////////////////////////////////////////////// // COleStreamFile diagnostics #ifdef _DEBUG void COleStreamFile::AssertValid() const { CFile::AssertValid(); } void COleStreamFile::Dump(CDumpContext& dc) const { CFile::Dump(dc); dc << "m_lpStream = " << m_lpStream; dc << "m_strStorageName = \"" << m_strStorageName; dc << "\"\n"; } #endif //////////////////////////////////////////////////////////////////////////// #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(COleStreamFile, CFile) ////////////////////////////////////////////////////////////////////////////