|
|
//+-------------------------------------------------------------------
//
// File: memstm.cxx
//
// Contents: test class for IStream
//
// Classes: CMemStm
//
// History: 23-Nov-92 Rickhi Created
//
//--------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "memstm.h"
extern "C" { const GUID CLSID_StdMemStm = {0x00000301,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
const GUID CLSID_StdMemBytes = {0x00000302,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; }
// Shared memory IStream implementation
//
STDMETHODIMP CMemStm::QueryInterface(REFIID iidInterface, void **ppvObj) { SCODE error; *ppvObj = NULL;
// Two interfaces supported: IUnknown, IStream
if (m_pData != NULL && (IsEqualIID(iidInterface,IID_IStream) || IsEqualIID(iidInterface,IID_IUnknown)))
{ m_refs++; // A pointer to this object is returned
*ppvObj = this; error = S_OK; } else { // Not accessible or unsupported interface
*ppvObj = NULL; error = E_NOINTERFACE; }
return error; }
STDMETHODIMP_(ULONG) CMemStm::AddRef(void) { ++ m_refs; return m_refs; }
STDMETHODIMP_(ULONG) CMemStm::Release(void) { --m_refs;
if (m_refs != 0) // Still used by others
return m_refs;
// Matches the allocation in CMemStm::Create().
//
if (--m_pData->cRef == 0) { GlobalUnlock(m_hMem); GlobalFree(m_hMem); } else GlobalUnlock(m_hMem);
delete this; // Free storage
return 0; }
STDMETHODIMP CMemStm::Read(void HUGEP* pb, ULONG cb, ULONG * pcbRead) { SCODE error = S_OK; ULONG cbRead = cb; if (pcbRead) *pcbRead = 0L; if (cbRead + m_pos > m_pData->cb) { cbRead = m_pData->cb - m_pos; error = E_FAIL; }
// BUGBUG - size_t limit
memcpy(pb,m_pData->buf + m_pos,(size_t) cbRead); m_pos += cbRead;
if (pcbRead != NULL) *pcbRead = cbRead;
return error; }
STDMETHODIMP CMemStm::Write(void const HUGEP* pb, ULONG cb, ULONG * pcbWritten) { SCODE error = S_OK; ULONG cbWritten = cb; ULARGE_INTEGER ularge_integer;
if (pcbWritten) *pcbWritten = 0L;
if (cbWritten + m_pos > m_pData->cb) { ULISet32( ularge_integer, m_pos+cbWritten ); error = SetSize(ularge_integer); if (error != S_OK) return error; }
// BUGBUG - size_t limit
memcpy(m_pData->buf + m_pos,pb,(size_t) cbWritten); m_pos += cbWritten;
if (pcbWritten != NULL) *pcbWritten = cbWritten;
return error; }
STDMETHODIMP CMemStm::Seek(LARGE_INTEGER dlibMoveIN, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition) { SCODE error = S_OK; LONG dlibMove = dlibMoveIN.LowPart ; ULONG cbNewPos = dlibMove;
if (plibNewPosition != NULL) { ULISet32(*plibNewPosition, m_pos); }
switch(dwOrigin) { case STREAM_SEEK_SET: if (dlibMove >= 0) m_pos = dlibMove; else error = E_FAIL; break;
case STREAM_SEEK_CUR: if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pos)) m_pos += dlibMove; else error = E_FAIL; break;
case STREAM_SEEK_END: if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pData->cb)) m_pos = m_pData->cb + dlibMove; else error = E_FAIL; break;
default: error = E_FAIL; }
if (plibNewPosition != NULL) ULISet32(*plibNewPosition, m_pos);
return error; }
STDMETHODIMP CMemStm::SetSize(ULARGE_INTEGER cb) { HANDLE hMemNew; struct MEMSTM * pDataNew;
if (m_pData->cb == cb.LowPart) return S_OK;
if (GlobalUnlock(m_hMem) != 0) return E_FAIL;
hMemNew = GlobalReAlloc(m_hMem,sizeof(MEMSTM) - sizeof(m_pData->buf) + cb.LowPart,GMEM_DDESHARE | GMEM_MOVEABLE);
if (hMemNew == NULL) { GlobalLock(m_hMem); return E_OUTOFMEMORY; }
pDataNew = (MEMSTM *) GlobalLock(hMemNew);
if (pDataNew == NULL) // Completely hosed
return E_FAIL;
m_hMem = hMemNew; pDataNew->cb = cb.LowPart; m_pData = pDataNew;
return S_OK; }
STDMETHODIMP CMemStm::CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { SCODE hRslt; ULONG cbWritten = 0;
if (!pstm) return E_FAIL;
// write our data into the stream.
hRslt = pstm->Write(m_pData->buf, cb.LowPart, &cbWritten);
pcbRead->LowPart = cb.LowPart; pcbRead->HighPart = 0; pcbWritten->LowPart = cbWritten; pcbWritten->HighPart = 0;
return hRslt; }
STDMETHODIMP CMemStm::Commit(DWORD grfCommitFlags) { return E_FAIL; } STDMETHODIMP CMemStm::Revert(void) { return E_FAIL; } STDMETHODIMP CMemStm::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_FAIL; } STDMETHODIMP CMemStm::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return E_FAIL; }
STDMETHODIMP CMemStm::Stat(STATSTG *pstatstg, DWORD statflag) { pstatstg->pwcsName = NULL; pstatstg->type = 0; pstatstg->cbSize.HighPart = 0; pstatstg->cbSize.LowPart = m_pData->cb; pstatstg->mtime.dwLowDateTime = 0; pstatstg->mtime.dwHighDateTime = 0; pstatstg->ctime.dwLowDateTime = 0; pstatstg->ctime.dwHighDateTime = 0; pstatstg->atime.dwLowDateTime = 0; pstatstg->atime.dwHighDateTime = 0; pstatstg->grfMode = 0; pstatstg->grfLocksSupported = 0; pstatstg->clsid = CLSID_NULL; pstatstg->grfStateBits = 0;
#ifdef CAIROLE_DOWNLEVEL
pstatstg->reserved = 0; #else
pstatstg->dwStgFmt = 0; #endif
return S_OK; }
STDMETHODIMP CMemStm::Clone(IStream * *ppstm) { SCODE hRslt = E_FAIL;
// create a new stream
IStream *pIStm = CreateMemStm(m_pData->cb, NULL);
if (pIStm) { // copy data to it
ULARGE_INTEGER cbRead, cbWritten; ULARGE_INTEGER cb; cb.LowPart = m_pData->cb; cb.HighPart = 0;
hRslt = CopyTo(pIStm, cb, &cbRead, &cbWritten); if (hRslt == S_OK) { *ppstm = pIStm; } }
return hRslt; }
// Create CMemStm.
//
CMemStm * CMemStm::Create(HANDLE hMem) { CMemStm * pCMemStm; struct MEMSTM * pData;
pData = (MEMSTM *) GlobalLock(hMem); if (pData == NULL) return NULL;
pCMemStm = new CMemStm;
if (pCMemStm == NULL) { GlobalUnlock(hMem); return NULL; }
// Initialize CMemStm
//
pCMemStm->m_hMem = hMem; (pCMemStm->m_pData = pData)->cRef++; pCMemStm->m_refs = 1;
return pCMemStm; }
// Allocate shared memory and create CMemStm on top of it.
// Return pointer to the stream if done, NULL if error.
//
STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem) { HANDLE hMem; struct MEMSTM * pData; IStream * pStm;
if ( phMem ) *phMem = NULL;
// Get shared memory
hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(MEMSTM) - sizeof(pData->buf) + cb); if (hMem == NULL) return NULL;
pData = (MEMSTM *) GlobalLock(hMem); if (pData == NULL) goto FreeMem;
pData->cb = cb; // If caller doesn't ask for the memory handle
// Release() should free the memory.
//
pData->cRef = (phMem == NULL) ? 0 : 1; GlobalUnlock(hMem);
pStm = CMemStm::Create(hMem); // Create the stream
if (pStm == NULL) goto FreeMem;
if (phMem) *phMem = hMem;
return pStm;
FreeMem: GlobalFree(hMem); return NULL; }
// Create CMemStm on top of the specified hMem.
// Return pointer to the stream if done, NULL if error.
//
STDAPI_(LPSTREAM) CloneMemStm(HANDLE hMem) { return CMemStm::Create(hMem); // Create the stream
}
//////////////////////////////////////////////////////////////////////////
// Shared memory ILockBytes implementation
//
STDMETHODIMP CMemBytes::QueryInterface(REFIID iidInterface, void **ppvObj) { SCODE error = S_OK; *ppvObj = NULL;
// Two interfaces supported: IUnknown, ILockBytes
if (m_pData != NULL && (IsEqualIID(iidInterface,IID_ILockBytes) || IsEqualIID(iidInterface,IID_IUnknown))) {
m_refs++; // A pointer to this object is returned
*ppvObj = this; } else if (IsEqualIID(iidInterface,IID_IMarshal)) { *ppvObj = (LPVOID) CMarshalMemBytes::Create(this); if (*ppvObj == NULL) error = E_OUTOFMEMORY; } else { // Not accessible or unsupported interface
*ppvObj = NULL; error = E_NOINTERFACE; }
return error; }
STDMETHODIMP_(ULONG) CMemBytes::AddRef(void) { return ++m_refs; }
STDMETHODIMP_(ULONG) CMemBytes::Release(void) { if (--m_refs != 0) // Still used by others
return m_refs;
// Matches the allocation in CMemBytes::Create().
//
if (--m_pData->cRef == 0) { if (m_pData->fDeleteOnRelease) { GlobalFree(m_pData->hGlobal); } GlobalUnlock(m_hMem); GlobalFree(m_hMem); } else GlobalUnlock(m_hMem);
delete this; // Free storage
return 0; }
STDMETHODIMP CMemBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP* pb, ULONG cb, ULONG * pcbRead) { SCODE error = S_OK; ULONG cbRead = cb;
if (pcbRead) *pcbRead = 0L;
if (cbRead + ulOffset.LowPart > m_pData->cb) { if (ulOffset.LowPart > m_pData->cb) cbRead = 0; else cbRead = m_pData->cb - ulOffset.LowPart;
error = E_FAIL; }
char HUGEP* pGlobal = (char HUGEP*) GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { return STG_E_READFAULT; }
memcpy(pb, pGlobal + ulOffset.LowPart, cbRead); GlobalUnlock (m_pData->hGlobal);
if (pcbRead != NULL) *pcbRead = cbRead;
return error; }
STDMETHODIMP CMemBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP* pb, ULONG cb, ULONG * pcbWritten) { SCODE error = S_OK; ULONG cbWritten = cb; char HUGEP* pGlobal;
if (pcbWritten) *pcbWritten = 0;
if (cbWritten + ulOffset.LowPart > m_pData->cb) { ULARGE_INTEGER ularge_integer; ULISet32( ularge_integer, ulOffset.LowPart + cbWritten); error = SetSize( ularge_integer ); if (error != S_OK) return error; }
pGlobal = (char HUGEP*) GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { return STG_E_WRITEFAULT; }
memcpy(pGlobal + ulOffset.LowPart, pb, cbWritten); GlobalUnlock (m_pData->hGlobal);
if (pcbWritten != NULL) *pcbWritten = cbWritten;
return error; }
STDMETHODIMP CMemBytes::Flush(void) { return S_OK; }
STDMETHODIMP CMemBytes::SetSize(ULARGE_INTEGER cb) { HANDLE hMemNew;
if (m_pData->cb == cb.LowPart) return S_OK;
hMemNew = GlobalReAlloc(m_pData->hGlobal, cb.LowPart, GMEM_DDESHARE | GMEM_MOVEABLE);
if (hMemNew == NULL) return E_OUTOFMEMORY;
m_pData->hGlobal = hMemNew; m_pData->cb = cb.LowPart;
return S_OK; }
STDMETHODIMP CMemBytes::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return S_OK; }
STDMETHODIMP CMemBytes::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { return S_OK; }
STDMETHODIMP CMemBytes::Stat(STATSTG *pstatstg, DWORD statflag) { pstatstg->pwcsName = NULL; pstatstg->type = 0; pstatstg->cbSize.HighPart = 0; pstatstg->cbSize.LowPart = m_pData->cb; pstatstg->mtime.dwLowDateTime = 0; pstatstg->mtime.dwHighDateTime = 0; pstatstg->ctime.dwLowDateTime = 0; pstatstg->ctime.dwHighDateTime = 0; pstatstg->atime.dwLowDateTime = 0; pstatstg->atime.dwHighDateTime = 0; pstatstg->grfMode = 0; pstatstg->grfLocksSupported = 0; pstatstg->clsid = CLSID_NULL; pstatstg->grfStateBits = 0; #ifdef CAIROLE_DOWNLEVEL
pstatstg->reserved = 0; #else
pstatstg->dwStgFmt = 0; #endif
return S_OK; }
// Create CMemBytes.
//
CMemBytes * CMemBytes::Create(HANDLE hMem) { CMemBytes * pCMemBytes; struct MEMBYTES * pData;
pData = (MEMBYTES *) GlobalLock(hMem); if (pData == NULL) return NULL;
pCMemBytes = new CMemBytes;
if (pCMemBytes == NULL) { GlobalUnlock(hMem); return NULL; }
// Initialize CMemBytes
//
pCMemBytes->m_dwSig = LOCKBYTE_SIG; pCMemBytes->m_hMem = hMem; (pCMemBytes->m_pData = pData)->cRef++; pCMemBytes->m_refs = 1;
return pCMemBytes; }
STDAPI_(LPLOCKBYTES) CreateMemLockBytes(DWORD cb, LPHANDLE phMem) { HANDLE h; LPLOCKBYTES plb = NULL;
if (phMem) *phMem = NULL;
h = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cb); if (NULL==h) return NULL;
if (CreateILockBytesOnHGlobal (h, phMem==NULL, &plb) != S_OK) return NULL;
if (phMem) GetHGlobalFromILockBytes (plb, phMem);
return plb; }
// Create CMemBytes on top of the specified hMem.
// Return pointer to the stream if done, NULL if error.
//
STDAPI_(LPLOCKBYTES) CloneMemLockbytes(HANDLE hMem) { return CMemBytes::Create(hMem); // Create the lockbytes
}
// CMemStm object's IMarshal implementation
//
STDMETHODIMP CMarshalMemStm::QueryInterface(REFIID iidInterface, void * * ppvObj) { SCODE error = S_OK; *ppvObj = NULL;
// Two interfaces supported: IUnknown, IMarshal
if (IsEqualIID(iidInterface,IID_IMarshal) || IsEqualIID(iidInterface,IID_IUnknown)) { m_refs++; // A pointer to this object is returned
*ppvObj = this; } else { // Not accessible or unsupported interface
*ppvObj = NULL; error = E_NOINTERFACE; }
return error; }
STDMETHODIMP_(ULONG) CMarshalMemStm::AddRef(void) { return ++m_refs; }
STDMETHODIMP_(ULONG) CMarshalMemStm::Release(void) { if (--m_refs != 0) // Still used by others
return m_refs;
if (m_pMemStm) m_pMemStm->Release();
delete this; // Free storage
return 0; }
// Returns the clsid of the object that created this CMarshalMemStm.
//
STDMETHODIMP CMarshalMemStm::GetUnmarshalClass(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pCid) { *pCid = m_clsid; return S_OK; }
STDMETHODIMP CMarshalMemStm::GetMarshalSizeMax(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD * pSize) { *pSize = sizeof(m_pMemStm->m_hMem); return S_OK; }
STDMETHODIMP CMarshalMemStm::MarshalInterface(IStream * pStm, REFIID riid, void * pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) { if (m_pMemStm == NULL) return E_FAIL;
if ((!IsEqualIID(riid,IID_IStream) && !IsEqualIID(riid,IID_IUnknown)) || pv != m_pMemStm) return E_INVALIDARG;
// increase ref count on hglobal (ReleaseMarshalData has -- to match)
SCODE error; error = pStm->Write(&m_pMemStm->m_hMem,sizeof(m_pMemStm->m_hMem), NULL); if (error == S_OK) m_pMemStm->m_pData->cRef++;
return error; }
STDMETHODIMP CMarshalMemStm::UnmarshalInterface(IStream * pStm, REFIID riid, void * * ppv) { SCODE error; HANDLE hMem;
*ppv = NULL; if (!IsEqualIID(riid,IID_IStream) && !IsEqualIID(riid,IID_IUnknown)) return E_INVALIDARG;
error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error != S_OK) return error;
if (m_pMemStm != NULL) { if (hMem != m_pMemStm->m_hMem) return E_FAIL; } else { m_pMemStm = (CMemStm *) CloneMemStm(hMem); if (m_pMemStm == NULL) return E_OUTOFMEMORY; }
m_pMemStm->AddRef(); *ppv = (LPVOID) m_pMemStm; return S_OK; }
STDMETHODIMP CMarshalMemStm::ReleaseMarshalData(IStream * pStm) { // reduce ref count on hglobal (matches that done in MarshalInterface)
SCODE error; MEMSTM * pData; HANDLE hMem;
error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error != S_OK) return error;
pData = (MEMSTM *) GlobalLock(hMem); if (pData == NULL) return E_FAIL;
if (--pData->cRef == 0) { GlobalUnlock(hMem); GlobalFree(hMem); } else // still used by one or more CMemStm in one or more processes
GlobalUnlock(hMem);
return S_OK; }
STDMETHODIMP CMarshalMemStm::DisconnectObject(DWORD dwReserved) { return S_OK; }
CMarshalMemStm * CMarshalMemStm::Create(CMemStm * pMemStm) { CMarshalMemStm * pMMS = new CMarshalMemStm;
if (pMMS == NULL) return NULL;
if (pMemStm != NULL) { pMMS->m_pMemStm = pMemStm; pMMS->m_pMemStm->AddRef(); }
pMMS->m_clsid = CLSID_StdMemStm; pMMS->m_refs = 1;
return pMMS; }
STDAPI_(IUnknown *) CMemStmUnMarshal(void) { return CMarshalMemStm::Create(NULL); }
// CMemBytes object's IMarshal implementation
//
STDMETHODIMP CMarshalMemBytes::QueryInterface(REFIID iidInterface, void * * ppvObj) { SCODE error = S_OK; *ppvObj = NULL;
// Two interfaces supported: IUnknown, IMarshal
if (IsEqualIID(iidInterface,IID_IMarshal) || IsEqualIID(iidInterface,IID_IUnknown)) { m_refs++; // A pointer to this object is returned
*ppvObj = this; } else { // Not accessible or unsupported interface
*ppvObj = NULL; error = E_NOINTERFACE; }
return error; }
STDMETHODIMP_(ULONG) CMarshalMemBytes::AddRef(void) { return ++m_refs; }
STDMETHODIMP_(ULONG) CMarshalMemBytes::Release(void) { if (--m_refs != 0) // Still used by others
return m_refs;
if (m_pMemBytes != NULL) m_pMemBytes->Release();
delete this; // Free storage
return 0; }
// Returns the clsid of the object that created this CMarshalMemBytes.
//
STDMETHODIMP CMarshalMemBytes::GetUnmarshalClass(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID * pCid) { *pCid = m_clsid; return S_OK; }
STDMETHODIMP CMarshalMemBytes::GetMarshalSizeMax(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD * pSize) { *pSize = sizeof(m_pMemBytes->m_hMem); return S_OK; }
STDMETHODIMP CMarshalMemBytes::MarshalInterface(IStream * pStm, REFIID riid, void * pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) { if (m_pMemBytes == NULL) return E_FAIL;
if ((!IsEqualIID(riid,IID_ILockBytes) && !IsEqualIID(riid,IID_IUnknown)) || pv != m_pMemBytes) return E_INVALIDARG;
// increase ref count on hglobal (ReleaseMarshalData has -- to match)
SCODE error; error = pStm->Write(&m_pMemBytes->m_hMem,sizeof(m_pMemBytes->m_hMem),NULL); if (error == S_OK) m_pMemBytes->m_pData->cRef++;
return error; }
STDMETHODIMP CMarshalMemBytes::UnmarshalInterface(IStream * pStm, REFIID riid, void * * ppv) { HANDLE hMem;
*ppv = NULL;
if (!IsEqualIID(riid,IID_ILockBytes) && !IsEqualIID(riid,IID_IUnknown)) return E_INVALIDARG;
SCODE error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error != S_OK) return error;
if (m_pMemBytes != NULL) { if (hMem != m_pMemBytes->m_hMem) return E_FAIL; } else { m_pMemBytes = (CMemBytes *) CloneMemLockbytes(hMem); if (m_pMemBytes == NULL) return E_OUTOFMEMORY; }
m_pMemBytes->AddRef(); *ppv = (LPVOID) m_pMemBytes; return S_OK; }
STDMETHODIMP CMarshalMemBytes::ReleaseMarshalData(IStream * pStm) { // reduce ref count on hglobal (matches that done in MarshalInterface)
MEMBYTES *pData; HANDLE hMem;
SCODE error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error != S_OK) return error;
pData = (MEMBYTES *) GlobalLock(hMem); if (pData == NULL) return E_FAIL;
if (--pData->cRef == 0) { GlobalUnlock(hMem); GlobalFree(hMem); } else { // still used by one or more CMemStm in one or more processes
GlobalUnlock(hMem); }
return S_OK; }
STDMETHODIMP CMarshalMemBytes::DisconnectObject(DWORD dwReserved) { return S_OK; }
CMarshalMemBytes *CMarshalMemBytes::Create(CMemBytes *pMemBytes) { CMarshalMemBytes *pMMB = new CMarshalMemBytes;
if (pMMB == NULL) return NULL;
if (pMemBytes != NULL) { pMMB->m_pMemBytes = pMemBytes; pMMB->m_pMemBytes->AddRef(); }
pMMB->m_clsid = CLSID_StdMemBytes; pMMB->m_refs = 1;
return pMMB; }
STDAPI_(IUnknown *) CMemBytesUnMarshal(void) { return CMarshalMemBytes::Create(NULL); }
|