Windows2003-3790/inetcore/outlookexpress/inetcomm/mimeole/stmlock.cpp
2020-09-30 16:53:55 +02:00

524 lines
16 KiB
C++

// --------------------------------------------------------------------------------
// Stmlock.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "stmlock.h"
#include "vstream.h"
#include "demand.h"
// --------------------------------------------------------------------------------
// CStreamLockBytes::CStreamLockBytes
// --------------------------------------------------------------------------------
CStreamLockBytes::CStreamLockBytes(IStream *pStream)
{
Assert(pStream);
m_cRef = 1;
m_pStream = pStream;
m_pStream->AddRef();
InitializeCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::CStreamLockBytes
// --------------------------------------------------------------------------------
CStreamLockBytes::~CStreamLockBytes(void)
{
SafeRelease(m_pStream);
DeleteCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::CStreamLockBytes
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::QueryInterface(REFIID riid, LPVOID *ppv)
{
// check params
if (ppv == NULL)
return TrapError(E_INVALIDARG);
// Init
*ppv = NULL;
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else if (IID_ILockBytes == riid)
*ppv = (ILockBytes *)this;
else if (IID_CStreamLockBytes == riid)
*ppv = (CStreamLockBytes *)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::CStreamLockBytes
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStreamLockBytes::AddRef(void)
{
return (ULONG)InterlockedIncrement(&m_cRef);
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::CStreamLockBytes
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CStreamLockBytes::Release(void)
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::HrSetPosition
// --------------------------------------------------------------------------------
HRESULT CStreamLockBytes::HrSetPosition(ULARGE_INTEGER uliOffset)
{
EnterCriticalSection(&m_cs);
LARGE_INTEGER liOrigin;
liOrigin.QuadPart = (DWORDLONG)uliOffset.QuadPart;
HRESULT hr = m_pStream->Seek(liOrigin, STREAM_SEEK_SET, NULL);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::HrHandsOffStorage
// --------------------------------------------------------------------------------
HRESULT CStreamLockBytes::HrHandsOffStorage(void)
{
// Locals
HRESULT hr=S_OK;
LPSTREAM pstmNew=NULL;
// Thread Safety
EnterCriticalSection(&m_cs);
// If Reference Count Isn't 1 (i.e. owned by IMimeMessageTree), dup the internal data
if (1 != m_cRef)
{
// Copy m_pStream to a local place...
CHECKALLOC(pstmNew = new CVirtualStream);
// Rewind Internal
CHECKHR(hr = HrRewindStream(m_pStream));
// Copy the stream
CHECKHR(hr = HrCopyStream(m_pStream, pstmNew, NULL));
// Rewind and commit
CHECKHR(hr = pstmNew->Commit(STGC_DEFAULT));
// Rewind
CHECKHR(hr = HrRewindStream(pstmNew));
// Replace Internal Stream
ReplaceInternalStream(pstmNew);
}
exit:
// Cleanup
SafeRelease(pstmNew);
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -------------------------------------------------------------------------
// CStreamLockBytes::GetCurrentStream
// -------------------------------------------------------------------------
void CStreamLockBytes::GetCurrentStream(IStream **ppStream)
{
EnterCriticalSection(&m_cs);
Assert(ppStream && m_pStream);
*ppStream = m_pStream;
(*ppStream)->AddRef();
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::ReplaceInternalStream
// --------------------------------------------------------------------------------
void CStreamLockBytes::ReplaceInternalStream(IStream *pStream)
{
// Locals
HRESULT hr=S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// No Internal Strea ?
if (NULL == m_pStream)
{
Assert(FALSE);
goto exit;
}
// DEBUG: Make sure stream are EXACTLY the same size
#ifdef DEBUG
ULONG cbInternal, cbExternal;
HrGetStreamSize(m_pStream, &cbInternal);
HrGetStreamSize(pStream, &cbExternal);
Assert(cbInternal == cbExternal);
#endif
// Release Internal
m_pStream->Release();
m_pStream = pStream;
m_pStream->AddRef();
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::Flush
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::Flush(void)
{
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->Commit(STGC_DEFAULT);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::LockRegion
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->LockRegion(libOffset, cb, dwLockType);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::UnlockRegion
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->LockRegion(libOffset, cb, dwLockType);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::ReadAt
// --------------------------------------------------------------------------------
#ifndef WIN16
STDMETHODIMP CStreamLockBytes::ReadAt(ULARGE_INTEGER ulOffset, void *pv, ULONG cb, ULONG *pcbRead)
#else
STDMETHODIMP CStreamLockBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP *pv, ULONG cb, ULONG *pcbRead)
#endif // !WIN16
{
LARGE_INTEGER liOrigin={ulOffset.LowPart, ulOffset.HighPart};
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->Seek(liOrigin, STREAM_SEEK_SET, NULL);
if (SUCCEEDED(hr))
hr = m_pStream->Read(pv, cb, pcbRead);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::WriteAt
// --------------------------------------------------------------------------------
#ifndef WIN16
STDMETHODIMP CStreamLockBytes::WriteAt(ULARGE_INTEGER ulOffset, void const *pv, ULONG cb, ULONG *pcbWritten)
#else
STDMETHODIMP CStreamLockBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP *pv, ULONG cb, ULONG *pcbWritten)
#endif // !WIN16
{
LARGE_INTEGER liOrigin={ulOffset.LowPart, ulOffset.HighPart};
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->Seek(liOrigin, STREAM_SEEK_SET, NULL);
if (SUCCEEDED(hr))
hr = m_pStream->Write(pv, cb, pcbWritten);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::SetSize
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::SetSize(ULARGE_INTEGER cb)
{
EnterCriticalSection(&m_cs);
HRESULT hr = m_pStream->SetSize(cb);
LeaveCriticalSection(&m_cs);
return hr;
}
// --------------------------------------------------------------------------------
// CStreamLockBytes::Stat
// --------------------------------------------------------------------------------
STDMETHODIMP CStreamLockBytes::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
// Locals
HRESULT hr=S_OK;
// Parameters
if (NULL == pstatstg)
return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// Zero Init
ZeroMemory(pstatstg, sizeof(STATSTG));
// Stat
if (FAILED(m_pStream->Stat(pstatstg, grfStatFlag)))
{
// Locals
ULARGE_INTEGER uliPos;
LARGE_INTEGER liOrigin;
// Initialize
uliPos.QuadPart = 0;
liOrigin.QuadPart = 0;
// If that failed, lets generate our own information (mainly, fill in size
pstatstg->type = STGTY_LOCKBYTES;
// Seek
if (FAILED(m_pStream->Seek(liOrigin, STREAM_SEEK_END, &uliPos)))
hr = E_FAIL;
else
pstatstg->cbSize.QuadPart = uliPos.QuadPart;
}
// URLMON Streams return a filled pwcsName event though this flag is set
else if (ISFLAGSET(grfStatFlag, STATFLAG_NONAME))
{
// Free it
SafeMemFree(pstatstg->pwcsName);
}
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -------------------------------------------------------------------------
// CLockedStream::CLockedStream
// -------------------------------------------------------------------------
CLockedStream::CLockedStream(ILockBytes *pLockBytes, ULONG cbSize)
{
Assert(pLockBytes);
m_cRef = 1;
m_pLockBytes = pLockBytes;
m_pLockBytes->AddRef();
m_uliOffset.QuadPart = 0;
m_uliSize.QuadPart = cbSize;
InitializeCriticalSection(&m_cs);
}
// -------------------------------------------------------------------------
// CLockedStream::CLockedStream
// -------------------------------------------------------------------------
CLockedStream::~CLockedStream(void)
{
SafeRelease(m_pLockBytes);
DeleteCriticalSection(&m_cs);
}
// -------------------------------------------------------------------------
// CLockedStream::QueryInterface
// -------------------------------------------------------------------------
STDMETHODIMP CLockedStream::QueryInterface(REFIID riid, LPVOID *ppv)
{
// check params
if (ppv == NULL)
return TrapError(E_INVALIDARG);
// Init
*ppv = NULL;
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else if (IID_IStream == riid)
*ppv = (IStream *)this;
else
{
*ppv = NULL;
return TrapError(E_NOINTERFACE);
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
// Done
return S_OK;
}
// -------------------------------------------------------------------------
// CLockedStream::AddRef
// -------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CLockedStream::AddRef(void)
{
return (ULONG)InterlockedIncrement(&m_cRef);
}
// -------------------------------------------------------------------------
// CLockedStream::Release
// -------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CLockedStream::Release(void)
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
// -------------------------------------------------------------------------
// CLockedStream::Read
// -------------------------------------------------------------------------
#ifndef WIN16
STDMETHODIMP CLockedStream::Read(LPVOID pv, ULONG cb, ULONG *pcbRead)
#else
STDMETHODIMP CLockedStream::Read(VOID HUGEP *pv, ULONG cb, ULONG *pcbRead)
#endif // !WIN16
{
// Locals
HRESULT hr=S_OK;
ULONG cbRead;
// Thread Safety
EnterCriticalSection(&m_cs);
// Read Buffer
CHECKHR(hr = m_pLockBytes->ReadAt(m_uliOffset, pv, cb, &cbRead));
// Done
m_uliOffset.QuadPart += cbRead;
// Return amount read
if (pcbRead)
*pcbRead = cbRead;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// -------------------------------------------------------------------------
// CLockedStream::Seek
// -------------------------------------------------------------------------
STDMETHODIMP CLockedStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
{
// Locals
HRESULT hr=S_OK;
ULARGE_INTEGER uliNew;
// Thread Safety
EnterCriticalSection(&m_cs);
// Seek the file pointer
switch (dwOrigin)
{
// --------------------------------------------------------
case STREAM_SEEK_SET:
uliNew.QuadPart = (DWORDLONG)dlibMove.QuadPart;
break;
// --------------------------------------------------------
case STREAM_SEEK_CUR:
if (dlibMove.QuadPart < 0)
{
if ((DWORDLONG)(0 - dlibMove.QuadPart) > m_uliOffset.QuadPart)
{
hr = TrapError(E_FAIL);
goto exit;
}
}
uliNew.QuadPart = m_uliOffset.QuadPart + dlibMove.QuadPart;
break;
// --------------------------------------------------------
case STREAM_SEEK_END:
if (dlibMove.QuadPart < 0 || (DWORDLONG)dlibMove.QuadPart > m_uliSize.QuadPart)
{
hr = TrapError(E_FAIL);
goto exit;
}
uliNew.QuadPart = m_uliSize.QuadPart - dlibMove.QuadPart;
break;
// --------------------------------------------------------
default:
hr = TrapError(STG_E_INVALIDFUNCTION);
goto exit;
}
// New offset greater than size...
m_uliOffset.QuadPart = min(uliNew.QuadPart, m_uliSize.QuadPart);
// Return Position
if (plibNew)
plibNew->QuadPart = (LONGLONG)m_uliOffset.QuadPart;
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// CLockedStream::CopyTo
// --------------------------------------------------------------------------------
STDMETHODIMP CLockedStream::CopyTo(LPSTREAM pstmDest, ULARGE_INTEGER cb, ULARGE_INTEGER *puliRead, ULARGE_INTEGER *puliWritten)
{
return HrCopyStreamCB((IStream *)this, pstmDest, cb, puliRead, puliWritten);
}
// --------------------------------------------------------------------------------
// CLockedStream::Stat
// --------------------------------------------------------------------------------
STDMETHODIMP CLockedStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
// Parameters
if (NULL == pstatstg)
return TrapError(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&m_cs);
// If that failed, lets generate our own information (mainly, fill in size
ZeroMemory(pstatstg, sizeof(STATSTG));
pstatstg->type = STGTY_STREAM;
pstatstg->cbSize.QuadPart = m_uliSize.QuadPart;
// Thread Safety
LeaveCriticalSection(&m_cs);
// Done
return S_OK;
}