//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: memstm.cxx // // Contents: memstm.cpp from OLE2 // // History: 11-Apr-94 DrewB Copied from OLE2 // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop #include #include "memstm.h" #include static const UINT grfMem = GMEM_SHARE | GMEM_MOVEABLE; // REVIEW: there is a lot of duplicate code. There used to be two separate // but identical structs: MEMSTM and MEMBYTES; the structs have be merged and // common code should be pulled out including: Release, AddRef, marshal, SetSize // Shared memory IStream implementation // OLEMETHODIMP CMemStm::QueryInterface(REFIID iidInterface, void FAR* FAR* ppvObj) { M_PROLOG(this); HRESULT error; VDATEPTROUT( ppvObj, LPVOID ); *ppvObj = NULL; VDATEIID( iidInterface ); // Two interfaces supported: IUnknown, IStream if (m_pData != NULL && (iidInterface == IID_IStream || iidInterface == IID_IUnknown)) { m_refs++; // A pointer to this object is returned *ppvObj = this; error = NOERROR; } else // // BUGBUG - Renable this once CraigWi seperates Custom Marshalling stuff from // standard identity stuff. (Right now you can't get in between the standard // marshaller and the code which calls it, you're either completely custom // marshalling, or your not). Once it is better organized, we could marshall // a heap handle and the custom marshalling stuff. Then when unmarshalling in // the same wow, we unmarshal the heap handle, when not in the same wow, then // use the standard marshalling stuff. // Same goes for ILockBytesonHglobal below... // #define BOBDAY_DISABLE_MARSHAL_FOR_NOW #ifdef BOBDAY_DISABLE_MARSHAL_FOR_NOW #else if (iidInterface == IID_IMarshal) { *ppvObj = (LPVOID) CMarshalMemStm::Create(this); if (*ppvObj != NULL) error = NOERROR; else error = ReportResult(0, E_OUTOFMEMORY, 0, 0); } else #endif { // Not accessible or unsupported interface *ppvObj = NULL; error = ReportResult(0, E_NOINTERFACE, 0, 0); } return error; } // Called when CMemStm is referenced by an additional pointer. // OLEMETHODIMP_(ULONG) CMemStm::AddRef(void) { M_PROLOG(this); return ++m_refs; } // Called when a pointer to this CMemStm is discarded // OLEMETHODIMP_(ULONG) CMemStm::Release(void) { M_PROLOG(this); if (--m_refs != 0) // Still used by others return m_refs; ReleaseMemStm(&m_hMem); delete this; // Free storage return 0; } OLEMETHODIMP CMemStm::Read(void HUGEP* pb, ULONG cb, ULONG FAR* pcbRead) { M_PROLOG(this); thkDebugOut((DEB_ITRACE, "%p _IN CMemStm16::Read(pb=%p,cb=%lx)\n", this,pb,cb)); HRESULT error = NOERROR; ULONG cbRead = cb; VDATEPTROUT( pb, char); if (pcbRead) { VDATEPTROUT( pcbRead, ULONG ); *pcbRead = 0L; } if (pcbRead != NULL) *pcbRead = 0; if (cbRead + m_pos > m_pData->cb) { // Caller is asking for more bytes than we have left cbRead = m_pData->cb - m_pos; } if (cbRead > 0) { Assert (m_pData->hGlobal); char HUGEP* pGlobal = GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { Assert (0); error = ResultFromScode (STG_E_READFAULT); goto exitRtn; } UtMemCpy (pb, pGlobal + m_pos, cbRead); GlobalUnlock (m_pData->hGlobal); m_pos += cbRead; } if (pcbRead != NULL) *pcbRead = cbRead; exitRtn: thkDebugOut((DEB_ITRACE, "%p OUT CMemStm16::Read() returns %lx\n", this,error)); return error; } OLEMETHODIMP CMemStm::Write(void const HUGEP* pb, ULONG cb, ULONG FAR* pcbWritten) { A5_PROLOG(this); HRESULT error = NOERROR; thkDebugOut((DEB_ITRACE, "%p _IN CMemStm16::Write(pb=%p,cb=%lx)\n", this,pb,cb)); ULONG cbWritten = cb; ULARGE_INTEGER ularge_integer; char HUGEP* pGlobal; if ( pcbWritten ) { VDATEPTROUT( pcbWritten, ULONG ); *pcbWritten = 0L; } VDATEPTRIN( pb , char ); 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; } pGlobal = GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { Assert (0); error = ResultFromScode (STG_E_WRITEFAULT); goto Exit; } UtMemCpy (pGlobal + m_pos, pb, cbWritten); GlobalUnlock (m_pData->hGlobal); m_pos += cbWritten; if (pcbWritten != NULL) *pcbWritten = cbWritten; Exit: RESTORE_A5(); thkDebugOut((DEB_ITRACE, "%p OUT CMemStm16::Write() returns %lx\n", this,error)); return error; } OLEMETHODIMP CMemStm::Seek(LARGE_INTEGER dlibMoveIN, DWORD dwOrigin, ULARGE_INTEGER FAR* plibNewPosition) { M_PROLOG(this); thkDebugOut((DEB_ITRACE,"%p _IN CMemStm16::Seek()\n",this)); HRESULT error = NOERROR; LONG dlibMove = dlibMoveIN.LowPart ; ULONG cbNewPos = dlibMove; if (plibNewPosition != NULL){ VDATEPTROUT( plibNewPosition, ULONG ); ULISet32(*plibNewPosition, m_pos); } switch(dwOrigin) { case STREAM_SEEK_SET: if (dlibMove >= 0) m_pos = dlibMove; else error = ReportResult(0, E_UNSPEC, 0, 0); // should return invalid seek break; case STREAM_SEEK_CUR: if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pos)) m_pos += dlibMove; else error = ReportResult(0, E_UNSPEC, 0, 0); // should return invalid seek break; case STREAM_SEEK_END: if (!(dlibMove < 0 && ((ULONG) -dlibMove) > m_pData->cb)) m_pos = m_pData->cb + dlibMove; else error = ReportResult(0, E_UNSPEC, 0, 0); // should return invalid seek break; default: error = ReportResult(0, E_UNSPEC, 0, 0); // should return invalid seek mode } if (plibNewPosition != NULL) ULISet32(*plibNewPosition, m_pos); thkDebugOut((DEB_ITRACE,"%p OUT CMemStm16::Seek() returns %lx\n",this,error)); return error; } OLEMETHODIMP CMemStm::SetSize(ULARGE_INTEGER cb) { M_PROLOG(this); thkDebugOut((DEB_ITRACE, "%p _IN CMemStm16::SetSize(cb=%lx%lx)\n", this,cb.HighPart,cb.LowPart)); HANDLE hMemNew; HRESULT hresult = NOERROR; if (m_pData->cb == cb.LowPart) { goto errRtn; } hMemNew = GlobalReAlloc(m_pData->hGlobal,max (cb.LowPart,1),grfMem); if (hMemNew == NULL) { hresult = ResultFromScode (E_OUTOFMEMORY); goto errRtn; } m_pData->hGlobal = hMemNew; m_pData->cb = cb.LowPart; errRtn: thkDebugOut((DEB_ITRACE, "%p OUT CMemStm16::SetSize() returns %lx\n", this, hresult)); return hresult; } OLEMETHODIMP CMemStm::CopyTo(IStream FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER FAR * pcbRead, ULARGE_INTEGER FAR * pcbWritten) { thkDebugOut((DEB_ITRACE, "%p _IN CMemStm16::CopyTo(pstm=%p)\n", this, pstm)); ULONG cbRead = cb.LowPart; ULONG cbWritten = 0; HRESULT hresult = NOERROR; // pstm cannot be NULL VDATEPTRIN(pstm, LPSTREAM); // 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. thkAssert(!"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 ) { thkAssert(!"GlobalLock failed"); hresult = (HRESULT)STG_E_INSUFFICIENTMEMORY; goto errRtn; } 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); } errRtn: thkDebugOut((DEB_ITRACE, "%p OUT CMemStm16::CopyTo(pstm=%p) returns %lx\n", this, pstm, hresult)); return hresult; } OLEMETHODIMP CMemStm::Commit(DWORD grfCommitFlags) { M_PROLOG(this); return NOERROR; // since this stream is not transacted, no error } OLEMETHODIMP CMemStm::Revert(void) { M_PROLOG(this); return NOERROR; // nothing done } OLEMETHODIMP CMemStm::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { M_PROLOG(this); return ResultFromScode(STG_E_INVALIDFUNCTION); } OLEMETHODIMP CMemStm::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { M_PROLOG(this); return ResultFromScode(STG_E_INVALIDFUNCTION); } OLEMETHODIMP CMemStm::Stat(STATSTG FAR *pstatstg, DWORD statflag) { M_PROLOG(this); VDATEPTROUT( pstatstg, STATSTG ); 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; pstatstg->reserved = 0; return NOERROR; } // returns new instance of pstm pointing to same data at same position. OLEMETHODIMP CMemStm::Clone(IStream FAR * FAR *ppstm) { M_PROLOG(this); CMemStm FAR* pCMemStm; VDATEPTROUT (ppstm, LPSTREAM); *ppstm = pCMemStm = CMemStm::Create(m_hMem); if (pCMemStm == NULL) return ResultFromScode(E_OUTOFMEMORY); pCMemStm->m_pos = m_pos; return NOERROR; } // Create CMemStm. Handle must be a MEMSTM block. // OLESTATICIMP_(CMemStm FAR*) CMemStm::Create(HANDLE hMem) { CMemStm FAR* pCMemStm; struct MEMSTM FAR* pData; pData = (MEMSTM FAR*)MAKELONG(0, HIWORD(GlobalHandle(hMem))); if (pData == NULL) return NULL; pCMemStm = new CMemStm; if (pCMemStm == NULL) return NULL; // Initialize CMemStm // pCMemStm->m_hMem = hMem; (pCMemStm->m_pData = pData)->cRef++; // AddRefMemStm pCMemStm->m_refs = 1; pCMemStm->m_dwSig = STREAM_SIG; return pCMemStm; } // Allocate shared memory and create CMemStm on top of it. // Return pointer to the stream if done, NULL if error. // If the handle is returned, it must be free with ReleaseMemStm // (because of ref counting and the nested global handle). // OLEAPI_(LPSTREAM) CreateMemStm(DWORD cb, LPHANDLE phMem) { HANDLE h; thkDebugOut((DEB_ITRACE, "%p _IN CreateMemStm16(cb=%lx,phMem=%p\n",0,cb,phMem)); LPSTREAM pstm = NULL; if (phMem) { *phMem = NULL; } h = GlobalAlloc (grfMem, cb); if (NULL==h) { goto errRtn; } if (CreateStreamOnHGlobal (h, TRUE, &pstm) != NOERROR) { pstm = NULL; goto errRtn; } 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); ((CMemStm FAR*)pstm)->m_pData->cRef++; // AddRefMemStm } errRtn: thkDebugOut((DEB_ITRACE, "%p OUT CreateMemStm16(cb=%lx,phMem=%p) returns %p\n",0,pstm)); return pstm; } // Create CMemStm on top of the specified hMem (which must be a MEMSTM block). // Return pointer to the stream if done, NULL if error. // OLEAPI_(LPSTREAM) CloneMemStm(HANDLE hMem) { return CMemStm::Create(hMem); // Create the stream } OLEAPI_(void) ReleaseMemStm (LPHANDLE phMem, BOOL fInternalOnly) { struct MEMSTM FAR* pData; pData = (MEMSTM FAR*)MAKELONG(0, HIWORD(GlobalHandle(*phMem))); // check for NULL pointer in case handle got freed already // decrement ref count and free if no refs left if (pData != NULL && --pData->cRef == 0) { if (pData->fDeleteOnRelease) { Verify (0==GlobalFree (pData->hGlobal)); } if (!fInternalOnly) { Verify (0==GlobalFree(*phMem)); } } *phMem = NULL; } OLEAPI CreateStreamOnHGlobal (HANDLE hGlobal, BOOL fDeleteOnRelease, LPSTREAM FAR* ppstm) { thkDebugOut((DEB_ITRACE, "%p _IN CreateStreamOnHGlobal16(hGlobal=%x)\n",0,hGlobal)); HANDLE hMem = NULL; // point to struct MEMSTM FAR* pData = NULL; // a struct MEMSTM LPSTREAM pstm = NULL; DWORD cbSize = -1L; VDATEPTRIN (ppstm, LPSTREAM); *ppstm = NULL; if (NULL==hGlobal) { hGlobal = GlobalAlloc(grfMem, 0); if (hGlobal == NULL) goto ErrorExit; cbSize = 0; } else { cbSize = GlobalSize (hGlobal); // Is there a way to verify a zero-sized handle? if (cbSize!=0) { // verify validity of passed-in handle if (NULL==GlobalLock(hGlobal)) { // bad handle return ResultFromScode (E_INVALIDARG); } GlobalUnlock (hGlobal); } } hMem = GlobalAlloc (grfMem, sizeof (MEMSTM)); if (hMem == NULL) goto ErrorExit; pData = (MEMSTM FAR*)MAKELONG(0, HIWORD(GlobalHandle(hMem))); if (pData == NULL) goto FreeMem; pData->cRef = 0; pData->cb = cbSize; pData->fDeleteOnRelease = fDeleteOnRelease; pData->hGlobal = hGlobal; pstm = CMemStm::Create(hMem); if (pstm == NULL) goto FreeMem; *ppstm = pstm; thkDebugOut((DEB_ITRACE, "%p OUT CreateStreamOnHGlobal16() returns NOERROR\n",0)); return NOERROR; FreeMem: if (hMem) { Verify(0==GlobalFree(hMem)); } ErrorExit: Assert (0); thkDebugOut((DEB_ITRACE, "%p OUT CreateStreamOnHGlobal16() returns E_OUTOFMEMORY\n",0)); return ReportResult(0, E_OUTOFMEMORY, 0, 0); } OLEAPI GetHGlobalFromStream (LPSTREAM pstm, HGLOBAL FAR* phglobal) { VDATEIFACE (pstm); VDATEPTRIN (phglobal, HANDLE); CMemStm FAR* pCMemStm = (CMemStm FAR*) pstm; if (IsBadReadPtr (&(pCMemStm->m_dwSig), sizeof(ULONG)) || pCMemStm->m_dwSig != STREAM_SIG) { // we were passed someone else's implementation of ILockBytes return ResultFromScode (E_INVALIDARG); } MEMSTM FAR* pMem= pCMemStm->m_pData; if (NULL==pMem) { Assert (0); return ResultFromScode (E_OUTOFMEMORY); } Assert (pMem->cb <= GlobalSize (pMem->hGlobal)); Verify (*phglobal = pMem->hGlobal); return NOERROR; } ////////////////////////////////////////////////////////////////////////// // // Shared memory ILockBytes implementation // OLEMETHODIMP CMemBytes::QueryInterface(REFIID iidInterface, void FAR* FAR* ppvObj) { M_PROLOG(this); HRESULT error; VDATEPTROUT( ppvObj, LPVOID ); *ppvObj = NULL; VDATEIID( iidInterface ); // Two interfaces supported: IUnknown, ILockBytes if (m_pData != NULL && (iidInterface == IID_ILockBytes || iidInterface == IID_IUnknown)) { m_refs++; // A pointer to this object is returned *ppvObj = this; error = NOERROR; } else // // BUGBUG - See comment above for CMemStm::Queryinterface and IID_IMarshal // #ifdef BOBDAY_DISABLE_MARSHAL_FOR_NOW #else if (iidInterface == IID_IMarshal) { *ppvObj = (LPVOID) CMarshalMemBytes::Create(this); if (*ppvObj != NULL) error = NOERROR; else error = ReportResult(0, E_OUTOFMEMORY, 0, 0); } else #endif { // Not accessible or unsupported interface *ppvObj = NULL; error = ReportResult(0, E_NOINTERFACE, 0, 0); } return error; } // Called when CMemBytes is referenced by an additional pointer. // OLEMETHODIMP_(ULONG) CMemBytes::AddRef(void) { M_PROLOG(this); return ++m_refs; } // Called when a pointer to this CMemBytes is discarded // OLEMETHODIMP_(ULONG) CMemBytes::Release(void) { M_PROLOG(this); if (--m_refs != 0) // Still used by others return m_refs; ReleaseMemStm(&m_hMem); delete this; // Free storage return 0; } OLEMETHODIMP CMemBytes::ReadAt(ULARGE_INTEGER ulOffset, void HUGEP* pb, ULONG cb, ULONG FAR* pcbRead) { M_PROLOG(this); HRESULT error = NOERROR; ULONG cbRead = cb; VDATEPTROUT( pb, char ); if (pcbRead) { VDATEPTROUT( pcbRead, ULONG ); *pcbRead = 0L; } if (cbRead + ulOffset.LowPart > m_pData->cb) { if (ulOffset.LowPart > m_pData->cb) cbRead = 0; else cbRead = m_pData->cb - ulOffset.LowPart; } if (cbRead > 0) { char HUGEP* pGlobal = GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { Assert (0); return ResultFromScode (STG_E_READFAULT); } UtMemCpy (pb, pGlobal + ulOffset.LowPart, cbRead); GlobalUnlock (m_pData->hGlobal); } if (pcbRead != NULL) *pcbRead = cbRead; return error; } OLEMETHODIMP CMemBytes::WriteAt(ULARGE_INTEGER ulOffset, void const HUGEP* pb, ULONG cb, ULONG FAR* pcbWritten) { A5_PROLOG(this); HRESULT error = NOERROR; ULONG cbWritten = cb; char HUGEP* pGlobal; VDATEPTRIN( pb, char ); if (pcbWritten) { VDATEPTROUT( pcbWritten, ULONG ); *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; } pGlobal = GlobalLock (m_pData->hGlobal); if (NULL==pGlobal) { Assert (0); return ResultFromScode (STG_E_WRITEFAULT); } UtMemCpy (pGlobal + ulOffset.LowPart, pb, cbWritten); GlobalUnlock (m_pData->hGlobal); if (pcbWritten != NULL) *pcbWritten = cbWritten; Exit: RESTORE_A5(); return error; } OLEMETHODIMP CMemBytes::Flush(void) { M_PROLOG(this); return NOERROR; } OLEMETHODIMP CMemBytes::SetSize(ULARGE_INTEGER cb) { M_PROLOG(this); HANDLE hMemNew; if (m_pData->cb == cb.LowPart) return NOERROR; hMemNew = GlobalReAlloc(m_pData->hGlobal, max (cb.LowPart, 1), grfMem); if (hMemNew == NULL) return ReportResult(0, E_OUTOFMEMORY, 0, 0); m_pData->hGlobal = hMemNew; m_pData->cb = cb.LowPart; return NOERROR; } OLEMETHODIMP CMemBytes::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { // REVIEW - Docfile bug. Must return NOERROR for StgCreateDocfileOnILockbytes M_PROLOG(this); return NOERROR; } OLEMETHODIMP CMemBytes::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { // REVIEW - Docfiel bug. Must return NOERROR for StgCreateDocfileOnILockbytes M_PROLOG(this); return NOERROR; } OLEMETHODIMP CMemBytes::Stat(STATSTG FAR *pstatstg, DWORD statflag) { M_PROLOG(this); VDATEPTROUT( pstatstg, STATSTG ); 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; pstatstg->reserved = 0; return NOERROR; } // Create CMemBytes. Handle must be a MEMSTM block. // OLESTATICIMP_(CMemBytes FAR*) CMemBytes::Create(HANDLE hMem) { CMemBytes FAR* pCMemBytes; struct MEMSTM FAR* pData; pData = (MEMSTM FAR*)MAKELONG(0, HIWORD(GlobalHandle(hMem))); if (pData == NULL) return NULL; Assert (pData->hGlobal); pCMemBytes = new CMemBytes; if (pCMemBytes == NULL) return NULL; // Initialize CMemBytes // pCMemBytes->m_dwSig = LOCKBYTE_SIG; pCMemBytes->m_hMem = hMem; (pCMemBytes->m_pData = pData)->cRef++; // AddRefMemStm pCMemBytes->m_refs = 1; return pCMemBytes; } // CMemStm object's IMarshal implementation // OLEMETHODIMP CMarshalMemStm::QueryInterface(REFIID iidInterface, void FAR* FAR* ppvObj) { M_PROLOG(this); HRESULT error; VDATEPTROUT( ppvObj, LPVOID ); *ppvObj = NULL; VDATEIID( iidInterface ); // Two interfaces supported: IUnknown, IMarshal if (iidInterface == IID_IMarshal || iidInterface == IID_IUnknown) { 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; } // Called when CMarshalMemStm is referenced by an additional pointer. // OLEMETHODIMP_(ULONG) CMarshalMemStm::AddRef(void) { M_PROLOG(this); return ++m_refs; } // Called when a pointer to this CMarshalMemStm is discarded // OLEMETHODIMP_(ULONG) CMarshalMemStm::Release(void) { M_PROLOG(this); if (--m_refs != 0) // Still used by others return m_refs; if (m_pMemStm != NULL) m_pMemStm->Release(); delete this; // Free storage return 0; } // Returns the clsid of the object that created this CMarshalMemStm. // OLEMETHODIMP CMarshalMemStm::GetUnmarshalClass(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID FAR* pCid) { M_PROLOG(this); VDATEPTROUT( pCid, CLSID); VDATEIID( riid ); *pCid = m_clsid; return NOERROR; } OLEMETHODIMP CMarshalMemStm::GetMarshalSizeMax(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD FAR* pSize) { M_PROLOG(this); VDATEIID( riid ); VDATEIFACE( pv ); if (pSize) { VDATEPTROUT( pSize, DWORD ); *pSize = NULL; } *pSize = sizeof(m_pMemStm->m_hMem); return NOERROR; } OLEMETHODIMP CMarshalMemStm::MarshalInterface(IStream FAR* pStm, REFIID riid, void FAR* pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) { M_PROLOG(this); VDATEPTRIN( pStm, IStream ); VDATEIID( riid ); VDATEIFACE( pv ); if (m_pMemStm == NULL) return ReportResult(0, E_UNSPEC, 0, 0); if ((riid != IID_IStream && 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) m_pMemStm->m_pData->cRef++; // AddRefMemStm return error; } OLEMETHODIMP CMarshalMemStm::UnmarshalInterface(IStream FAR* pStm, REFIID riid, void FAR* FAR* ppv) { M_PROLOG(this); HRESULT error; HANDLE hMem; VDATEPTROUT( ppv, LPVOID ); *ppv = NULL; VDATEPTRIN( pStm, IStream ); VDATEIID( riid ); if (riid != IID_IStream && riid != IID_IUnknown) return ReportResult(0, E_INVALIDARG, 0, 0); error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error != NOERROR) return error; if (m_pMemStm != NULL) { if (hMem != m_pMemStm->m_hMem) return ReportResult(0, E_UNSPEC, 0, 0); } else { m_pMemStm = (CMemStm FAR*) CloneMemStm(hMem); if (m_pMemStm == NULL) return ReportResult(0, E_OUTOFMEMORY, 0, 0); } m_pMemStm->AddRef(); *ppv = (LPVOID) m_pMemStm; return NOERROR; } OLEMETHODIMP CMarshalMemStm::ReleaseMarshalData(IStream FAR* pStm) { M_PROLOG(this); // 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; } OLEMETHODIMP CMarshalMemStm::DisconnectObject(DWORD dwReserved) { M_PROLOG(this); return NOERROR; } OLESTATICIMP_(CMarshalMemStm FAR*) CMarshalMemStm::Create(CMemStm FAR* pMemStm) { CMarshalMemStm FAR* pMMS; //VDATEPTRIN rejects NULL if( pMemStm ) GEN_VDATEPTRIN( pMemStm, CMemStm, (CMarshalMemStm FAR *) NULL ); 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; } OLEAPI_(IUnknown FAR*) CMemStmUnMarshal(void) { return CMarshalMemStm::Create(NULL); } // CMemBytes object's IMarshal implementation // OLEMETHODIMP CMarshalMemBytes::QueryInterface(REFIID iidInterface, void FAR* FAR* ppvObj) { M_PROLOG(this); HRESULT error; VDATEIID( iidInterface ); VDATEPTROUT( ppvObj, LPVOID ); *ppvObj = NULL; // Two interfaces supported: IUnknown, IMarshal if (iidInterface == IID_IMarshal || iidInterface == IID_IUnknown) { 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; } // Called when CMarshalMemBytes is referenced by an additional pointer. // OLEMETHODIMP_(ULONG) CMarshalMemBytes::AddRef(void) { M_PROLOG(this); return ++m_refs; } // Called when a pointer to this CMarshalMemBytes is discarded // OLEMETHODIMP_(ULONG) CMarshalMemBytes::Release(void) { M_PROLOG(this); 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. // OLEMETHODIMP CMarshalMemBytes::GetUnmarshalClass(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, CLSID FAR* pCid) { M_PROLOG(this); VDATEIID( riid ); VDATEIFACE( pv ); *pCid = m_clsid; return NOERROR; } OLEMETHODIMP CMarshalMemBytes::GetMarshalSizeMax(REFIID riid, LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags, DWORD FAR* pSize) { M_PROLOG(this); VDATEPTROUT( pSize, DWORD ); VDATEIID( riid ); VDATEIFACE( pv ); *pSize = sizeof(m_pMemBytes->m_hMem); return NOERROR; } OLEMETHODIMP CMarshalMemBytes::MarshalInterface(IStream FAR* pStm, REFIID riid, void FAR* pv, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) { M_PROLOG(this); VDATEPTRIN(pStm, IStream ); VDATEIID( riid ); if ( pv ) VDATEPTRIN( pv , char ); if (m_pMemBytes == NULL) return ReportResult(0, E_UNSPEC, 0, 0); if ((riid != IID_ILockBytes && 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) m_pMemBytes->m_pData->cRef++; // AddRefMemStm return error; } OLEMETHODIMP CMarshalMemBytes::UnmarshalInterface(IStream FAR* pStm, REFIID riid, void FAR* FAR* ppv) { M_PROLOG(this); HRESULT error; HANDLE hMem; VDATEPTROUT( ppv , LPVOID ); *ppv = NULL; VDATEIFACE( pStm ); VDATEIID( riid ); if (riid != IID_ILockBytes && 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; } OLEMETHODIMP CMarshalMemBytes::ReleaseMarshalData(IStream FAR* pStm) { // reduce ref count on hglobal (matches that done in MarshalInterface) M_PROLOG(this); HRESULT error; MEMSTM FAR* pData; HANDLE hMem; VDATEIFACE( pStm ); error = pStm->Read(&hMem,sizeof(hMem),NULL); if (error == NOERROR) ReleaseMemStm(&hMem); return error; } OLEMETHODIMP CMarshalMemBytes::DisconnectObject(DWORD dwReserved) { M_PROLOG(this); return NOERROR; } OLESTATICIMP_(CMarshalMemBytes FAR*) CMarshalMemBytes::Create( CMemBytes FAR* pMemBytes) { CMarshalMemBytes FAR* pMMB; //VDATEPTRIN rejects NULL if( pMemBytes ) GEN_VDATEPTRIN( pMemBytes, CMemBytes, (CMarshalMemBytes FAR *)NULL ); 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; } OLEAPI_(IUnknown FAR*) CMemBytesUnMarshal(void) { return CMarshalMemBytes::Create(NULL); }