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 >
Wrap
C/C++ Source or Header
|
1998-06-16
|
12KB
|
511 lines
// 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)
////////////////////////////////////////////////////////////////////////////