mirror of https://github.com/tongzx/nt5src
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.
3644 lines
84 KiB
3644 lines
84 KiB
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: memstm.cpp
|
|
//
|
|
// Contents: Implementations of IStream and ILockBytes on memory
|
|
// (versus the file system)
|
|
//
|
|
// Classes: CMemStm
|
|
// CMemBytes
|
|
// CMarshalMemStm
|
|
// CMarshalMemBytes
|
|
//
|
|
// Functions: CreateMemStm
|
|
// CloneMemStm
|
|
// ReleaseMemStm
|
|
// CreateStreamOnHGlobal
|
|
// GetHGlobalFromStream
|
|
// CMemStmUnMarshal
|
|
// CMemBytesUnMarshall
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH added Dump methods to CMemStm and CMemBytes
|
|
// (_DEBUG only)
|
|
// added DumpCMemStm and CMemBytes APIs
|
|
// 04-Nov-94 ricksa Made CMemStm class multithread safe.
|
|
// 24-Jan-94 alexgo first pass at converting to Cairo-style
|
|
// memory allocation
|
|
// 11-Jan-94 alexgo added VDATEHEAP macros to every function &
|
|
// method, fixed compile warnings, removed
|
|
// custom marshalling code. Memory streams
|
|
// and ILockBytes now use standard
|
|
// marshalling.
|
|
// 16-Dec-93 alexgo fixed memory reference bugs (bad pointer)
|
|
// 02-Dec-93 alexgo 32bit port, implement CMemStm::CopyTo
|
|
// 11/22/93 - ChrisWe - replace overloaded ==, != with
|
|
// IsEqualIID and IsEqualCLSID
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <le2int.h>
|
|
#pragma SEG(memstm)
|
|
|
|
#include <nturtl.h>
|
|
#include "memstm.h"
|
|
#include "sem.hxx"
|
|
#include <reterr.h>
|
|
|
|
#ifdef _DEBUG
|
|
#include "dbgdump.h"
|
|
#endif // _DEBUG
|
|
|
|
NAME_SEG(CMemStm)
|
|
ASSERTDATA
|
|
|
|
|
|
// CRefMutexSem implementation
|
|
//
|
|
// Instances of this class are shared among all CMemStm objects
|
|
// cloned from a common CMemStm object, as well as their parent.
|
|
//
|
|
// This guarantees synchronization between all instances of CMemStm that share common data
|
|
|
|
CRefMutexSem::CRefMutexSem() : m_lRefs(1)
|
|
{
|
|
// Note: we begin life with one reference
|
|
}
|
|
|
|
CRefMutexSem* CRefMutexSem::CreateInstance()
|
|
{
|
|
CRefMutexSem* prefMutexSem = NULL;
|
|
prefMutexSem = new CRefMutexSem();
|
|
if (prefMutexSem != NULL)
|
|
{
|
|
if (prefMutexSem->FInit() == FALSE)
|
|
{
|
|
ASSERT(FALSE);
|
|
delete prefMutexSem;
|
|
prefMutexSem = NULL;
|
|
}
|
|
}
|
|
return prefMutexSem;
|
|
}
|
|
|
|
BOOL CRefMutexSem::FInit()
|
|
{
|
|
return m_mxs.FInit();
|
|
}
|
|
|
|
ULONG CRefMutexSem::AddRef()
|
|
{
|
|
return InterlockedIncrement (&m_lRefs);
|
|
}
|
|
|
|
ULONG CRefMutexSem::Release()
|
|
{
|
|
LONG lRefs = InterlockedDecrement (&m_lRefs);
|
|
if (lRefs == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return lRefs;
|
|
}
|
|
|
|
void CRefMutexSem::RequestCS()
|
|
{
|
|
m_mxs.Request();
|
|
}
|
|
|
|
void CRefMutexSem::ReleaseCS()
|
|
{
|
|
m_mxs.Release();
|
|
}
|
|
|
|
const CMutexSem2* CRefMutexSem::GetMutexSem()
|
|
{
|
|
return &m_mxs;
|
|
}
|
|
|
|
|
|
inline CRefMutexAutoLock::CRefMutexAutoLock (CRefMutexSem* pmxs)
|
|
{
|
|
Win4Assert (pmxs != NULL);
|
|
|
|
m_pmxs = pmxs;
|
|
m_pmxs->RequestCS();
|
|
|
|
END_CONSTRUCTION (CRefMutexAutoLock);
|
|
}
|
|
|
|
inline CRefMutexAutoLock::~CRefMutexAutoLock()
|
|
{
|
|
m_pmxs->ReleaseCS();
|
|
}
|
|
|
|
// Shared memory IStream implementation
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::CMemStm
|
|
//
|
|
// Synopsis: constructor for memory stream
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// History: 20-Dec-94 Rickhi moved from h file
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CMemStm::CMemStm()
|
|
{
|
|
m_hMem = NULL;
|
|
m_pData = NULL;
|
|
m_pos = 0;
|
|
m_refs = 0;
|
|
m_pmxs = NULL;
|
|
}
|
|
|
|
CMemStm::~CMemStm()
|
|
{
|
|
if (m_pmxs != NULL)
|
|
{
|
|
m_pmxs->Release();
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::QueryInterface
|
|
//
|
|
// Synopsis: retrieves the requested interface
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [iidInterface] -- the requested interface ID
|
|
// [ppvObj] -- where to put the interface pointer
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_OUTOFMEMORY, E_NOINTERFACE
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 11-Jan-94 alexgo removed QI for IMarshal so that
|
|
// the standard marshaller is used.
|
|
// This is fix marshalling across
|
|
// process on 32bit platforms.
|
|
// 02-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_QueryInterface)
|
|
STDMETHODIMP CMemStm::QueryInterface(REFIID iidInterface,
|
|
void FAR* FAR* ppvObj)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
|
|
VDATEPTROUT( ppvObj, LPVOID );
|
|
*ppvObj = NULL;
|
|
VDATEIID( iidInterface );
|
|
|
|
// Two interfaces supported: IUnknown, IStream
|
|
|
|
if (m_pData != NULL && (IsEqualIID(iidInterface, IID_IStream) ||
|
|
IsEqualIID(iidInterface, IID_ISequentialStream) ||
|
|
IsEqualIID(iidInterface, IID_IUnknown)))
|
|
{
|
|
|
|
AddRef(); // A pointer to this object is returned
|
|
*ppvObj = this;
|
|
error = NOERROR;
|
|
}
|
|
#ifndef WIN32
|
|
else if (IsEqualIID(iidInterface, IID_IMarshal))
|
|
{
|
|
*ppvObj = (LPVOID) CMarshalMemStm::Create(this);
|
|
|
|
if (*ppvObj != NULL)
|
|
{
|
|
error = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
error = ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{ // Not accessible or unsupported interface
|
|
*ppvObj = NULL;
|
|
error = ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::AddRef
|
|
//
|
|
// Synopsis: increments the reference count
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new reference count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 02-Dec-93 alexgo 32bit port
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_AddRef)
|
|
STDMETHODIMP_(ULONG) CMemStm::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return InterlockedIncrement((LONG *) &m_refs);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Release
|
|
//
|
|
// Synopsis: decrements the reference count
|
|
//
|
|
// Effects: deletes the object when ref count == 0
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new ref count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 16-Dec-93 alexgo added GlobalUnlock of the MEMSTM handle
|
|
// 02-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Release)
|
|
STDMETHODIMP_(ULONG) CMemStm::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// The reason for this here is that there is a race when releasing
|
|
// this object. If two threads are trying to release this object
|
|
// at the same time, there is a case where the first one dec's
|
|
// the ref count & then loses the processor to the second thread.
|
|
// This second thread decrements the reference count to 0 and frees
|
|
// the memory. The first thread can no longer safely examine the
|
|
// internal state of the object.
|
|
ULONG ulResult = InterlockedDecrement((LONG *) &m_refs);
|
|
|
|
if (ulResult == 0)
|
|
{
|
|
// this MEMSTM handle was GlobalLock'ed in ::Create
|
|
// we unlock it here, as we no longer need it.
|
|
GlobalUnlock(m_hMem);
|
|
|
|
ReleaseMemStm(&m_hMem);
|
|
|
|
delete this;
|
|
}
|
|
|
|
return ulResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Read
|
|
//
|
|
// Synopsis: reads [cb] bytes from the stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pb] -- where to put the data read
|
|
// [cb] -- the number of bytes to read
|
|
// [pcbRead] -- where to put the actual number of bytes
|
|
// read
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm: uses xmemcpy
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 02-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Read)
|
|
STDMETHODIMP CMemStm::Read(void HUGEP* pb, ULONG cb, ULONG FAR* pcbRead)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error = NOERROR;
|
|
ULONG cbRead = cb;
|
|
|
|
if(cb)
|
|
{
|
|
VDATEPTROUT( pb, char);
|
|
}
|
|
|
|
// Single thread
|
|
CRefMutexAutoLock lck(m_pmxs);
|
|
|
|
if (pcbRead)
|
|
{
|
|
VDATEPTROUT( pcbRead, ULONG );
|
|
*pcbRead = 0L;
|
|
}
|
|
|
|
// cbRead + m_pos could cause roll-over.
|
|
if ( ( (cbRead + m_pos) > m_pData->cb) || ( (cbRead + m_pos) < m_pos) )
|
|
{
|
|
// Caller is asking for more bytes than we have left
|
|
if(m_pData->cb > m_pos)
|
|
cbRead = m_pData->cb - m_pos;
|
|
else
|
|
cbRead = 0;
|
|
}
|
|
|
|
if (cbRead > 0)
|
|
{
|
|
Assert (m_pData->hGlobal);
|
|
BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
|
|
m_pData->hGlobal);
|
|
if (NULL==pGlobal)
|
|
{
|
|
LEERROR(1, "GlobalLock Failed!");
|
|
|
|
return ResultFromScode (STG_E_READFAULT);
|
|
}
|
|
// overlap is currently considered a bug (see the discussion
|
|
// on the Write method
|
|
_xmemcpy(pb, pGlobal + m_pos, cbRead);
|
|
GlobalUnlock (m_pData->hGlobal);
|
|
m_pos += cbRead;
|
|
}
|
|
|
|
if (pcbRead != NULL)
|
|
{
|
|
*pcbRead = cbRead;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Write
|
|
//
|
|
// Synopsis: Writes [cb] bytes into the stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pb] -- the bytes to write
|
|
// [cb] -- the number of bytes to write
|
|
// [pcbWritten] -- where to put the number of bytes written
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm: resizes the internal buffer (if needed), then uses xmemcpy
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 02-Dec-93 alexgo 32bit port, fixed bug dealing with
|
|
// 0-byte sized memory
|
|
// 06-Dec-93 alexgo handle overlap case.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Write)
|
|
STDMETHODIMP CMemStm::Write(void const HUGEP* pb, ULONG cb,
|
|
ULONG FAR* pcbWritten)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error = NOERROR;
|
|
ULONG cbWritten = cb;
|
|
ULARGE_INTEGER ularge_integer;
|
|
BYTE HUGEP* pGlobal;
|
|
|
|
if(cb)
|
|
{
|
|
VDATEPTRIN( pb , char );
|
|
}
|
|
|
|
// Single thread
|
|
CRefMutexAutoLock lck(m_pmxs);
|
|
|
|
if (pcbWritten != NULL)
|
|
{
|
|
*pcbWritten = 0;
|
|
}
|
|
|
|
if (cbWritten + m_pos > m_pData->cb)
|
|
{
|
|
ULISet32( ularge_integer, m_pos+cbWritten );
|
|
error = SetSize(ularge_integer);
|
|
if (error != NOERROR)
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// we don't write anything if 0 bytes are asked for for two
|
|
// reasons: 1. optimization, 2. m_pData->hGlobal could be a
|
|
// handle to a zero-byte memory block, in which case GlobalLock
|
|
// will fail.
|
|
|
|
if( cbWritten > 0 )
|
|
{
|
|
pGlobal = (BYTE HUGEP *)GlobalLock (m_pData->hGlobal);
|
|
if (NULL==pGlobal)
|
|
{
|
|
LEERROR(1, "GlobalLock Failed!");
|
|
|
|
return ResultFromScode (STG_E_WRITEFAULT);
|
|
}
|
|
|
|
// we use memmove here instead of memcpy to handle the
|
|
// overlap case. Recall that the app originally gave
|
|
// use the memory for the memstm. He could (either through
|
|
// a CopyTo or through really strange code), be giving us
|
|
// this region to read from, so we have to handle the overlapp
|
|
// case. The same argument also applies for Read, but for
|
|
// now, we'll consider overlap on Read a bug.
|
|
_xmemmove(pGlobal + m_pos, pb, cbWritten);
|
|
GlobalUnlock (m_pData->hGlobal);
|
|
|
|
m_pos += cbWritten;
|
|
}
|
|
|
|
if (pcbWritten != NULL)
|
|
{
|
|
*pcbWritten = cbWritten;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Seek
|
|
//
|
|
// Synopsis: Moves the internal seek pointer
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [dlibMoveIN] -- the amount to move by
|
|
// [dwOrigin] -- flags to control whether seeking is
|
|
// relative to the current postion or
|
|
// the begging/end.
|
|
// [plibNewPosition] -- where to put the new position
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 02-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Seek)
|
|
STDMETHODIMP CMemStm::Seek(LARGE_INTEGER dlibMoveIN, DWORD dwOrigin,
|
|
ULARGE_INTEGER FAR* plibNewPosition)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error = NOERROR;
|
|
LONG dlibMove = dlibMoveIN.LowPart ;
|
|
ULONG cbNewPos = dlibMove;
|
|
|
|
// Single thread
|
|
CRefMutexAutoLock lck(m_pmxs);
|
|
|
|
if (plibNewPosition != NULL)
|
|
{
|
|
VDATEPTROUT( plibNewPosition, ULONG );
|
|
ULISet32(*plibNewPosition, m_pos);
|
|
}
|
|
|
|
switch(dwOrigin)
|
|
{
|
|
|
|
case STREAM_SEEK_SET:
|
|
if (dlibMove >= 0)
|
|
{
|
|
m_pos = dlibMove;
|
|
}
|
|
else
|
|
{
|
|
error = ResultFromScode(STG_E_SEEKERROR);
|
|
}
|
|
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pos))
|
|
{
|
|
m_pos += dlibMove;
|
|
}
|
|
else
|
|
{
|
|
error = ResultFromScode(STG_E_SEEKERROR);
|
|
}
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pData->cb))
|
|
{
|
|
m_pos = m_pData->cb + dlibMove;
|
|
}
|
|
else
|
|
{
|
|
error = ResultFromScode(STG_E_SEEKERROR);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error = ResultFromScode(STG_E_SEEKERROR);
|
|
}
|
|
|
|
if (plibNewPosition != NULL)
|
|
{
|
|
ULISet32(*plibNewPosition, m_pos);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::SetSize
|
|
//
|
|
// Synopsis: Sets the size of our memory
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [cb] -- the new size
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm: calls GlobalRealloc
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 02-Dec-93 alexgo 32bit port, added assert
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_SetSize)
|
|
STDMETHODIMP CMemStm::SetSize(ULARGE_INTEGER cb)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HANDLE hMemNew;
|
|
|
|
// Single thread
|
|
CRefMutexAutoLock lck(m_pmxs);
|
|
|
|
// make sure we aren't in overflow conditions.
|
|
|
|
AssertSz(cb.HighPart == 0,
|
|
"MemStream::More than 2^32 bytes asked for");
|
|
|
|
if (m_pData->cb == cb.LowPart)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
hMemNew = GlobalReAlloc(m_pData->hGlobal, max (cb.LowPart,1),
|
|
GMEM_SHARE | GMEM_MOVEABLE);
|
|
|
|
if (hMemNew == NULL)
|
|
{
|
|
return ResultFromScode (E_OUTOFMEMORY);
|
|
}
|
|
|
|
m_pData->hGlobal = hMemNew;
|
|
m_pData->cb = cb.LowPart;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::CopyTo
|
|
//
|
|
// Synopsis: Copies data from [this] stream to [pstm]
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pstm] -- the stream to copy to
|
|
// [cb] -- the number of bytes to copy
|
|
// [pcbRead] -- where to return the number of bytes read
|
|
// [pcbWritten] -- where to return the number of bytes written
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm: does an IStream->Write to the given stream
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 04-Nov-94 ricksa Modified for multithreading
|
|
// 03-Dec-93 alexgo original implementation
|
|
//
|
|
// Notes: This implementation assumes that the address space
|
|
// is not greater than ULARGE_INTEGER.LowPart (which is
|
|
// for for 32bit operating systems). 64bit NT may need
|
|
// to revisit this code.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_CopyTo)
|
|
STDMETHODIMP CMemStm::CopyTo(IStream FAR *pstm, ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER FAR * pcbRead, ULARGE_INTEGER FAR * pcbWritten)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG cbRead = cb.LowPart;
|
|
ULONG cbWritten = 0;
|
|
HRESULT hresult = NOERROR;
|
|
|
|
// pstm cannot be NULL
|
|
|
|
VDATEPTRIN(pstm, LPSTREAM);
|
|
|
|
// Single thread
|
|
CRefMutexAutoLock lck(m_pmxs);
|
|
|
|
// the spec says that if cb is it's maximum value (all bits set,
|
|
// since it's unsigned), then we will simply read the copy of
|
|
// this stream
|
|
|
|
if ( ~(cb.LowPart) == 0 && ~(cb.HighPart) == 0 )
|
|
{
|
|
cbRead = m_pData->cb - m_pos;
|
|
}
|
|
else if ( cb.HighPart > 0 )
|
|
{
|
|
// we assume that our memory stream cannot
|
|
// be large enough to accomodate very large (>32bit)
|
|
// copy to requests. Since this is probably an error
|
|
// on the caller's part, we assert.
|
|
|
|
AssertSz(0, "WARNING: CopyTo request exceeds 32 bits");
|
|
|
|
// set the Read value to what's left, so that "Ignore"ing
|
|
// the assert works properly.
|
|
|
|
cbRead = m_pData->cb - m_pos;
|
|
}
|
|
else if ( cbRead + m_pos > m_pData->cb )
|
|
{
|
|
// more bytes were requested to read than we had left.
|
|
// cbRead is set to the amount remaining.
|
|
|
|
cbRead = m_pData->cb - m_pos;
|
|
}
|
|
|
|
// now write the data to the stream
|
|
|
|
if ( cbRead > 0 )
|
|
{
|
|
BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
|
|
m_pData->hGlobal);
|
|
|
|
if( pGlobal == NULL )
|
|
{
|
|
LEERROR(1, "GlobalLock failed");
|
|
|
|
return ResultFromScode(STG_E_INSUFFICIENTMEMORY);
|
|
}
|
|
|
|
hresult = pstm->Write(pGlobal + m_pos, cbRead, &cbWritten);
|
|
|
|
// in the error case, the spec says that the return values
|
|
// may be meaningless, so we do not need to do any special
|
|
// error handling here
|
|
|
|
GlobalUnlock(m_pData->hGlobal);
|
|
}
|
|
|
|
// increment our seek pointer and set the out parameters
|
|
|
|
m_pos += cbRead;
|
|
|
|
if( pcbRead )
|
|
{
|
|
ULISet32(*pcbRead, cbRead);
|
|
}
|
|
|
|
if( pcbWritten )
|
|
{
|
|
ULISet32(*pcbWritten, cbWritten);
|
|
}
|
|
|
|
return hresult;
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Commit
|
|
//
|
|
// Synopsis: Does nothing, no transactions available on memory streams
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [grfCommitFlags]
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Commit)
|
|
STDMETHODIMP CMemStm::Commit(DWORD grfCommitFlags)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Revert
|
|
//
|
|
// Synopsis: does nothing, as no transactions are supported on memory
|
|
// streams
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Revert)
|
|
STDMETHODIMP CMemStm::Revert(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::LockRegion
|
|
//
|
|
// Synopsis: not supported in OLE2.01
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [libOffset]
|
|
// [cb]
|
|
// [dwLockType]
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: STG_E_INVALIDFUNCTION
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_LockRegion)
|
|
STDMETHODIMP CMemStm::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return ResultFromScode(STG_E_INVALIDFUNCTION);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::UnlockRegion
|
|
//
|
|
// Synopsis: not implemented for OLE2.01
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [libOffset]
|
|
// [cb]
|
|
// [dwLockType]
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: STG_E_INVALIDFUNCTION
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_UnlockRegion)
|
|
STDMETHODIMP CMemStm::UnlockRegion(ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb, DWORD dwLockType)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return ResultFromScode(STG_E_INVALIDFUNCTION);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Stat
|
|
//
|
|
// Synopsis: Returns info about this stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pstatstg] -- the STATSTG to fill with info
|
|
// [statflag] -- status flags, unused
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_INVALIDARG
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
// 01-Jun-94 AlexT Set type correctly
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Stat)
|
|
STDMETHODIMP CMemStm::Stat(STATSTG FAR *pstatstg, DWORD statflag)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT( pstatstg, STATSTG );
|
|
|
|
memset ( pstatstg, 0, sizeof(STATSTG) );
|
|
|
|
pstatstg->type = STGTY_STREAM;
|
|
pstatstg->cbSize.LowPart = m_pData->cb;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Clone
|
|
//
|
|
// Synopsis: creates a new instance of this stream pointing to the
|
|
// same data at the same position (same seek pointer)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppstm] -- where to put the new CMemStm pointer
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_OUTOFMEMORY
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IStream
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Clone)
|
|
STDMETHODIMP CMemStm::Clone(IStream FAR * FAR *ppstm)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CMemStm FAR* pCMemStm;
|
|
|
|
VDATEPTROUT (ppstm, LPSTREAM);
|
|
|
|
*ppstm = pCMemStm = CMemStm::Create(m_hMem, m_pmxs);
|
|
|
|
if (pCMemStm == NULL)
|
|
{
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
pCMemStm->m_pos = m_pos;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Create
|
|
//
|
|
// Synopsis: Creates a new CMemStm. [hMem] must be a handle to a MEMSTM
|
|
// block.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [hMem] -- handle to a MEMSTM block
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: CMemStm *
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 15-Dec-93 alexgo fixed memory access bug
|
|
// 03-Dec-93 alexgo 32bit port
|
|
// 20-Sep-2000 mfeingol Added Mutex inheritance
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemStm_Create)
|
|
STDSTATICIMP_(CMemStm FAR*) CMemStm::Create(HANDLE hMem, CRefMutexSem* pmxs)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CMemStm FAR* pCMemStm = NULL;
|
|
struct MEMSTM FAR* pData;
|
|
|
|
pData = (MEMSTM FAR*) GlobalLock(hMem);
|
|
|
|
if (pData != NULL)
|
|
{
|
|
pCMemStm = new CMemStm;
|
|
|
|
if (pCMemStm != NULL)
|
|
{
|
|
// Initialize CMemStm
|
|
pCMemStm->m_hMem = hMem;
|
|
InterlockedIncrement ((LPLONG) &(pCMemStm->m_pData = pData)->cRef); // AddRefMemStm
|
|
pCMemStm->m_refs = 1;
|
|
pCMemStm->m_dwSig = STREAM_SIG;
|
|
|
|
if (pmxs != NULL)
|
|
{
|
|
// Addref the input
|
|
pmxs->AddRef();
|
|
}
|
|
else
|
|
{
|
|
// Create a new mutex (implicit addref)
|
|
pmxs = CRefMutexSem::CreateInstance();
|
|
}
|
|
|
|
if (pmxs != NULL)
|
|
{
|
|
// Give the CMemStm a mutex
|
|
pCMemStm->m_pmxs = pmxs;
|
|
}
|
|
else
|
|
{
|
|
// uh-oh, low on memory
|
|
delete pCMemStm;
|
|
pCMemStm = NULL;
|
|
|
|
GlobalUnlock(hMem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// uh-oh, low on memory
|
|
GlobalUnlock(hMem);
|
|
}
|
|
}
|
|
|
|
// we do *not* unlock the memory now, the memstm structure should
|
|
// be locked for the lifetime of any CMemStm's that refer to it.
|
|
// when the CMemStm is destroyed, we will release our lock on
|
|
// hMem.
|
|
|
|
return pCMemStm;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemStm::Dump, public (_DEBUG only)
|
|
//
|
|
// Synopsis: return a string containing the contents of the data members
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: [ppsz] - argument
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm: use dbgstream to create a string containing information on the
|
|
// content of data structures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CMemStm::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszMEMSTM;
|
|
char *pszCMutexSem;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump(400);
|
|
|
|
// determine prefix of newlines
|
|
if ( ulFlag & DEB_VERBOSE )
|
|
{
|
|
dstrPrefix << this << " _VB ";
|
|
}
|
|
|
|
// determine indentation prefix for all newlines
|
|
for (i = 0; i < nIndentLevel; i++)
|
|
{
|
|
dstrPrefix << DUMPTAB;
|
|
}
|
|
|
|
pszPrefix = dstrPrefix.str();
|
|
|
|
// put data members in stream
|
|
dstrDump << pszPrefix << "Impl. Signature = " << m_dwSig << endl;
|
|
|
|
dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "Seek pointer = " << m_pos << endl;
|
|
|
|
dstrDump << pszPrefix << "Memory handle = " << m_hMem << endl;
|
|
|
|
if (m_pData != NULL)
|
|
{
|
|
pszMEMSTM = DumpMEMSTM(m_pData, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "MEMSTM:" << endl;
|
|
dstrDump << pszMEMSTM;
|
|
CoTaskMemFree(pszMEMSTM);
|
|
}
|
|
else
|
|
{
|
|
dstrDump << pszPrefix << "MEMSTM = " << m_pData << endl;
|
|
}
|
|
|
|
pszCMutexSem = DumpCMutexSem ((CMutexSem2*) m_pmxs->GetMutexSem());
|
|
dstrDump << pszPrefix << "Mutex = " << pszCMutexSem << endl;
|
|
CoTaskMemFree(pszCMutexSem);
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCMemStm, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CMemStm::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pMS] - pointer to CMemStm
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: character array of structure dump or error (null terminated)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCMemStm(CMemStm *pMS, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pMS == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pMS->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateMemStm
|
|
//
|
|
// Synopsis: Allocates memory and creates a CMemStm for it.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [cb] -- the number of bytes to allocate
|
|
// [phMem] -- where to put a handle to the MEMSTM structure
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: LPSTREAM to the CMemStream
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 03-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes: phMem must be free'd with ReleaseMemStm (because of ref
|
|
// counting and the nested handle)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CreateMemStm)
|
|
STDAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HANDLE h;
|
|
LPSTREAM pstm = NULL;
|
|
|
|
if (phMem)
|
|
{
|
|
*phMem = NULL;
|
|
}
|
|
|
|
h = GlobalAlloc (GMEM_SHARE | GMEM_MOVEABLE, cb);
|
|
if (NULL==h)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (CreateStreamOnHGlobal (h, TRUE, &pstm) != NOERROR)
|
|
{
|
|
GlobalFree(h); // COM+ 22886
|
|
return NULL;
|
|
}
|
|
if (phMem)
|
|
{
|
|
// retrieve handle from just-created CMemStm
|
|
*phMem = ((CMemStm FAR*)pstm)->m_hMem;
|
|
|
|
// use pointer to bump ref count
|
|
Assert(((CMemStm FAR*)pstm)->m_pData != NULL);
|
|
InterlockedIncrement ((LPLONG) &((CMemStm FAR*)pstm)->m_pData->cRef); // AddRefMemStm
|
|
}
|
|
return pstm;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CloneMemStm
|
|
//
|
|
// Synopsis: Clones a memory stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [hMem] -- a handle to the MEMSTM block
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: LPSTREAM
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#pragma SEG(CloneMemStm)
|
|
|
|
STDAPI_(LPSTREAM) CloneMemStm(HANDLE hMem)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return CMemStm::Create(hMem, NULL); // Create the stream
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ReleaseMemStm
|
|
//
|
|
// Synopsis: Releases the memory used by a MEMSTM structure (including
|
|
// the nested handle)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [phMem] -- pointer the MEMSTM handle
|
|
// [fInternalOnly] -- if TRUE, then only the actual memory
|
|
// that MEMSTM refers to is freed
|
|
// (not the MEMSTM structure itself)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: void
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: sets *phMem to NULL on success
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port and fixed bad memory access
|
|
// bug
|
|
//
|
|
// Notes: REVIEW32: look at taking out the second argument
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(ReleaseMemStm)
|
|
STDAPI_(void) ReleaseMemStm (LPHANDLE phMem, BOOL fInternalOnly)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
struct MEMSTM FAR* pData;
|
|
|
|
pData = (MEMSTM FAR*) GlobalLock(*phMem);
|
|
|
|
// check for NULL pointer in case handle got freed already
|
|
// decrement ref count and free if no refs left
|
|
if (pData != NULL && InterlockedDecrement ((LPLONG) &pData->cRef) == 0)
|
|
{
|
|
if (pData->fDeleteOnRelease)
|
|
{
|
|
Verify (0==GlobalFree (pData->hGlobal));
|
|
}
|
|
|
|
if (!fInternalOnly)
|
|
{
|
|
GlobalUnlock(*phMem);
|
|
Verify (0==GlobalFree(*phMem));
|
|
goto End;
|
|
}
|
|
}
|
|
|
|
GlobalUnlock(*phMem);
|
|
End:
|
|
*phMem = NULL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateStreamOnHGlobal
|
|
//
|
|
// Synopsis: Creates a CMemStm from the given hGlobal (if [hGlobal] is
|
|
// NULL, we allocate a zero byte one)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [hGlobal] -- the memory
|
|
// [fDeleteOnRelease] -- whether the memory should be
|
|
// release on delete
|
|
// [ppstm] -- where to put the stream
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 11-Jan-93 alexgo removed initialization of cbSize to -1
|
|
// to fix compile warning
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CreateStreamOnHGlobal)
|
|
STDAPI CreateStreamOnHGlobal(HANDLE hGlobal, BOOL fDeleteOnRelease,
|
|
LPSTREAM FAR* ppstm)
|
|
{
|
|
OLETRACEIN((API_CreateStreamOnHGlobal, PARAMFMT("hGlobal= %h, fDeleteOnRelease= %B, ppstm= %p"),
|
|
hGlobal, fDeleteOnRelease, ppstm));
|
|
|
|
VDATEHEAP();
|
|
|
|
HANDLE hMem = NULL;
|
|
struct MEMSTM FAR* pData = NULL;
|
|
LPSTREAM pstm = NULL;
|
|
DWORD cbSize;
|
|
BOOL fAllocated = FALSE;
|
|
HRESULT hresult;
|
|
|
|
VDATEPTROUT_LABEL (ppstm, LPSTREAM, SafeExit, hresult);
|
|
|
|
*ppstm = NULL;
|
|
|
|
if (NULL==hGlobal)
|
|
{
|
|
hGlobal = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, 0);
|
|
if (hGlobal == NULL)
|
|
{
|
|
goto FreeMem;
|
|
}
|
|
cbSize = 0;
|
|
fAllocated = TRUE;
|
|
}
|
|
else
|
|
{
|
|
cbSize = (ULONG) GlobalSize (hGlobal);
|
|
// Is there a way to verify a zero-sized handle?
|
|
// we currently do no verification for them
|
|
if (cbSize!=0)
|
|
{
|
|
// verify validity of passed-in handle
|
|
if (NULL==GlobalLock(hGlobal))
|
|
{
|
|
// bad handle
|
|
hresult = ResultFromScode (E_INVALIDARG);
|
|
goto SafeExit;
|
|
}
|
|
GlobalUnlock (hGlobal);
|
|
}
|
|
}
|
|
|
|
hMem = GlobalAlloc (GMEM_SHARE | GMEM_MOVEABLE, sizeof (MEMSTM));
|
|
if (hMem == NULL)
|
|
{
|
|
goto FreeMem;
|
|
}
|
|
|
|
pData = (MEMSTM FAR*) GlobalLock(hMem);
|
|
|
|
if (pData == NULL)
|
|
{
|
|
GlobalUnlock(hMem);
|
|
goto FreeMem;
|
|
}
|
|
|
|
pData->cRef = 0;
|
|
pData->cb = cbSize;
|
|
pData->fDeleteOnRelease = fDeleteOnRelease;
|
|
pData->hGlobal = hGlobal;
|
|
GlobalUnlock(hMem);
|
|
|
|
pstm = CMemStm::Create(hMem, NULL);
|
|
|
|
if (pstm == NULL)
|
|
{
|
|
goto FreeMem;
|
|
}
|
|
|
|
*ppstm = pstm;
|
|
|
|
CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)ppstm);
|
|
hresult = NOERROR;
|
|
goto SafeExit;
|
|
|
|
FreeMem:
|
|
if (hGlobal && fAllocated)
|
|
{
|
|
Verify(0==GlobalFree(hGlobal));
|
|
}
|
|
if (hMem)
|
|
{
|
|
Verify(0==GlobalFree(hMem));
|
|
}
|
|
|
|
LEERROR(1, "Out of memory!");
|
|
|
|
hresult = ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
SafeExit:
|
|
|
|
OLETRACEOUT((API_CreateStreamOnHGlobal, hresult));
|
|
|
|
return hresult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetHGlobalFromStream
|
|
//
|
|
// Synopsis: Retrieves the HGLOBAL to the memory from the given stream
|
|
// pointer (must be a pointer to a CMemByte structure)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pstm] -- pointer to the CMemByte
|
|
// [phglobal] -- where to put the hglobal
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT (E_INVALIDARG, E_OUTOFMEMORY, NOERROR)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(GetHGlobalFromStream)
|
|
STDAPI GetHGlobalFromStream(LPSTREAM pstm, HGLOBAL FAR* phglobal)
|
|
{
|
|
OLETRACEIN((API_GetHGlobalFromStream, PARAMFMT("pstm= %p, phglobal= %p"),
|
|
pstm, phglobal));
|
|
|
|
VDATEHEAP();
|
|
|
|
HRESULT hresult;
|
|
CMemStm FAR* pCMemStm;
|
|
MEMSTM FAR* pMem;
|
|
|
|
VDATEIFACE_LABEL (pstm, errRtn, hresult);
|
|
VDATEPTROUT_LABEL(phglobal, HANDLE, errRtn, hresult);
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pstm);
|
|
|
|
pCMemStm = (CMemStm FAR*) pstm;
|
|
|
|
if (!IsValidReadPtrIn (&(pCMemStm->m_dwSig), sizeof(ULONG))
|
|
|| pCMemStm->m_dwSig != STREAM_SIG)
|
|
{
|
|
// we were passed someone else's implementation of ILockBytes
|
|
hresult = ResultFromScode (E_INVALIDARG);
|
|
goto errRtn;
|
|
}
|
|
|
|
pMem= pCMemStm->m_pData;
|
|
if (NULL==pMem)
|
|
{
|
|
LEERROR(1, "Out of memory!");
|
|
|
|
hresult = ResultFromScode (E_OUTOFMEMORY);
|
|
goto errRtn;
|
|
}
|
|
Assert (pMem->cb <= GlobalSize (pMem->hGlobal));
|
|
Verify (*phglobal = pMem->hGlobal);
|
|
|
|
hresult = NOERROR;
|
|
|
|
errRtn:
|
|
OLETRACEOUT((API_GetHGlobalFromStream, hresult));
|
|
|
|
return hresult;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Shared memory ILockBytes implementation
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::QueryInterface
|
|
//
|
|
// Synopsis: returns the requested interface pointer
|
|
//
|
|
// Effects: a CMarshalMemBytes will be created if IID_IMarshal is
|
|
// requested
|
|
//
|
|
// Arguments: [iidInterface] -- the requested interface ID
|
|
// [ppvObj] -- where to put the interface pointer
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_OUTOFMEMORY, E_NOINTERFACE
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 11-Jan-94 alexgo removed QI for IMarshal so that
|
|
// the standard marshaller will be used.
|
|
// This is to enable correct operation on
|
|
// 32bit platforms.
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_QueryInterface)
|
|
STDMETHODIMP CMemBytes::QueryInterface(REFIID iidInterface,
|
|
void FAR* FAR* ppvObj)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
|
|
VDATEPTROUT( ppvObj, LPVOID );
|
|
*ppvObj = NULL;
|
|
VDATEIID( iidInterface );
|
|
|
|
if (m_pData != NULL && (IsEqualIID(iidInterface, IID_ILockBytes) ||
|
|
IsEqualIID(iidInterface, IID_IUnknown)))
|
|
{
|
|
InterlockedIncrement ((LPLONG) &m_refs); // A pointer to this object is returned
|
|
*ppvObj = this;
|
|
error = NOERROR;
|
|
}
|
|
|
|
// this is not an else if because m_pData can be NULL and we
|
|
// allow creating a CMarshalMemBytes. REVIEW32: We may want
|
|
// to remove this behavior.
|
|
|
|
#ifndef WIN32
|
|
if (IsEqualIID(iidInterface, IID_IMarshal))
|
|
{
|
|
*ppvObj = (LPVOID) CMarshalMemBytes::Create(this);
|
|
if (*ppvObj != NULL)
|
|
{
|
|
error = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
error = ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
error = ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::AddRef
|
|
//
|
|
// Synopsis: Incrememts the reference count
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new reference count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CMemBytes::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return InterlockedIncrement ((LPLONG) &m_refs);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::Release
|
|
//
|
|
// Synopsis: decrements the reference count
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new reference count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 16-Dec-93 alexgo added GlobalUnlock to match the Global
|
|
// Lock in Create
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) CMemBytes::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG ulRefs = InterlockedDecrement ((LPLONG) &m_refs);
|
|
|
|
if (ulRefs != 0)
|
|
{
|
|
return ulRefs;
|
|
}
|
|
|
|
// GlobalUnlock the m_hMem that we GlobalLocke'd in Create
|
|
GlobalUnlock(m_hMem);
|
|
|
|
ReleaseMemStm(&m_hMem);
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::ReadAt
|
|
//
|
|
// Synopsis: reads [cb] bytes from starting position [ulOffset]
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ulOffset] -- the offset to start reading from
|
|
// [pb] -- where to put the data
|
|
// [cb] -- the number of bytes to read
|
|
// [pcbRead] -- where to put the number of bytes actually
|
|
// read
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm: just calls xmemcpy
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_ReadAt)
|
|
STDMETHODIMP CMemBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP* pb,
|
|
ULONG cb, ULONG FAR* pcbRead)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error = NOERROR;
|
|
ULONG cbRead = cb;
|
|
|
|
VDATEPTROUT( pb, char );
|
|
|
|
// make sure we don't offset out of the address space!
|
|
AssertSz(ulOffset.HighPart == 0,
|
|
"CMemBytes: offset greater than 2^32");
|
|
|
|
if (pcbRead)
|
|
{
|
|
*pcbRead = 0L;
|
|
}
|
|
|
|
if (cbRead + ulOffset.LowPart > m_pData->cb)
|
|
{
|
|
|
|
if (ulOffset.LowPart > m_pData->cb)
|
|
{
|
|
// the offset overruns the size of the memory
|
|
cbRead = 0;
|
|
}
|
|
else
|
|
{
|
|
// just read what's left
|
|
cbRead = m_pData->cb - ulOffset.LowPart;
|
|
}
|
|
}
|
|
|
|
if (cbRead > 0)
|
|
{
|
|
BYTE HUGEP* pGlobal = (BYTE HUGEP *)GlobalLock(
|
|
m_pData->hGlobal);
|
|
if (NULL==pGlobal)
|
|
{
|
|
LEERROR(1, "GlobalLock failed!");
|
|
|
|
return ResultFromScode (STG_E_READFAULT);
|
|
}
|
|
_xmemcpy(pb, pGlobal + ulOffset.LowPart, cbRead);
|
|
GlobalUnlock (m_pData->hGlobal);
|
|
}
|
|
|
|
if (pcbRead != NULL)
|
|
{
|
|
*pcbRead = cbRead;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::WriteAt
|
|
//
|
|
// Synopsis: writes [cb] bytes at [ulOffset] in the stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ulOffset] -- the offset at which to start writing
|
|
// [pb] -- the buffer to read from
|
|
// [cb] -- the number of bytes to write
|
|
// [pcbWritten] -- where to put the number of bytes written
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_WriteAt)
|
|
STDMETHODIMP CMemBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP* pb,
|
|
ULONG cb, ULONG FAR* pcbWritten)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error = NOERROR;
|
|
ULONG cbWritten = cb;
|
|
BYTE HUGEP* pGlobal;
|
|
|
|
VDATEPTRIN( pb, char );
|
|
|
|
// make sure the offset doesn't go beyond our address space!
|
|
|
|
AssertSz(ulOffset.HighPart == 0, "WriteAt, offset greater than 2^32");
|
|
|
|
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 != NOERROR)
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// CMemBytes does not allow zero-sized memory handles
|
|
|
|
pGlobal = (BYTE HUGEP *)GlobalLock (m_pData->hGlobal);
|
|
|
|
if (NULL==pGlobal)
|
|
{
|
|
LEERROR(1, "GlobalLock failed!");
|
|
|
|
return ResultFromScode (STG_E_WRITEFAULT);
|
|
}
|
|
|
|
_xmemcpy(pGlobal + ulOffset.LowPart, pb, cbWritten);
|
|
GlobalUnlock (m_pData->hGlobal);
|
|
|
|
|
|
if (pcbWritten != NULL)
|
|
{
|
|
*pcbWritten = cbWritten;
|
|
}
|
|
|
|
Exit:
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::Flush
|
|
//
|
|
// Synopsis: Flushes internal state to disk
|
|
// Not needed for memory ILockBytes
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_Flush)
|
|
STDMETHODIMP CMemBytes::Flush(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::SetSize
|
|
//
|
|
// Synopsis: Sets the size of the memory buffer
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [cb] -- the new size
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_OUTOFMEMORY
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_SetSize)
|
|
STDMETHODIMP CMemBytes::SetSize(ULARGE_INTEGER cb)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HANDLE hMemNew;
|
|
|
|
AssertSz(cb.HighPart == 0,
|
|
"SetSize: trying to set to more than 2^32 bytes");
|
|
|
|
if (m_pData->cb == cb.LowPart)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
hMemNew = GlobalReAlloc(m_pData->hGlobal, max (cb.LowPart, 1),
|
|
GMEM_SHARE | GMEM_MOVEABLE);
|
|
|
|
if (hMemNew == NULL)
|
|
{
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
m_pData->hGlobal = hMemNew;
|
|
m_pData->cb = cb.LowPart;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::LockRegion
|
|
//
|
|
// Synopsis: Locks a region. Since only we have access to the memory,
|
|
// nothing needs to be done (note that the *app* also may
|
|
// access, but there's not much we can do about that)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [libOffset] -- offset to start with
|
|
// [cb] -- the number of bytes in the locked region
|
|
// [dwLockType] -- the type of lock to use
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_LockRegion)
|
|
STDMETHODIMP CMemBytes::LockRegion(ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb, DWORD dwLockType)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::UnlockRegion
|
|
//
|
|
// Synopsis: Unlocks a region; since only we have access to the memory,
|
|
// nothing needs to be done.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [libOffset] -- the offset to start with
|
|
// [cb] -- the number of bytes in the region
|
|
// [dwLockType] -- the lock type
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_UnlockRegion)
|
|
STDMETHODIMP CMemBytes::UnlockRegion(ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb, DWORD dwLockType)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::Stat
|
|
//
|
|
// Synopsis: returns status information
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pstatstg] -- where to put the status info
|
|
// [statflag] -- status flags (ignored)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_INVALIDARG
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: ILockBytes
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
// 01-Jun-94 AlexT Set type correctly
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_Stat)
|
|
STDMETHODIMP CMemBytes::Stat(STATSTG FAR *pstatstg, DWORD statflag)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT( pstatstg, STATSTG );
|
|
|
|
memset ( pstatstg, 0, sizeof(STATSTG) );
|
|
|
|
pstatstg->type = STGTY_LOCKBYTES;
|
|
pstatstg->cbSize.LowPart = m_pData->cb;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::Create
|
|
//
|
|
// Synopsis: Creates an instance of CMemBytes
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [hMem] -- handle to the memory (must be a MEMSTM block)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: CMemBytes *
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 16-Dec-93 alexgo fixed bad pointer bug (took out
|
|
// GlobalUnlock)
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMemBytes_Create)
|
|
STDSTATICIMP_(CMemBytes FAR*) CMemBytes::Create(HANDLE hMem)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CMemBytes FAR* pCMemBytes = NULL;
|
|
struct MEMSTM FAR* pData;
|
|
|
|
pData = (MEMSTM FAR*) GlobalLock(hMem);
|
|
|
|
if (pData != NULL)
|
|
{
|
|
Assert (pData->hGlobal);
|
|
|
|
pCMemBytes = new CMemBytes;
|
|
|
|
if (pCMemBytes != NULL)
|
|
{
|
|
// Initialize CMemBytes
|
|
pCMemBytes->m_dwSig = LOCKBYTE_SIG;
|
|
pCMemBytes->m_hMem = hMem;
|
|
InterlockedIncrement ((LPLONG) &(pCMemBytes->m_pData = pData)->cRef); // AddRefMemStm
|
|
pCMemBytes->m_refs = 1;
|
|
CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_ILockBytes,
|
|
(IUnknown **)&pCMemBytes);
|
|
}
|
|
else
|
|
{
|
|
// uh-oh, low on memory
|
|
GlobalUnlock(hMem);
|
|
}
|
|
}
|
|
|
|
// we don't GlobalUnlock(hMem) until we destory this CMemBytes
|
|
return pCMemBytes;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMemBytes::Dump, public (_DEBUG only)
|
|
//
|
|
// Synopsis: return a string containing the contents of the data members
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: [ppsz] - argument
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm: use dbgstream to create a string containing information on the
|
|
// content of data structures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CMemBytes::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszMEMSTM;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump(400);
|
|
|
|
// determine prefix of newlines
|
|
if ( ulFlag & DEB_VERBOSE )
|
|
{
|
|
dstrPrefix << this << " _VB ";
|
|
}
|
|
|
|
// determine indentation prefix for all newlines
|
|
for (i = 0; i < nIndentLevel; i++)
|
|
{
|
|
dstrPrefix << DUMPTAB;
|
|
}
|
|
|
|
pszPrefix = dstrPrefix.str();
|
|
|
|
// put data members in stream
|
|
dstrDump << pszPrefix << "Impl. Signature = " << m_dwSig << endl;
|
|
|
|
dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "Memory handle = " << m_hMem << endl;
|
|
|
|
if (m_pData != NULL)
|
|
{
|
|
pszMEMSTM = DumpMEMSTM(m_pData, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "MEMSTM:" << endl;
|
|
dstrDump << pszMEMSTM;
|
|
CoTaskMemFree(pszMEMSTM);
|
|
}
|
|
else
|
|
{
|
|
dstrDump << pszPrefix << "MEMSTM = " << m_pData << endl;
|
|
}
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCMemBytes, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CMemBytes::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pMB] - pointer to CMemBytes
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: character array of structure dump or error (null terminated)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCMemBytes(CMemBytes *pMB, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pMB == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pMB->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
// --------------------------------------------------------------------
|
|
// EVERYTHING BELOW HERE HAS BEEN REMOVED FROM WIN32 VERSIONS.
|
|
|
|
#ifndef WIN32
|
|
|
|
// CMemStm object's IMarshal implementation
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::QueryInterface
|
|
//
|
|
// Synopsis: returns the requested interface ID
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [iidInterface] -- the requested interface
|
|
// [ppvObj] -- where to put the interface pointer
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_NOINTERFACE
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_QueryInterface)
|
|
STDMETHODIMP CMarshalMemStm::QueryInterface(REFIID iidInterface,
|
|
void FAR* FAR* ppvObj)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
|
|
VDATEPTROUT( ppvObj, LPVOID );
|
|
*ppvObj = NULL;
|
|
VDATEIID( iidInterface );
|
|
|
|
// Two interfaces supported: IUnknown, IMarshal
|
|
|
|
if (IsEqualIID(iidInterface, IID_IMarshal) ||
|
|
IsEqualIID(iidInterface, IID_IUnknown))
|
|
{
|
|
InterlockedIncrement (&m_refs); // A pointer to this object is returned
|
|
*ppvObj = this;
|
|
error = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
// Not accessible or unsupported interface
|
|
*ppvObj = NULL;
|
|
error = ResultFromScode (E_NOINTERFACE);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemstm::AddRef
|
|
//
|
|
// Synopsis: increments the reference count
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new reference count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_AddRef)
|
|
STDMETHODIMP_(ULONG) CMarshalMemStm::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return InterlockedIncrement (&m_refs);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::Release
|
|
//
|
|
// Synopsis: decrements the reference count
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: ULONG -- the new reference count
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_Release)
|
|
STDMETHODIMP_(ULONG) CMarshalMemStm::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG ulRefs = InterlockedDecrement (&m_refs);
|
|
|
|
if (ulRefs != 0)
|
|
{
|
|
return ulRefs;
|
|
}
|
|
|
|
if (m_pMemStm != NULL)
|
|
{
|
|
m_pMemStm->Release();
|
|
}
|
|
|
|
delete this; // Free storage
|
|
return 0;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::GetUnmarshalClass
|
|
//
|
|
// Synopsis: returns the object class that should be used to create
|
|
// the proxy in the unmarshalling process (CLSID_StdMemStm)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [riid] -- the interface ID of the object to be
|
|
// marshalled
|
|
// [pv] -- pointer to the object
|
|
// [dwDestContext] -- marshalling context (such a no shared mem)
|
|
// [pvDestContext] -- reserved
|
|
// [mshlfags] -- marshalling flags (e.g. NORMAL)
|
|
// [pCid] -- where to put the class ID
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_GetUnmarshalClass)
|
|
STDMETHODIMP CMarshalMemStm::GetUnmarshalClass(REFIID riid, LPVOID pv,
|
|
DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags,
|
|
CLSID FAR* pCid)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT( pCid, CLSID);
|
|
|
|
*pCid = CLSID_StdMemStm;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::GetUnmarshalSizeMax
|
|
//
|
|
// Synopsis: returns the amount of memory needed to marshal the data
|
|
// (in this case, the hglobal)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [riid] -- the interface of the object
|
|
// [pv] -- pointer to the object
|
|
// [dwDestContext] -- marshalling context (such a no shared mem)
|
|
// [pvDestContext] -- reserved
|
|
// [mshlfags] -- marshalling flags (e.g. NORMAL)
|
|
// [pSize] -- where to put the size
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: NOERROR, E_INVALIDARG
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_GetMarshalSizeMax)
|
|
STDMETHODIMP CMarshalMemStm::GetMarshalSizeMax(REFIID riid, LPVOID pv,
|
|
DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags,
|
|
DWORD FAR* pSize)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT(pSize, DWORD);
|
|
|
|
*pSize = sizeof(m_pMemStm->m_hMem);
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::MarshalInterface
|
|
//
|
|
// Synopsis: marshals a reference of the objects interface into [pStm]
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pStm] -- the stream into which the object should
|
|
// be marshalled
|
|
// [riid] -- the interface ID of the object to be
|
|
// marshalled
|
|
// [pv] -- points to the interface
|
|
// [dwDestContext] -- the marshalling context
|
|
// [pvDestContext] -- unused
|
|
// [mshlflags] -- marshalling flags
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_MarshalInterface)
|
|
STDMETHODIMP CMarshalMemStm::MarshalInterface(IStream FAR* pStm,
|
|
REFIID riid, void FAR* pv, DWORD dwDestContext,
|
|
LPVOID pvDestContext, DWORD mshlflags)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTRIN( pStm, IStream );
|
|
VDATEIID( riid );
|
|
VDATEIFACE( pv );
|
|
|
|
if (m_pMemStm == NULL)
|
|
{
|
|
return ResultFromScode(E_UNSPEC);
|
|
}
|
|
|
|
if ((!IsEqualIID(riid, IID_IStream) &&
|
|
!IsEqualIID(riid, IID_IUnknown)) || pv != m_pMemStm)
|
|
{
|
|
return ReportResult(0, E_INVALIDARG, 0, 0);
|
|
}
|
|
|
|
// increase ref count on hglobal (ReleaseMarshalData has -- to match)
|
|
HRESULT error;
|
|
if ((error = pStm->Write(&m_pMemStm->m_hMem,
|
|
sizeof(m_pMemStm->m_hMem), NULL)) == NOERROR)
|
|
{
|
|
InterlockedIncrement (&m_pMemStm->m_pData->cRef); // AddRefMemStm
|
|
}
|
|
return error;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::UnmarshalInterface
|
|
//
|
|
// Synopsis: Unmarshals an the object from the given stream
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pStm] -- the stream to read data from
|
|
// [riid] -- the interface the caller wants from the
|
|
// object
|
|
// [ppvObj] -- where to put a pointer to the object
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation: IMarshal
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 05-Dec-93 alexgo 32bit port
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CMarshalMemStm_UnmarshalInterface)
|
|
STDMETHODIMP CMarshalMemStm::UnmarshalInterface(IStream FAR* pStm,
|
|
REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
HANDLE hMem;
|
|
|
|
VDATEPTROUT( ppv, LPVOID );
|
|
*ppv = NULL;
|
|
VDATEPTRIN( pStm, IStream );
|
|
VDATEIID( riid );
|
|
|
|
if (!IsEqualIID(riid, IID_IStream) && !IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
error = pStm->Read(&hMem,sizeof(hMem),NULL);
|
|
if (error != NOERROR)
|
|
{
|
|
return error;
|
|
}
|
|
|
|
if (m_pMemStm != NULL)
|
|
{
|
|
if (hMem != m_pMemStm->m_hMem)
|
|
{
|
|
return ResultFromScode(E_UNSPEC);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pMemStm = (CMemStm FAR*) CloneMemStm(hMem);
|
|
if (m_pMemStm == NULL)
|
|
{
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
m_pMemStm->AddRef();
|
|
*ppv = (LPVOID) m_pMemStm;
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CMarshalMemStm::ReleaseMarshalData
|
|
//
|
|
// Synopsis: releases the marshalling data (takes away ref count on
|
|
// hglobal)
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemStm_ReleaseMarshalData)
|
|
STDMETHODIMP CMarshalMemStm::ReleaseMarshalData(IStream FAR* pStm)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// reduce ref count on hglobal (matches that done in MarshalInterface)
|
|
HRESULT error;
|
|
HANDLE hMem;
|
|
|
|
VDATEIFACE( pStm );
|
|
|
|
error = pStm->Read(&hMem,sizeof(hMem),NULL);
|
|
if (error == NOERROR)
|
|
ReleaseMemStm(&hMem);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemStm_DisconnectObject)
|
|
STDMETHODIMP CMarshalMemStm::DisconnectObject(DWORD dwReserved)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemStm_Create)
|
|
STDSTATICIMP_(CMarshalMemStm FAR*) CMarshalMemStm::Create(CMemStm FAR* pMemStm)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CMarshalMemStm FAR* pMMS;
|
|
|
|
//VDATEPTRIN rejects NULL
|
|
if( pMemStm )
|
|
GEN_VDATEPTRIN( pMemStm, CMemStm, (CMarshalMemStm FAR *) NULL );
|
|
|
|
pMMS = new(MEMCTX_TASK, NULL) CMarshalMemStm;
|
|
|
|
if (pMMS == NULL)
|
|
return NULL;
|
|
|
|
if (pMemStm != NULL) {
|
|
pMMS->m_pMemStm = pMemStm;
|
|
pMMS->m_pMemStm->AddRef();
|
|
}
|
|
|
|
pMMS->m_refs = 1;
|
|
|
|
return pMMS;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMemStmUnMarshal)
|
|
STDAPI_(IUnknown FAR*) CMemStmUnMarshal(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return CMarshalMemStm::Create(NULL);
|
|
}
|
|
|
|
|
|
|
|
// CMemBytes object's IMarshal implementation
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_QueryInterface)
|
|
STDMETHODIMP CMarshalMemBytes::QueryInterface(REFIID iidInterface,
|
|
void FAR* FAR* ppvObj)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
|
|
VDATEIID( iidInterface );
|
|
VDATEPTROUT( ppvObj, LPVOID );
|
|
*ppvObj = NULL;
|
|
|
|
// Two interfaces supported: IUnknown, IMarshal
|
|
|
|
if (IsEqualIID(iidInterface, IID_IMarshal)
|
|
|| IsEqualIID(iidInterface, IID_IUnknown))
|
|
{
|
|
InterlockedIncrement (&m_refs); // A pointer to this object is returned
|
|
*ppvObj = this;
|
|
error = NOERROR;
|
|
}
|
|
else
|
|
{ // Not accessible or unsupported interface
|
|
*ppvObj = NULL;
|
|
error = ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
// Called when CMarshalMemBytes is referenced by an additional pointer.
|
|
//
|
|
|
|
#pragma SEG(CMarshalMemBytes_AddRef)
|
|
STDMETHODIMP_(ULONG) CMarshalMemBytes::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return InterlockedIncrement (&m_refs);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_Release)
|
|
// Called when a pointer to this CMarshalMemBytes is discarded
|
|
//
|
|
STDMETHODIMP_(ULONG) CMarshalMemBytes::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG ulRefs = InterlockedDecrement (&m_refs);
|
|
|
|
if (ulRefs != 0) // Still used by others
|
|
return ulRefs;
|
|
|
|
if (m_pMemBytes != NULL)
|
|
m_pMemBytes->Release();
|
|
|
|
delete this; // Free storage
|
|
return 0;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_GetUnmarshalClass)
|
|
// Returns the clsid of the object that created this CMarshalMemBytes.
|
|
//
|
|
STDMETHODIMP CMarshalMemBytes::GetUnmarshalClass(REFIID riid, LPVOID pv,
|
|
DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID FAR* pCid)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEIID( riid );
|
|
VDATEIFACE( pv );
|
|
|
|
*pCid = CLSID_StdMemBytes;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_GetMarshalSizeMax)
|
|
STDMETHODIMP CMarshalMemBytes::GetMarshalSizeMax(REFIID riid, LPVOID pv,
|
|
DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD FAR* pSize)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT( pSize, DWORD );
|
|
VDATEIID( riid );
|
|
VDATEIFACE( pv );
|
|
|
|
*pSize = sizeof(m_pMemBytes->m_hMem);
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_MarshalInterface)
|
|
STDMETHODIMP CMarshalMemBytes::MarshalInterface(IStream FAR* pStm,
|
|
REFIID riid, void FAR* pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTRIN(pStm, IStream );
|
|
VDATEIID( riid );
|
|
if ( pv )
|
|
VDATEPTRIN( pv , char );
|
|
|
|
if (m_pMemBytes == NULL)
|
|
return ReportResult(0, E_UNSPEC, 0, 0);
|
|
|
|
if ((!IsEqualIID(riid, IID_ILockBytes) &&
|
|
!IsEqualIID(riid, IID_IUnknown)) || pv != m_pMemBytes)
|
|
return ReportResult(0, E_INVALIDARG, 0, 0);
|
|
|
|
// increase ref count on hglobal (ReleaseMarshalData has -- to match)
|
|
HRESULT error;
|
|
|
|
if ((error = pStm->Write(&m_pMemBytes->m_hMem,
|
|
sizeof(m_pMemBytes->m_hMem), NULL)) == NOERROR)
|
|
InterlockedIncrement (&m_pMemBytes->m_pData->cRef); // AddRefMemStm
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_UnmarshalInterface)
|
|
STDMETHODIMP CMarshalMemBytes::UnmarshalInterface(IStream FAR* pStm,
|
|
REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
HANDLE hMem;
|
|
|
|
VDATEPTROUT( ppv , LPVOID );
|
|
*ppv = NULL;
|
|
VDATEIFACE( pStm );
|
|
VDATEIID( riid );
|
|
|
|
|
|
if (!IsEqualIID(riid, IID_ILockBytes) &&
|
|
!IsEqualIID(riid, IID_IUnknown))
|
|
return ReportResult(0, E_INVALIDARG, 0, 0);
|
|
|
|
error = pStm->Read(&hMem,sizeof(hMem),NULL);
|
|
if (error != NOERROR)
|
|
return error;
|
|
|
|
if (m_pMemBytes != NULL)
|
|
{
|
|
if (hMem != m_pMemBytes->m_hMem)
|
|
return ReportResult(0, E_UNSPEC, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
m_pMemBytes = CMemBytes::Create(hMem); // Create the lockbytes
|
|
|
|
if (m_pMemBytes == NULL)
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
|
|
m_pMemBytes->AddRef();
|
|
*ppv = (LPVOID) m_pMemBytes;
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
STDMETHODIMP CMarshalMemBytes::ReleaseMarshalData(IStream FAR* pStm)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// reduce ref count on hglobal (matches that done in MarshalInterface)
|
|
HRESULT error;
|
|
HANDLE hMem;
|
|
|
|
VDATEIFACE( pStm );
|
|
|
|
error = pStm->Read(&hMem,sizeof(hMem),NULL);
|
|
if (error == NOERROR)
|
|
ReleaseMemStm(&hMem);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_DisconnectObject)
|
|
STDMETHODIMP CMarshalMemBytes::DisconnectObject(DWORD dwReserved)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#pragma SEG(CMarshalMemBytes_Create)
|
|
STDSTATICIMP_(CMarshalMemBytes FAR*) CMarshalMemBytes::Create(
|
|
CMemBytes FAR* pMemBytes)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CMarshalMemBytes FAR* pMMB;
|
|
|
|
//VDATEPTRIN rejects NULL
|
|
if( pMemBytes )
|
|
GEN_VDATEPTRIN( pMemBytes, CMemBytes,
|
|
(CMarshalMemBytes FAR *)NULL);
|
|
|
|
pMMB = new(MEMCTX_TASK, NULL) CMarshalMemBytes;
|
|
|
|
if (pMMB == NULL)
|
|
return NULL;
|
|
|
|
if (pMemBytes != NULL)
|
|
{
|
|
pMMB->m_pMemBytes = pMemBytes;
|
|
pMMB->m_pMemBytes->AddRef();
|
|
}
|
|
|
|
pMMB->m_refs = 1;
|
|
|
|
return pMMB;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#pragma SEG(CMemBytesUnMarshal)
|
|
STDAPI_(IUnknown FAR*) CMemBytesUnMarshal(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return CMarshalMemBytes::Create(NULL);
|
|
}
|
|
|
|
#endif // !WIN32 -- win32 builds use standard marshalling for
|
|
// streams and lockbytes.
|