|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: hpalette.cxx
//
// Contents: Support for Windows/OLE data types for oleprx32.dll.
// Used to be transmit_as routines, now user_marshal routines.
//
// This file contains support for STGMEDIUM, FLAG_STGMEDIUM, and
// ASYNC_STGMEDIUM.
//
// Functions:
// STGMEDIUM_UserSize
// STGMEDIUM_UserMarshal
// STGMEDIUM_UserUnmarshal
// STGMEDIUM_UserFree
// STGMEDIUM_UserSize64
// STGMEDIUM_UserMarshal64
// STGMEDIUM_UserUnmarshal64
// STGMEDIUM_UserFree64
// FLAG_STGMEDIUM_UserSize
// FLAG_STGMEDIUM_UserMarshal
// FLAG_STGMEDIUM_UserUnmarshal
// FLAG_STGMEDIUM_UserFree
// FLAG_STGMEDIUM_UserSize64
// FLAG_STGMEDIUM_UserMarshal64
// FLAG_STGMEDIUM_UserUnmarshal64
// FLAG_STGMEDIUM_UserFree64
// ASYNC_STGMEDIUM_UserSize
// ASYNC_STGMEDIUM_UserMarshal
// ASYNC_STGMEDIUM_UserUnmarshal
// ASYNC_STGMEDIUM_UserFree
// ASYNC_STGMEDIUM_UserSize64
// ASYNC_STGMEDIUM_UserMarshal64
// ASYNC_STGMEDIUM_UserUnmarshal64
// ASYNC_STGMEDIUM_UserFree64
//
// History: 13-Dec-00 JohnDoty Migrated from transmit.cxx,
// created NDR64 functions
//
//--------------------------------------------------------------------------
#include "stdrpc.hxx"
#pragma hdrstop
#include <oleauto.h>
#include <objbase.h>
#include "transmit.hxx"
#include <rpcwdt.h>
#include <storext.h>
#include <valid.h>
#include <obase.h>
#include <stream.hxx>
#include "carefulreader.hxx"
// PROTOTYPES FOR OTHER USERMARSHAL ROUTINES, TO HELP US!
EXTERN_C unsigned long __stdcall __RPC_USER WdtpInterfacePointer_UserSize (USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned long Offset, IUnknown *pIf, const IID &IId ); EXTERN_C unsigned char __RPC_FAR * __RPC_USER __stdcall WdtpInterfacePointer_UserMarshal (USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned char *pBuffer, IUnknown *pIf, const IID &IId ); EXTERN_C unsigned long __stdcall __RPC_USER WdtpInterfacePointer_UserSize64 (USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned long Offset, IUnknown *pIf, const IID &IId ); EXTERN_C unsigned char __RPC_FAR * __RPC_USER __stdcall WdtpInterfacePointer_UserMarshal64 (USER_MARSHAL_CB * pContext, unsigned long Flags, unsigned char *pBuffer, IUnknown *pIf, const IID &IId ); unsigned char __RPC_FAR * __RPC_USER WdtpInterfacePointer_UserUnmarshalWorker (USER_MARSHAL_CB * pContext, unsigned char * pBuffer, IUnknown ** ppIf, const IID &IId, ULONG_PTR BufferSize, BOOL fNDR64 );
unsigned char __RPC_FAR * __RPC_USER HMETAFILEPICT_UserUnmarshalWorker (unsigned long * pFlags, unsigned char * pBuffer, HMETAFILEPICT * pHMetaFilePict, ULONG_PTR BufferSize); unsigned char __RPC_FAR * __RPC_USER HMETAFILEPICT_UserUnmarshalWorker64 (unsigned long * pFlags, unsigned char * pBuffer, HMETAFILEPICT * pHMetaFilePict, ULONG_PTR BufferSize);
unsigned char __RPC_FAR * __RPC_USER HENHMETAFILE_UserUnmarshalWorker (unsigned long * pFlags, unsigned char * pBuffer, HENHMETAFILE * pHMetaFilePict, ULONG_PTR BufferSize); unsigned char __RPC_FAR * __RPC_USER HENHMETAFILE_UserUnmarshalWorker64 (unsigned long * pFlags, unsigned char * pBuffer, HENHMETAFILE * pHMetaFilePict, ULONG_PTR BufferSize);
unsigned char __RPC_FAR * __RPC_USER HBITMAP_UserUnmarshalWorker (unsigned long * pFlags, unsigned char * pBuffer, HBITMAP * pHMetaFilePict, ULONG_PTR BufferSize); unsigned char __RPC_FAR * __RPC_USER HBITMAP_UserUnmarshalWorker64 (unsigned long * pFlags, unsigned char * pBuffer, HBITMAP * pHMetaFilePict, ULONG_PTR BufferSize);
unsigned char __RPC_FAR * __RPC_USER HPALETTE_UserUnmarshalWorker (unsigned long * pFlags, unsigned char * pBuffer, HPALETTE * pHMetaFilePict, ULONG_PTR BufferSize); unsigned char __RPC_FAR * __RPC_USER HPALETTE_UserUnmarshalWorker64 (unsigned long * pFlags, unsigned char * pBuffer, HPALETTE * pHMetaFilePict, ULONG_PTR BufferSize);
unsigned char __RPC_FAR * __RPC_USER WdtpGlobalUnmarshal (unsigned long * pFlags, unsigned char * pBuffer, HGLOBAL * pGlobal, BOOL fCanReallocate, ULONG_PTR BufferSize); unsigned char __RPC_FAR * __RPC_USER WdtpGlobalUnmarshal64 (unsigned long * pFlags, unsigned char * pBuffer, HGLOBAL * pGlobal, BOOL fCanReallocate, ULONG_PTR BufferSize);
//+-------------------------------------------------------------------------
//
// class: CPunkForRelease
//
// purpose: special IUnknown for remoted STGMEDIUMs
//
// history: 02-Mar-94 Rickhi Created
//
// notes: This class is used to do the cleanup correctly when certain
// types of storages are passed between processes or machines
// in Nt and Chicago.
//
// On NT, GLOBAL, GDI, and BITMAP handles cannot be passed between
// processes, so we actually copy the whole data and create a
// new handle in the receiving process. However, STGMEDIUMs have
// this weird behaviour where if PunkForRelease is non-NULL then
// the sender is responsible for cleanup, not the receiver. Since
// we create a new handle in the receiver, we would leak handles
// if we didnt do some special processing. So, we do the
// following...
//
// During STGMEDIUM_UserUnmarshal, if there is a pUnkForRelease
// replace it with a CPunkForRelease. When Release is called
// on the CPunkForRelease, do the necessary cleanup work,
// then call the real PunkForRelease.
//
//+-------------------------------------------------------------------------
class CPunkForRelease : public IUnknown { public: CPunkForRelease( STGMEDIUM *pStgMed, ulong fTopLayerOnly);
// IUnknown Methods
STDMETHOD(QueryInterface)(REFIID riid, void **ppunk); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void);
private: ~CPunkForRelease(void);
ULONG _cRefs; // reference count
ULONG _fTopLayerMFP:1; // optimisation flag for Chicago
STGMEDIUM _stgmed; // storage medium
IUnknown * _pUnkForRelease; // real pUnkForRelease
};
inline CPunkForRelease::CPunkForRelease( STGMEDIUM * pStgMed, ulong fTopLayerMFPict ) : _cRefs(1), _fTopLayerMFP( fTopLayerMFPict), _stgmed(*pStgMed) { // NOTE: we assume the caller has verified pStgMed is not NULL,
// and the pUnkForRelease is non-null, otherwise there is no
// point in constructing this object. The tymed must also be
// one of the special ones.
UserNdrAssert(pStgMed); UserNdrAssert(pStgMed->tymed == TYMED_HGLOBAL || pStgMed->tymed == TYMED_GDI || pStgMed->tymed == TYMED_MFPICT || pStgMed->tymed == TYMED_ENHMF);
_pUnkForRelease = pStgMed->pUnkForRelease; }
inline CPunkForRelease::~CPunkForRelease() { // since we really have our own copies of these handles' data, just
// pretend like the callee is responsible for the release, and
// recurse into ReleaseStgMedium to do the cleanup.
_stgmed.pUnkForRelease = NULL;
// There is this weird optimized case of Chicago MFPICT when we have two
// layers with a HENHMETAFILE handle inside. Top layer is an HGLOBAL.
if ( _fTopLayerMFP ) GlobalFree( _stgmed.hGlobal ); else ReleaseStgMedium( &_stgmed );
// release the callers punk
_pUnkForRelease->Release(); }
STDMETHODIMP_(ULONG) CPunkForRelease::AddRef(void) { InterlockedIncrement((LONG *)&_cRefs); return _cRefs; }
STDMETHODIMP_(ULONG) CPunkForRelease::Release(void) { long Ref = _cRefs - 1;
UserNdrAssert( _cRefs );
if (InterlockedDecrement((LONG *)&_cRefs) == 0) { // null out the vtable.
long * p = (long *)this; *p = 0;
delete this; return 0; } else return Ref; }
STDMETHODIMP CPunkForRelease::QueryInterface(REFIID riid, void **ppv) { if (IsEqualIID(riid, IID_IUnknown)) { *ppv = (void *)(IUnknown *) this; AddRef(); return S_OK; } else { *ppv = NULL; return E_NOINTERFACE; } }
//+-------------------------------------------------------------------------
//
// Function: SetContextFlagsForAsyncCall
//
// Synopsis: Forces correct flags for an async stgmed call.
//
// history: May-97 Ryszardk Created.
//
// We used to force MSHCTX_DIFFERENTMACHINE context on every
// async stgmedium call because of problems with handles - for a truly
// async call passing a handle, the client may free the handle before
// the server can use it.
// That is still needed. However, we cannot force the different machine
// flags on IStream and IStorage as that prevents custom marshaler from
// running.
//
//--------------------------------------------------------------------------
void inline SetContextFlagsForAsyncCall( unsigned long * pFlags, STGMEDIUM * pStgmed ) { if ( *pFlags & USER_CALL_IS_ASYNC ) { // Additional considerations for async calls.
switch( pStgmed->tymed ) { case TYMED_NULL: case TYMED_MFPICT: case TYMED_ENHMF: case TYMED_GDI: case TYMED_HGLOBAL: case TYMED_FILE: default: if (!REMOTE_CALL(*pFlags)) { *pFlags &= ~0xff; *pFlags |= MSHCTX_DIFFERENTMACHINE; } break;
case TYMED_ISTREAM: case TYMED_ISTORAGE: // Dont force remote.
break;
} } }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserSize
//
// Synopsis: Sizes a stgmedium pbject for RPC marshalling.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER STGMEDIUM_UserSize( unsigned long * pFlags, unsigned long Offset, STGMEDIUM * pStgmed ) { if ( ! pStgmed ) return Offset;
LENGTH_ALIGN( Offset, 3 );
// Both handle and pUnk are represented by a long.
if ( pStgmed->tymed == TYMED_NULL ) Offset += sizeof(long) + sizeof(long); // switch, (empty arm), pUnk
else Offset += sizeof(long) + 2 * sizeof(long); // switch, handle, pUnk
// Pointee of the union arm.
// Only if the handle/pointer field is non-null.
if ( pStgmed->hGlobal ) { SetContextFlagsForAsyncCall( pFlags, pStgmed );
switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: Offset = HMETAFILEPICT_UserSize( pFlags, Offset, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: Offset = HENHMETAFILE_UserSize( pFlags, Offset, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI:
// A GDI object is not necesarrily a BITMAP. Therefore, we handle
// those types we know about based on the object type, and reject
// those which we do not support.
// switch for object type.
Offset += sizeof(long);
switch( GetObjectType( (HGDIOBJ)pStgmed->hBitmap ) ) { case OBJ_BITMAP: Offset = HBITMAP_UserSize( pFlags, Offset, &pStgmed->hBitmap ); break;
case OBJ_PAL: Offset = HPALETTE_UserSize( pFlags, Offset, (HPALETTE *) & pStgmed->hBitmap ); break;
default: RAISE_RPC_EXCEPTION(DV_E_TYMED); break; } break;
case TYMED_HGLOBAL: Offset = HGLOBAL_UserSize( pFlags, Offset, &pStgmed->hGlobal ); break; case TYMED_FILE: { ulong ulDataSize = lstrlenW(pStgmed->lpszFileName) + 1; Offset += 3 * sizeof(long); // [string]
Offset += ulDataSize * sizeof(wchar_t); } break;
case TYMED_ISTREAM: case TYMED_ISTORAGE: Offset = WdtpInterfacePointer_UserSize( (USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pstg, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage)); break;
default: break;
} }
// pUnkForRelease, if not null.
if ( pStgmed->pUnkForRelease ) Offset = WdtpInterfacePointer_UserSize( (USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pUnkForRelease, IID_IUnknown );
return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserMarshal
//
// Synopsis: Marshals a stgmedium pbject for RPC.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserMarshal( unsigned long * pFlags, unsigned char * pBufferStart, STGMEDIUM * pStgmed ) { unsigned char * pBuffer; unsigned char * pUnionArmMark;
if ( ! pStgmed ) return pBufferStart;
UserNdrDebugOut(( UNDR_FORCE, "--STGMEDIUM_UserMarshal: %s\n", WdtpGetStgmedName(pStgmed)));
pBuffer = pBufferStart; ALIGN( pBuffer, 3 );
// userSTGMEDIUM: switch, union arm, pUnk ptr.
*( PULONG_LV_CAST pBuffer)++ = pStgmed->tymed; pUnionArmMark = pBuffer; if ( pStgmed->tymed != TYMED_NULL ) { // hGlobal stands for any of these handles.
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( pStgmed->hGlobal ); }
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( pStgmed->pUnkForRelease );
// Now the pointee of the union arm.
// We need to marshal only if the handle/pointer field is non null.
// Otherwise it is already in the buffer.
if ( pStgmed->hGlobal ) { SetContextFlagsForAsyncCall( pFlags, pStgmed );
switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: pBuffer = HMETAFILEPICT_UserMarshal( pFlags, pBuffer, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: pBuffer = HENHMETAFILE_UserMarshal( pFlags, pBuffer, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI:
{ // A GDI object is not necesarrily a BITMAP. Therefore, we handle
// those types we know about based on the object type, and reject
// those which we do not support.
ulong GdiObjectType = GetObjectType( (HGDIOBJ)pStgmed->hBitmap );
// GDI_OBJECT
*( PULONG_LV_CAST pBuffer)++ = GdiObjectType;
switch( GdiObjectType ) { case OBJ_BITMAP: pBuffer = HBITMAP_UserMarshal( pFlags, pBuffer, &pStgmed->hBitmap ); break;
case OBJ_PAL: pBuffer = HPALETTE_UserMarshal( pFlags, pBuffer, (HPALETTE *) & pStgmed->hBitmap ); break;
default: RpcRaiseException(DV_E_TYMED); } } break;
case TYMED_HGLOBAL: pBuffer = HGLOBAL_UserMarshal( pFlags, pBuffer, & pStgmed->hGlobal ); break; case TYMED_FILE: { // We marshal it as a [string].
ulong Count = (pStgmed->lpszFileName) ? lstrlenW(pStgmed->lpszFileName) + 1 : 0;
*( PULONG_LV_CAST pBuffer)++ = Count; *( PULONG_LV_CAST pBuffer)++ = 0; *( PULONG_LV_CAST pBuffer)++ = Count; memcpy( pBuffer, pStgmed->lpszFileName, Count * sizeof(wchar_t) ); pBuffer += Count * sizeof(wchar_t); } break;
case TYMED_ISTREAM: case TYMED_ISTORAGE: pBuffer = WdtpInterfacePointer_UserMarshal( ((USER_MARSHAL_CB *)pFlags), *pFlags, pBuffer, pStgmed->pstg, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage)); break;
default: break; } }
// Marker for this pointer is already in the buffer.
if ( pStgmed->pUnkForRelease ) pBuffer = WdtpInterfacePointer_UserMarshal( ((USER_MARSHAL_CB *)pFlags ), *pFlags, pBuffer, pStgmed->pUnkForRelease, IID_IUnknown );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserUnmarshalWorker
//
// Synopsis: Unmarshals a stgmedium object for RPC.
//
// history: Aug-99 JohnStra Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserUnmarshalWorker( unsigned long * pFlags, unsigned char * pBuffer, STGMEDIUM * pStgmed, ULONG_PTR BufferSize ) { unsigned long fUnkForRelease; LONG_PTR Handle = 0;
// Align the buffer and save the fixup size.
UCHAR* pBufferStart = pBuffer; ALIGN( pBuffer, 3 ); ULONG_PTR cbFixup = (ULONG_PTR) (pBuffer - pBufferStart);
// Check for EOB.
CHECK_BUFFER_SIZE( BufferSize, cbFixup + sizeof( ULONG ) );
// switch, union arm, pUnk.
pStgmed->tymed = *( PULONG_LV_CAST pBuffer)++;
UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s\n", WdtpGetStgmedName(pStgmed) ));
ULONG_PTR cbData = cbFixup + (2 * sizeof( ULONG )); if ( pStgmed->tymed != TYMED_NULL ) { cbData += sizeof( ULONG );
CHECK_BUFFER_SIZE( BufferSize, cbData );
// This value is just a marker for the handle - a long.
Handle = *( PLONG_LV_CAST pBuffer)++; } else { CHECK_BUFFER_SIZE( BufferSize, cbData ); }
// pUnkForRelease pointer marker.
fUnkForRelease = *( PULONG_LV_CAST pBuffer)++;
// First pointee
// Union arm pointee.
// We need to unmarshal only if the handle/pointer field was not NULL.
if ( Handle ) { SetContextFlagsForAsyncCall( pFlags, pStgmed );
LONG* pBuf = (LONG*)pBuffer;
switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT:
#if defined(_WIN64)
if ( IS_DATA_MARKER( pBuf[0] ) ) { CHECK_BUFFER_SIZE( BufferSize, cbData + (2 * sizeof( ULONG )) );
if ( Handle != pBuf[1] ) { RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } } else { //Inproc should always have marked this as handle64....
//Out-of-proc should always have marked this with a data marker....
if (!IS_HANDLE64_MARKER(pBuf[0])) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
// Align to 64b.
PBYTE pbBuf = (PBYTE)( pBuf + 1 ); PBYTE pbBufStart = pbBuf; ALIGN( pbBuf, 7 );
// Make sure we don't step off the end of the buffer.
CHECK_BUFFER_SIZE( BufferSize, cbData + (ULONG_PTR)(pbBuf - pbBufStart) + (sizeof(__int64)) );
// Verify that the handle put on the wire matches the
// first instance of the handle on the wire.
if ( Handle != (LONG_PTR) (*(LONG *)pbBuf ) ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } #else
CHECK_BUFFER_SIZE( BufferSize, cbData + (2 * sizeof(ULONG)) );
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); #endif
pBuffer = HMETAFILEPICT_UserUnmarshalWorker( pFlags, pBuffer, &pStgmed->hMetaFilePict, BufferSize - cbData ); break; case TYMED_ENHMF: // Must be room in buffer to do lookahead check.
CHECK_BUFFER_SIZE( BufferSize, cbData + (2 * sizeof( ULONG )) );
// validate the handle.
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
pBuffer = HENHMETAFILE_UserUnmarshalWorker( pFlags, pBuffer, &pStgmed->hEnhMetaFile, BufferSize - cbData ); break; case TYMED_GDI: { // A GDI object is not necesarrily a BITMAP. Therefore, we
// handle those types we know about based on the object type,
// and reject those which we do not support.
// Make sure we don't walk off the end of the buffer.
CHECK_BUFFER_SIZE( BufferSize, cbData + (3 * sizeof( ULONG )) );
cbData += sizeof( ULONG );
DWORD GdiObjectType = *( PULONG_LV_CAST pBuffer)++;
switch( GdiObjectType ) { case OBJ_BITMAP: // Lookahead validaton of the handle. We look at
// the 3rd DWORD: GDI type, DISC, Handle.
if ( Handle != pBuf[2] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
pBuffer = HBITMAP_UserUnmarshalWorker( pFlags, pBuffer, &pStgmed->hBitmap, BufferSize - cbData ); break;
case OBJ_PAL: // Lookahead validaton of the handle.
if ( Handle != pBuf[2] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
pBuffer = HPALETTE_UserUnmarshalWorker( pFlags, pBuffer, (HPALETTE *) & pStgmed->hBitmap, BufferSize - cbData ); break;
default: RAISE_RPC_EXCEPTION(DV_E_TYMED); } } break;
case TYMED_HGLOBAL: { // reallocation is forbidden for [in-out] hglobal in STGMEDIUM.
#if defined(_WIN64)
if ( IS_DATA_MARKER( pBuf[0] ) ) { CHECK_BUFFER_SIZE( BufferSize, cbData + (2 * sizeof( ULONG )) );
if ( Handle != pBuf[1] ) { RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } } else { // Align to 64b.
PBYTE pbBuf = (PBYTE)( pBuf + 1 ); PBYTE pbBufStart = pbBuf; ALIGN( pbBuf, 7 );
// Make sure we don't step off the end of the buffer.
CHECK_BUFFER_SIZE( BufferSize, cbData + (ULONG_PTR)(pbBuf - pbBufStart) + (sizeof(__int64)) );
// Verify that the handle put on the wire matches the
// first instance of the handle on the wire.
if ( Handle != (LONG_PTR) (*(LONG *)pbBuf ) ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } #else
CHECK_BUFFER_SIZE( BufferSize, cbData + (2 * sizeof(ULONG)) );
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); #endif
pBuffer = WdtpGlobalUnmarshal( pFlags, pBuffer, & pStgmed->hGlobal, FALSE, BufferSize - cbData); break; } case TYMED_FILE: { // Must be room in buffer for header.
CHECK_BUFFER_SIZE( BufferSize, cbData + (3 * sizeof(ULONG)) );
// We marshal it as a [string].
ulong Count = *( PULONG_LV_CAST pBuffer)++; if ( *( PULONG_LV_CAST pBuffer)++ != 0 || *( PULONG_LV_CAST pBuffer)++ != Count ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
if ( ! pStgmed->lpszFileName ) { pStgmed->lpszFileName = (LPOLESTR) WdtpAllocate( pFlags, Count * sizeof(wchar_t) ); if (!pStgmed->lpszFileName) RpcRaiseException( E_OUTOFMEMORY ); }
// Must be room in the buffer for the string.
CHECK_BUFFER_SIZE( BufferSize, cbData + (3 * sizeof( ULONG )) + (Count * sizeof( wchar_t )) );
memcpy(pStgmed->lpszFileName, pBuffer, Count * sizeof(wchar_t)); pBuffer += Count * sizeof(wchar_t); } break;
case TYMED_ISTREAM: case TYMED_ISTORAGE: // Non null pointer, retrieve the interface pointer
pBuffer = WdtpInterfacePointer_UserUnmarshalWorker( (USER_MARSHAL_CB *)pFlags, pBuffer, (IUnknown **) &pStgmed->pstm, ((pStgmed->tymed == TYMED_ISTREAM) ? IID_IStream : IID_IStorage), BufferSize - cbData, FALSE ); break;
default: break; } } else { // New handle/pointer field is null, so release the previous one
// if it wasn't null.
if ( pStgmed->hGlobal ) { // This should never happen for GetDataHere.
// Note, that we release the handle field, not the stgmedium itself.
// Accordingly, we don't follow punkForRelease.
UserNdrDebugOut(( UNDR_FORCE, "--STGMEDIUM_UserUnmarshal: %s: NULL in, freeing old one\n", WdtpGetStgmedName(pStgmed)));
STGMEDIUM TmpStg = *pStgmed; TmpStg.pUnkForRelease = NULL;
if ( pStgmed->tymed == TYMED_HGLOBAL ) { // Cannot reallocate.
RAISE_RPC_EXCEPTION(DV_E_TYMED); } else { ReleaseStgMedium( &TmpStg ); } }
pStgmed->hGlobal = 0; }
// Fixup the buffer size so if fUnkForRelease is set, we
// pass the correct BufferSize to the unmarshal routine.
BufferSize -= (ULONG_PTR)(pBuffer - pBufferStart);
if ( fUnkForRelease ) { // There is an interface pointer on the wire.
pBuffer = WdtpInterfacePointer_UserUnmarshalWorker( (USER_MARSHAL_CB *)pFlags, pBuffer, &pStgmed->pUnkForRelease, IID_IUnknown, BufferSize, FALSE ); }
if ( pStgmed->pUnkForRelease ) { // Replace the app's punkForRelease with our custom release
// handler for special situations.
// The special situation is when a handle is remoted with data
// and so we have to clean up a side effect of having a data copy
// around. UserFree does it properly but we need that for the callee.
// When the callee releases a stgmed, it would invoke
// ReleaseStgMedium and this API doesn't do anything for handles
// when the punkForRelease is not NULL.
ULONG fHandleWithData = 0; ULONG fTopLevelOnly = 0;
switch ( pStgmed->tymed ) { case TYMED_HGLOBAL: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); break;
case TYMED_ENHMF: case TYMED_GDI: fHandleWithData = GDI_DATA_PASSING( *pFlags ); break;
case TYMED_MFPICT: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); fTopLevelOnly = fHandleWithData && ! GDI_DATA_PASSING( *pFlags ); break;
default: break; }
if ( fHandleWithData ) { IUnknown * punkTmp = (IUnknown *) new CPunkForRelease( pStgmed, fTopLevelOnly ); if (!punkTmp) { RAISE_RPC_EXCEPTION(E_OUTOFMEMORY); }
pStgmed->pUnkForRelease = punkTmp; } }
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserUnmarshal
//
// Synopsis: Unmarshals a stgmedium object for RPC.
//
// history: May-95 Ryszardk Created.
// Aug-99 JohnStra Factored bulk of code out into a
// worker routine in order to add
// consistency checks.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserUnmarshal( unsigned long * pFlags, unsigned char * pBuffer, STGMEDIUM * pStgmed ) { // Init buffer size and ptr to buffer.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); ULONG_PTR BufferSize = MarshalInfo.GetBufferSize(); UCHAR* pBufferStart = MarshalInfo.GetBuffer();
pBuffer = STGMEDIUM_UserUnmarshalWorker( pFlags, pBufferStart, pStgmed, BufferSize ); return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserFree
//
// Synopsis: Frees a stgmedium object for RPC.
//
// history: May-95 Ryszardk Created.
//
// Note: This routine is called from the freeing walk at server
// or from the SetData *proxy*, when ownership has been passed.
//
//--------------------------------------------------------------------------
EXTERN_C void NukeHandleAndReleasePunk( STGMEDIUM * pStgmed ) { pStgmed->hGlobal = NULL; pStgmed->tymed = TYMED_NULL;
if (pStgmed->pUnkForRelease) { pStgmed->pUnkForRelease->Release(); pStgmed->pUnkForRelease = 0; } }
void __RPC_USER STGMEDIUM_UserFree( unsigned long * pFlags, STGMEDIUM * pStgmed ) { UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserFree: %s\n", WdtpGetStgmedName(pStgmed)));
if( pStgmed ) { SetContextFlagsForAsyncCall( pFlags, pStgmed );
switch ( pStgmed->tymed ) { case TYMED_FILE: WdtpFree( pFlags, pStgmed->lpszFileName); NukeHandleAndReleasePunk( pStgmed ); break;
case TYMED_NULL: case TYMED_ISTREAM: case TYMED_ISTORAGE: ReleaseStgMedium( pStgmed ); break;
case TYMED_GDI: case TYMED_ENHMF:
if ( GDI_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up.
// For punk !=0, this will go to our CPunk object.
ReleaseStgMedium( pStgmed ); } break;
case TYMED_HGLOBAL:
if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up.
// For punk ==0, this will just release the data.
// For punk !=0, this will go to our CPunk object,
// release the data, and then call the original punk.
ReleaseStgMedium( pStgmed ); } break;
case TYMED_MFPICT:
if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else if ( GDI_HANDLE_PASSING(*pFlags) ) { if ( pStgmed->pUnkForRelease ) { pStgmed->pUnkForRelease->Release(); } else { if ( pStgmed->hGlobal ) GlobalFree( pStgmed->hGlobal ); pStgmed->hGlobal = NULL; pStgmed->tymed = TYMED_NULL; } } else { // Handle w/data: there is a side effect to clean up.
// For punk !=0, this will go to our CPunk object.
ReleaseStgMedium( pStgmed ); } break;
default: RAISE_RPC_EXCEPTION( E_INVALIDARG ); break; } } }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserSize
//
// Synopsis: Sizes a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER FLAG_STGMEDIUM_UserSize( unsigned long * pFlags, unsigned long Offset, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return Offset;
LENGTH_ALIGN( Offset, 3 );
Offset += 2 * sizeof(long); Offset = STGMEDIUM_UserSize( pFlags, Offset, & pFlagStgmed->Stgmed );
return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserMarshal
//
// Synopsis: Marshals a wrapper for stgmedium. Used in SetData.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserMarshal( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return pBuffer;
ALIGN( pBuffer, 3 );
// Flags: we need them when freeing in the client call_as routine
pFlagStgmed->ContextFlags = *pFlags;
*( PULONG_LV_CAST pBuffer)++ = *pFlags; *( PULONG_LV_CAST pBuffer)++ = pFlagStgmed->fPassOwnership;
pBuffer = STGMEDIUM_UserMarshal( pFlags, pBuffer, & pFlagStgmed->Stgmed );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserUnmarshal
//
// Synopsis: Unmarshals a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserUnmarshal( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { // Init buffer size.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); ULONG_PTR BufferSize = MarshalInfo.GetBufferSize(); UCHAR* pBufferStart = MarshalInfo.GetBuffer(); UCHAR* pBufferPtr = pBufferStart;
// Align the buffer.
ALIGN( pBufferPtr, 3 ); ULONG_PTR cbFixup = (ULONG_PTR)(pBufferPtr - pBufferStart);
// BufferSize must not be less than the
// alignment fixup + ContextFlags + fPassOwnership + tymed.
CHECK_BUFFER_SIZE( BufferSize, cbFixup + (2 * sizeof( ULONG )) );
// Flags and buffer marker
pFlagStgmed->ContextFlags = *( PULONG_LV_CAST pBufferPtr)++;
// Flags: we need them when freeing in the client call_as routine
// We need that in the Proxy, when we call the user free routine.
pFlagStgmed->fPassOwnership = *( PULONG_LV_CAST pBufferPtr)++; pFlagStgmed->ContextFlags = *pFlags;
// Needed to handle both GDI handles and Istream/IStorage correctly.
// Subtract alignment fixup + 2 DWORDs from BufferSize.
BufferSize -= cbFixup + (2 * sizeof( ULONG ));
pBuffer = STGMEDIUM_UserUnmarshalWorker( pFlags, pBufferPtr, & pFlagStgmed->Stgmed, BufferSize ); return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserFree
//
// Synopsis: Freess a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
void __RPC_USER FLAG_STGMEDIUM_UserFree( unsigned long * pFlags, FLAG_STGMEDIUM* pFlagsStgmed ) { if ( ! pFlagsStgmed->fPassOwnership ) STGMEDIUM_UserFree( pFlags, & pFlagsStgmed->Stgmed );
// else the callee is supposed to release the stg medium.
}
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserSize
//
// Synopsis: Sizes a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
// May-97 Ryszardk introduced the async flag to optimize
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER ASYNC_STGMEDIUM_UserSize( unsigned long * pFlags, unsigned long Offset, ASYNC_STGMEDIUM* pAsyncStgmed ) { if ( ! pAsyncStgmed ) return Offset;
// Needed to handle both GDI handles and Istream/IStorage correctly.
// BTW: This is needed only as a workaround because the [async] attr
// has been temporarily removed from objidl.idl. (May 1997).
// After we have the new [async] in place, this code is unnecessary
// as the NDR engine is setting the same flag for every async call.
*pFlags |= USER_CALL_IS_ASYNC;
Offset = STGMEDIUM_UserSize( pFlags, Offset, pAsyncStgmed );
return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserMarshal
//
// Synopsis: Marshals a wrapper for stgmedium. Used in SetData.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER ASYNC_STGMEDIUM_UserMarshal( unsigned long * pFlags, unsigned char * pBuffer, ASYNC_STGMEDIUM* pAsyncStgmed ) { if ( ! pAsyncStgmed ) return pBuffer;
// Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
pBuffer = STGMEDIUM_UserMarshal( pFlags, pBuffer, pAsyncStgmed );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserUnmarshal
//
// Synopsis: Unmarshals a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER ASYNC_STGMEDIUM_UserUnmarshal( unsigned long * pFlags, unsigned char * pBuffer, ASYNC_STGMEDIUM* pAsyncStgmed ) { // Init buffer size.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); ULONG_PTR BufferSize = MarshalInfo.GetBufferSize(); UCHAR* pBufferStart = MarshalInfo.GetBuffer();
// Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
pBuffer = STGMEDIUM_UserUnmarshalWorker( pFlags, pBufferStart, pAsyncStgmed, BufferSize );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserFree
//
// Synopsis: Freess a wrapper for stgmedium.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
void __RPC_USER ASYNC_STGMEDIUM_UserFree( unsigned long * pFlags, ASYNC_STGMEDIUM* pAsyncStgmed ) { // Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
STGMEDIUM_UserFree( pFlags, pAsyncStgmed ); }
#if defined(_WIN64)
//
// NDR64 Support routines.
//
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserSize64
//
// Synopsis: Sizes a stgmedium pbject for RPC marshalling.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER STGMEDIUM_UserSize64 ( unsigned long * pFlags, unsigned long Offset, STGMEDIUM * pStgmed ) { if ( ! pStgmed ) return Offset;
LENGTH_ALIGN( Offset, 7 );
// tymed is 4 bytes, plus 4 bytes padding, plus potentially the handle (8 bytes),
// plus the pUnk.
if ( pStgmed->tymed == TYMED_NULL ) Offset += 4 + 4 + 8; // switch, pad, (empty arm), pUnk
else { Offset += 4 + 4 + 8 + 8; // switch, pad, handle, pUnk
// Pointee of the union arm.
// Only if the handle/pointer field is non-null.
if ( pStgmed->hGlobal ) { SetContextFlagsForAsyncCall( pFlags, pStgmed ); switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: Offset = HMETAFILEPICT_UserSize64( pFlags, Offset, &pStgmed->hMetaFilePict ); break; case TYMED_ENHMF: Offset = HENHMETAFILE_UserSize64( pFlags, Offset, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI: // A GDI object is not necesarrily a BITMAP. Therefore, we handle
// those types we know about based on the object type, and reject
// those which we do not support.
// 4 bytes for disc, plus 4 bytes pad, plus 8 bytes pointer?
Offset += 4 + 4 + 8;
switch( GetObjectType( (HGDIOBJ)pStgmed->hBitmap ) ) { case OBJ_BITMAP: Offset = HBITMAP_UserSize64( pFlags, Offset, &pStgmed->hBitmap ); break;
case OBJ_PAL: Offset = HPALETTE_UserSize64( pFlags, Offset, (HPALETTE *) & pStgmed->hBitmap ); break;
default: RAISE_RPC_EXCEPTION(DV_E_TYMED); break; } break;
case TYMED_HGLOBAL: Offset = HGLOBAL_UserSize64( pFlags, Offset, &pStgmed->hGlobal ); break;
case TYMED_FILE: { ulong ulDataSize = 0; if (pStgmed->lpszFileName) ulDataSize = lstrlenW(pStgmed->lpszFileName) + 1; Offset += 3 * 8; // max size, offset, conformance
Offset += ulDataSize * sizeof(wchar_t); } break;
case TYMED_ISTREAM: Offset = WdtpInterfacePointer_UserSize64((USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pstm, IID_IStream); break;
case TYMED_ISTORAGE: Offset = WdtpInterfacePointer_UserSize64((USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pstg, IID_IStorage); break;
default: RAISE_RPC_EXCEPTION(DV_E_TYMED); break; } } }
// pUnkForRelease, if not null.
if ( pStgmed->pUnkForRelease ) Offset = WdtpInterfacePointer_UserSize64( (USER_MARSHAL_CB *)pFlags, *pFlags, Offset, pStgmed->pUnkForRelease, IID_IUnknown ); return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserMarshal64
//
// Synopsis: Marshals a stgmedium pbject for RPC.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserMarshal64 ( unsigned long * pFlags, unsigned char * pBufferStart, STGMEDIUM * pStgmed ) { unsigned char * pBuffer; unsigned char * pUnionArmMark; DWORD tymed;
if ( ! pStgmed ) return pBufferStart; UserNdrDebugOut(( UNDR_FORCE, "--STGMEDIUM_UserMarshal64: %s\n", WdtpGetStgmedName(pStgmed)));
pBuffer = pBufferStart; ALIGN( pBuffer, 7 );
// userSTGMEDIUM: switch, union arm, pUnk ptr.
tymed = pStgmed->tymed; *( PULONG_LV_CAST pBuffer)++ = tymed; ALIGN( pBuffer, 7 ); pUnionArmMark = pBuffer; if ( tymed != TYMED_NULL ) { // hGlobal stands for any of these handles.
*(PHYPER_LV_CAST pBuffer)++ = (hyper)( pStgmed->hGlobal ); } *(PHYPER_LV_CAST pBuffer)++ = (hyper)( pStgmed->pUnkForRelease );
// Now the pointee of the union arm.
// We need to marshal only if the handle/pointer field is non null.
// Otherwise it is already in the buffer.
if ( pStgmed->hGlobal ) { SetContextFlagsForAsyncCall( pFlags, pStgmed ); switch( pStgmed->tymed ) { case TYMED_NULL: break; case TYMED_MFPICT: pBuffer = HMETAFILEPICT_UserMarshal64( pFlags, pBuffer, &pStgmed->hMetaFilePict ); break;
case TYMED_ENHMF: pBuffer = HENHMETAFILE_UserMarshal64( pFlags, pBuffer, &pStgmed->hEnhMetaFile ); break; case TYMED_GDI: { // A GDI object is not necesarrily a BITMAP. Therefore, we handle
// those types we know about based on the object type, and reject
// those which we do not support.
ulong GdiObjectType = GetObjectType( (HGDIOBJ)pStgmed->hBitmap );
// GDI_OBJECT
*(PULONG_LV_CAST pBuffer)++ = GdiObjectType; ALIGN( pBuffer, 7 ); *(PHYPER_LV_CAST pBuffer)++ = (hyper)(pStgmed->hBitmap);
switch( GdiObjectType ) { case OBJ_BITMAP: pBuffer = HBITMAP_UserMarshal64( pFlags, pBuffer, &pStgmed->hBitmap ); break;
case OBJ_PAL: pBuffer = HPALETTE_UserMarshal64( pFlags, pBuffer, (HPALETTE *) & pStgmed->hBitmap ); break; default: RpcRaiseException(DV_E_TYMED); } } break;
case TYMED_HGLOBAL: pBuffer = HGLOBAL_UserMarshal64( pFlags, pBuffer, &pStgmed->hGlobal ); break; case TYMED_FILE: { // We marshal it as a [string].
ulong Count = 0; if (pStgmed->lpszFileName) Count = lstrlenW(pStgmed->lpszFileName) + 1;
*( PHYPER_LV_CAST pBuffer)++ = Count; *( PHYPER_LV_CAST pBuffer)++ = 0; *( PHYPER_LV_CAST pBuffer)++ = Count; memcpy( pBuffer, pStgmed->lpszFileName, Count * sizeof(wchar_t) ); pBuffer += Count * sizeof(wchar_t); } break;
case TYMED_ISTREAM: pBuffer = WdtpInterfacePointer_UserMarshal64(((USER_MARSHAL_CB *)pFlags), *pFlags, pBuffer, pStgmed->pstm, IID_IStream); break; case TYMED_ISTORAGE: pBuffer = WdtpInterfacePointer_UserMarshal64(((USER_MARSHAL_CB *)pFlags), *pFlags, pBuffer, pStgmed->pstg, IID_IStorage); break;
default: RpcRaiseException(DV_E_TYMED); break; } }
// Marker for this pointer is already in the buffer.
if ( pStgmed->pUnkForRelease ) pBuffer = WdtpInterfacePointer_UserMarshal64( ((USER_MARSHAL_CB *)pFlags), *pFlags, pBuffer, pStgmed->pUnkForRelease, IID_IUnknown ); return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserUnmarshalWorker64
//
// Synopsis: Unmarshals a stgmedium object for RPC.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserUnmarshalWorker64 ( unsigned long * pFlags, unsigned char * pBuffer, STGMEDIUM * pStgmed, ULONG_PTR BufferSize ) { CarefulBufferReader stream(pBuffer, BufferSize); LONG_PTR fUnkForRelease; LONG_PTR Handle = 0; unsigned char *mark = NULL;
// Align the buffer and save the fixup size.
stream.Align(8);
// switch, union arm, pUnk.
pStgmed->tymed = stream.ReadULONGNA(); UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserUnmarshal64: %s\n", WdtpGetStgmedName(pStgmed) ));
// (Force the align here so we only align once)
stream.Align(8); if ( pStgmed->tymed != TYMED_NULL ) { // This value is just a marker for the handle - a long.
Handle = stream.ReadHYPERNA(); } // pUnkForRelease pointer marker.
fUnkForRelease = stream.ReadHYPERNA();
// First pointee
// Union arm pointee.
// We need to unmarshal only if the handle/pointer field was not NULL.
if ( Handle ) { SetContextFlagsForAsyncCall( pFlags, pStgmed );
hyper* pBuf = (hyper*)stream.GetBuffer();
switch( pStgmed->tymed ) { case TYMED_NULL: break;
case TYMED_MFPICT: // validate the handle...
stream.CheckSize( 4 + 4 + 8 ); // enc. union: 4b switch + 4b pad + 8b handle
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
mark = HMETAFILEPICT_UserUnmarshalWorker64 (pFlags, stream.GetBuffer(), &pStgmed->hMetaFilePict, stream.BytesRemaining() ); stream.AdvanceTo(mark); break;
case TYMED_ENHMF: // validate the handle...
stream.CheckSize( 4 + 4 + 8 ); // enc. union: 4b switch + 4b pad + 8b handle
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
mark = HENHMETAFILE_UserUnmarshalWorker64 ( pFlags, stream.GetBuffer(), &pStgmed->hEnhMetaFile, stream.BytesRemaining() ); stream.AdvanceTo(mark); break;
case TYMED_GDI: { // A GDI object is not necesarrily a BITMAP. Therefore, we
// handle those types we know about based on the object type,
// and reject those which we do not support.
DWORD GdiObjectType = stream.ReadULONGNA(); Handle = stream.ReadHYPER();
switch( GdiObjectType ) { case OBJ_BITMAP: // Lookahead validation of the handle.
stream.CheckSize( 4 + 4 + 8 ); pBuf = (hyper*)stream.GetBuffer(); if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
mark = HBITMAP_UserUnmarshalWorker64( pFlags, stream.GetBuffer(), &pStgmed->hBitmap, stream.BytesRemaining() ); stream.AdvanceTo(mark); break;
case OBJ_PAL: // Lookahead validaton of the handle.
stream.CheckSize( 4 + 4 + 8 ); pBuf = (hyper*)stream.GetBuffer(); if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
mark = HPALETTE_UserUnmarshalWorker64( pFlags, stream.GetBuffer(), (HPALETTE *) & pStgmed->hBitmap, stream.BytesRemaining() ); stream.AdvanceTo(mark); break; default: RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } } break;
case TYMED_HGLOBAL: // reallocation is forbidden for [in-out] hglobal in STGMEDIUM.
// validate the handle.
stream.CheckSize( 4 + 4 + 8 ); // enc. union: 4b switch + 4b pad + 8b handle
if ( Handle != pBuf[1] ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); mark = WdtpGlobalUnmarshal64( pFlags, stream.GetBuffer(), & pStgmed->hGlobal, FALSE, stream.BytesRemaining() ); stream.AdvanceTo(mark); break; case TYMED_FILE: { // Must be room in buffer for header.
ulong Count = (ulong)stream.ReadHYPERNA();
// We marshal it as a [string].
if ( stream.ReadHYPERNA() != 0 ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); if ( stream.ReadHYPERNA() != Count ) RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
if ( ! pStgmed->lpszFileName ) { pStgmed->lpszFileName = (LPOLESTR) WdtpAllocate( pFlags, Count * sizeof(wchar_t) ); if (!pStgmed->lpszFileName) RpcRaiseException( E_OUTOFMEMORY ); }
// Must be room in the buffer for the string.
stream.CheckSize( Count * sizeof(WCHAR) ); memcpy(pStgmed->lpszFileName, stream.GetBuffer(), Count * sizeof(wchar_t)); stream.Advance( Count * sizeof(WCHAR) ); } break;
case TYMED_ISTREAM: mark = WdtpInterfacePointer_UserUnmarshalWorker((USER_MARSHAL_CB *)pFlags, stream.GetBuffer(), (IUnknown **) &pStgmed->pstm, IID_IStream, stream.BytesRemaining(), TRUE); stream.AdvanceTo(mark); break;
case TYMED_ISTORAGE: mark = WdtpInterfacePointer_UserUnmarshalWorker((USER_MARSHAL_CB *)pFlags, stream.GetBuffer(), (IUnknown **) &pStgmed->pstg, IID_IStorage, stream.BytesRemaining(), TRUE); stream.AdvanceTo(mark); break;
default: RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); break; } } else { // New handle/pointer field is null, so release the previous one
// if it wasn't null.
if ( pStgmed->hGlobal ) { // This should never happen for GetDataHere.
// Note, that we release the handle field, not the stgmedium itself.
// Accordingly, we don't follow punkForRelease.
UserNdrDebugOut(( UNDR_FORCE, "--STGMEDIUM_UserUnmarshal64: %s: NULL in, freeing old one\n", WdtpGetStgmedName(pStgmed)));
STGMEDIUM TmpStg = *pStgmed; TmpStg.pUnkForRelease = NULL; if ( pStgmed->tymed == TYMED_HGLOBAL ) { // Cannot reallocate.
RAISE_RPC_EXCEPTION(DV_E_TYMED); } else { ReleaseStgMedium( &TmpStg ); } } pStgmed->hGlobal = 0; }
if ( fUnkForRelease ) { // There is an interface pointer on the wire.
mark = WdtpInterfacePointer_UserUnmarshalWorker((USER_MARSHAL_CB *)pFlags, stream.GetBuffer(), &pStgmed->pUnkForRelease, IID_IUnknown, stream.BytesRemaining(), TRUE); stream.AdvanceTo(mark); }
if ( pStgmed->pUnkForRelease ) { // Replace the app's punkForRelease with our custom release
// handler for special situations.
// The special situation is when a handle is remoted with data
// and so we have to clean up a side effect of having a data copy
// around. UserFree does it properly but we need that for the callee.
// When the callee releases a stgmed, it would invoke
// ReleaseStgMedium and this API doesn't do anything for handles
// when the punkForRelease is not NULL.
ULONG fHandleWithData = 0; ULONG fTopLevelOnly = 0;
switch ( pStgmed->tymed ) { case TYMED_HGLOBAL: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); break; case TYMED_ENHMF: case TYMED_GDI: fHandleWithData = GDI_DATA_PASSING( *pFlags ); break; case TYMED_MFPICT: fHandleWithData = HGLOBAL_DATA_PASSING( *pFlags ); fTopLevelOnly = fHandleWithData && !GDI_DATA_PASSING( *pFlags ); break; default: break; }
if ( fHandleWithData ) { IUnknown * punkTmp = (IUnknown *) new CPunkForRelease( pStgmed, fTopLevelOnly ); if (!punkTmp) { RAISE_RPC_EXCEPTION(E_OUTOFMEMORY); }
pStgmed->pUnkForRelease = punkTmp; } }
return( stream.GetBuffer() ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserUnmarshal64
//
// Synopsis: Unmarshals a stgmedium object for RPC.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER STGMEDIUM_UserUnmarshal64 ( unsigned long * pFlags, unsigned char * pBuffer, STGMEDIUM * pStgmed ) { // Init buffer size and ptr to buffer.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); ULONG_PTR BufferSize = MarshalInfo.GetBufferSize(); UCHAR* pBufferStart = MarshalInfo.GetBuffer();
pBuffer = STGMEDIUM_UserUnmarshalWorker64( pFlags, pBufferStart, pStgmed, BufferSize ); return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: STGMEDIUM_UserFree64
//
// Synopsis: Frees a stgmedium object for RPC.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
// Note: This routine is called from the freeing walk at server
// or from the SetData *proxy*, when ownership has been passed.
//
//--------------------------------------------------------------------------
void __RPC_USER STGMEDIUM_UserFree64 ( unsigned long * pFlags, STGMEDIUM * pStgmed ) { UserNdrDebugOut((UNDR_FORCE, "--STGMEDIUM_UserFree64: %s\n", WdtpGetStgmedName(pStgmed)));
if( pStgmed ) { SetContextFlagsForAsyncCall( pFlags, pStgmed ); switch ( pStgmed->tymed ) { case TYMED_FILE: WdtpFree( pFlags, pStgmed->lpszFileName); NukeHandleAndReleasePunk( pStgmed ); break; case TYMED_NULL: case TYMED_ISTREAM: case TYMED_ISTORAGE: ReleaseStgMedium( pStgmed ); break; case TYMED_GDI: case TYMED_ENHMF: if ( GDI_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up.
// For punk !=0, this will go to our CPunk object.
ReleaseStgMedium( pStgmed ); } break; case TYMED_HGLOBAL: if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else { // Handle w/data: there is a side effect to clean up.
// For punk ==0, this will just release the data.
// For punk !=0, this will go to our CPunk object,
// release the data, and then call the original punk.
ReleaseStgMedium( pStgmed ); } break; case TYMED_MFPICT: if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { NukeHandleAndReleasePunk( pStgmed ); } else if ( GDI_HANDLE_PASSING(*pFlags) ) { if ( pStgmed->pUnkForRelease ) { pStgmed->pUnkForRelease->Release(); } else { if ( pStgmed->hGlobal ) GlobalFree( pStgmed->hGlobal ); pStgmed->hGlobal = NULL; pStgmed->tymed = TYMED_NULL; } } else { // Handle w/data: there is a side effect to clean up.
// For punk !=0, this will go to our CPunk object.
ReleaseStgMedium( pStgmed ); } break; default: RAISE_RPC_EXCEPTION( E_INVALIDARG ); break; } } }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserSize64
//
// Synopsis: Sizes a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER FLAG_STGMEDIUM_UserSize64 ( unsigned long * pFlags, unsigned long Offset, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return Offset;
LENGTH_ALIGN( Offset, 7 );
Offset += 2 * sizeof(long); Offset = STGMEDIUM_UserSize64 ( pFlags, Offset, & pFlagStgmed->Stgmed );
return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserMarshal64
//
// Synopsis: Marshals a wrapper for stgmedium. Used in SetData.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserMarshal64 ( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { if ( ! pFlagStgmed ) return pBuffer;
ALIGN( pBuffer, 7 );
// Flags: we need them when freeing in the client call_as routine
pFlagStgmed->ContextFlags = *pFlags;
*( PULONG_LV_CAST pBuffer)++ = *pFlags; *( PULONG_LV_CAST pBuffer)++ = pFlagStgmed->fPassOwnership;
pBuffer = STGMEDIUM_UserMarshal64( pFlags, pBuffer, & pFlagStgmed->Stgmed );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserUnmarshal64
//
// Synopsis: Unmarshals a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER FLAG_STGMEDIUM_UserUnmarshal64 ( unsigned long * pFlags, unsigned char * pBuffer, FLAG_STGMEDIUM* pFlagStgmed ) { // Init buffer size.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); CarefulBufferReader stream(pBuffer, MarshalInfo.GetBufferSize());
// Align the buffer.
stream.Align(8); // Flags and buffer marker
pFlagStgmed->ContextFlags = stream.ReadULONGNA();
// Flags: we need them when freeing in the client call_as routine
// We need that in the Proxy, when we call the user free routine.
pFlagStgmed->fPassOwnership = stream.ReadULONGNA(); pFlagStgmed->ContextFlags = *pFlags;
pBuffer = STGMEDIUM_UserUnmarshalWorker64( pFlags, stream.GetBuffer(), & pFlagStgmed->Stgmed, stream.BytesRemaining() ); return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: FLAG_STGMEDIUM_UserFree64
//
// Synopsis: Freess a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
void __RPC_USER FLAG_STGMEDIUM_UserFree64 ( unsigned long * pFlags, FLAG_STGMEDIUM* pFlagsStgmed ) { if ( ! pFlagsStgmed->fPassOwnership ) STGMEDIUM_UserFree64 ( pFlags, & pFlagsStgmed->Stgmed );
// else the callee is supposed to release the stg medium.
}
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserSize64
//
// Synopsis: Sizes a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER ASYNC_STGMEDIUM_UserSize64 ( unsigned long * pFlags, unsigned long Offset, ASYNC_STGMEDIUM* pAsyncStgmed ) { if ( ! pAsyncStgmed ) return Offset;
// Needed to handle both GDI handles and Istream/IStorage correctly.
// BTW: This is needed only as a workaround because the [async] attr
// has been temporarily removed from objidl.idl. (May 1997).
// After we have the new [async] in place, this code is unnecessary
// as the NDR engine is setting the same flag for every async call.
*pFlags |= USER_CALL_IS_ASYNC;
Offset = STGMEDIUM_UserSize64 ( pFlags, Offset, pAsyncStgmed );
return( Offset ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserMarshal64
//
// Synopsis: Marshals a wrapper for stgmedium. Used in SetData.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER ASYNC_STGMEDIUM_UserMarshal64 ( unsigned long * pFlags, unsigned char * pBuffer, ASYNC_STGMEDIUM* pAsyncStgmed ) { if ( ! pAsyncStgmed ) return pBuffer;
// Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
pBuffer = STGMEDIUM_UserMarshal64( pFlags, pBuffer, pAsyncStgmed );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserUnmarshal64
//
// Synopsis: Unmarshals a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER ASYNC_STGMEDIUM_UserUnmarshal64( unsigned long * pFlags, unsigned char * pBuffer, ASYNC_STGMEDIUM* pAsyncStgmed ) { // Init buffer size.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer ); ULONG_PTR BufferSize = MarshalInfo.GetBufferSize(); UCHAR* pBufferStart = MarshalInfo.GetBuffer();
// Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
pBuffer = STGMEDIUM_UserUnmarshalWorker64( pFlags, pBufferStart, pAsyncStgmed, BufferSize );
return( pBuffer ); }
//+-------------------------------------------------------------------------
//
// Function: ASYNC_STGMEDIUM_UserFree64
//
// Synopsis: Freess a wrapper for stgmedium.
//
// history: Dec-00 JohnDoty Created based on 32b function.
//
//--------------------------------------------------------------------------
void __RPC_USER ASYNC_STGMEDIUM_UserFree64( unsigned long * pFlags, ASYNC_STGMEDIUM* pAsyncStgmed ) { // Needed to handle both GDI handles and Istream/IStorage correctly.
*pFlags |= USER_CALL_IS_ASYNC;
STGMEDIUM_UserFree64( pFlags, pAsyncStgmed ); }
#endif
|