2274 lines
76 KiB
C++
2274 lines
76 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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 "widewrap.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) );
|
|
|
|
// 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) );
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|