You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
523 lines
16 KiB
523 lines
16 KiB
// --------------------------------------------------------------------------------
|
|
// 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;
|
|
}
|