windows-nt/Source/XPSP1/NT/com/ole32/oleprx32/proxy/hglobal.cxx

700 lines
20 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: hglobal.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 HGLOBAL.
//
// Functions:
// HGLOBAL_UserSize
// HGLOBAL_UserMarshal
// HGLOBAL_UserUnmarshal
// HGLOBAL_UserFree
// HGLOBAL_UserSize64
// HGLOBAL_UserMarshal64
// HGLOBAL_UserUnmarshal64
// HGLOBAL_UserFree64
//
// History: 13-Dec-00 JohnDoty Migrated from transmit.cxx
//
//--------------------------------------------------------------------------
#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"
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserSize
//
// Synopsis: Get the wire size the HGLOBAL handle and data.
//
// Derivation: Conformant struct with a flag field:
// align + 12 + data size.
//
// history: May-95 Ryszardk Created.
// Dec-98 Ryszardk Ported to 64b.
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER
HGLOBAL_UserSize (
unsigned long * pFlags,
unsigned long Offset,
HGLOBAL * pGlobal)
{
if ( !pGlobal )
return Offset;
// userHGLOBAL: the encapsulated union.
// Discriminant and then handle or pointer from the union arm.
LENGTH_ALIGN( Offset, 3 );
// Union discriminent is 4 bytes
Offset += sizeof( long );
// Handle represented by a polymorphic type - for inproc case only!
if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
{
LENGTH_ALIGN( Offset, sizeof( HGLOBAL )-1 );
Offset += sizeof( HGLOBAL );
}
else
Offset += ( sizeof(long) + sizeof(HGLOBAL) );
if ( ! *pGlobal )
return Offset;
if ( HGLOBAL_DATA_PASSING(*pFlags) )
{
unsigned long ulDataSize = (ULONG) GlobalSize( *pGlobal );
Offset += 3 * sizeof(long) + ulDataSize;
}
return( Offset );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserMarshall
//
// Synopsis: Marshalls an HGLOBAL object into the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// history: May-95 Ryszardk Created.
// Dec-98 Ryszardk Ported to 64b.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
HGLOBAL_UserMarshal (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal)
{
if ( !pGlobal )
return pBuffer;
// We marshal a null handle, too.
UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n"));
ALIGN( pBuffer, 3 );
// Discriminant of the encapsulated union and union arm.
if ( HGLOBAL_DATA_PASSING(*pFlags) )
{
unsigned long ulDataSize;
// userHGLOBAL
*( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
if ( ! *pGlobal )
return pBuffer;
// FLAGGED_BYTE_BLOB
ulDataSize = (ULONG) GlobalSize( *pGlobal );
*( PULONG_LV_CAST pBuffer)++ = ulDataSize;
// Handle is the non-null flag
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
*( PULONG_LV_CAST pBuffer)++ = ulDataSize;
if( ulDataSize )
{
void * pData = GlobalLock( *pGlobal);
memcpy( pBuffer, pData, ulDataSize );
GlobalUnlock( *pGlobal);
}
pBuffer += ulDataSize;
}
else
{
// Sending a handle.
// For WIN64 HGLOBALs, 64 bits may by significant (e.i. GPTR).
#if defined(_WIN64)
*( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE64_MARKER;
ALIGN( pBuffer, 7 );
*( PHYPER_LV_CAST pBuffer)++ = *(__int64 *)pGlobal;
#else
*( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE_MARKER;
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
#endif
}
return( pBuffer );
}
//+-------------------------------------------------------------------------
//
// Function: WdtpGlobalUnmarshal
//
// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// Note: Reallocation is forbidden when the hglobal is part of
// an [in,out] STGMEDIUM in IDataObject::GetDataHere.
// This affects only data passing with old handles being
// non null.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
WdtpGlobalUnmarshal (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal,
BOOL fCanReallocate,
ULONG_PTR BufferSize )
{
unsigned long ulDataSize, fHandle, UnionDisc;
HGLOBAL hGlobal;
// Align the buffer and save the fixup size.
UCHAR* pBufferStart = pBuffer;
ALIGN( pBuffer, 3 );
ULONG_PTR cbFixup = (ULONG_PTR)(pBuffer - pBufferStart);
// Check for EOB before accessing discriminant and handle.
CHECK_BUFFER_SIZE( BufferSize, cbFixup + (2 * sizeof( ULONG )) );
// Get the tag from buffer.
UnionDisc = *( PULONG_LV_CAST pBuffer)++;
if ( IS_DATA_MARKER( UnionDisc) )
{
// Get the marker from the buffer.
hGlobal = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
// If handle is NULL, we are done.
if ( ! hGlobal )
{
if ( *pGlobal )
GlobalFree( *pGlobal );
*pGlobal = NULL;
return pBuffer;
}
// Check for EOB before accessing header.
CHECK_BUFFER_SIZE( BufferSize, cbFixup + (5 * sizeof( ULONG )) );
// Get the rest of the header from the buffer.
ulDataSize = *( PULONG_LV_CAST pBuffer)++;
HGLOBAL hGlobalDup = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
ULONG ulDataSizeDup = *( PULONG_LV_CAST pBuffer)++;
// Validate the header: handle and size are put on wire twice, make
// sure both instances of each are the same.
if ( (hGlobalDup != hGlobal) ||
(ulDataSizeDup != ulDataSize) )
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
if ( *pGlobal )
{
// Check for reallocation
if ( GlobalSize( *pGlobal ) == ulDataSize )
hGlobal = *pGlobal;
else
{
if ( fCanReallocate )
{
GlobalFree( *pGlobal );
hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
}
else
{
if ( GlobalSize(*pGlobal) < ulDataSize )
{
RAISE_RPC_EXCEPTION( STG_E_MEDIUMFULL );
}
else
hGlobal = *pGlobal;
}
}
}
else
{
// allocate a new block
hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
}
if ( hGlobal == NULL )
{
RAISE_RPC_EXCEPTION(E_OUTOFMEMORY);
}
else
{
// Check for EOB before accessing data.
CHECK_BUFFER_SIZE( BufferSize,
cbFixup + (5 * sizeof( ULONG )) + ulDataSize );
// Get the data from the buffer.
void * pData = GlobalLock( hGlobal);
memcpy( pData, pBuffer, ulDataSize );
pBuffer += ulDataSize;
GlobalUnlock( hGlobal);
}
}
else
{
// Sending a handle only.
// Reallocation problem doesn't apply to handle passing.
if ( IS_HANDLE_MARKER( UnionDisc ) )
{
hGlobal = (HGLOBAL) LongToHandle( *( PLONG_LV_CAST pBuffer)++ );
}
else if (IS_HANDLE64_MARKER( UnionDisc ) )
{
ALIGN( pBuffer, 7 );
// Must be enough buffer to do alignment fixup.
CHECK_BUFFER_SIZE( BufferSize, cbFixup +
(ULONG_PTR) (pBuffer - pBufferStart) + sizeof( __int64 ));
hGlobal = (HGLOBAL) ( *( PHYPER_LV_CAST pBuffer)++ );
}
else
{
RAISE_RPC_EXCEPTION( RPC_S_INVALID_TAG );
}
if ( *pGlobal != hGlobal && *pGlobal )
GlobalFree( *pGlobal );
}
*pGlobal = hGlobal;
return( pBuffer );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserUnmarshall
//
// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
HGLOBAL_UserUnmarshal (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal)
{
// Get the buffer size and the start of the buffer.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer );
ULONG_PTR BufferSize = MarshalInfo.GetBufferSize();
UCHAR* pBufferStart = MarshalInfo.GetBuffer();
pBuffer = WdtpGlobalUnmarshal( pFlags,
pBufferStart,
pGlobal,
TRUE, // reallocation possible
BufferSize );
return( pBuffer );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserFree
//
// Synopsis: Free an HGLOBAL.
//
// history: May-95 Ryszardk Created.
//
//--------------------------------------------------------------------------
void __RPC_USER
HGLOBAL_UserFree(
unsigned long * pFlags,
HGLOBAL * pGlobal)
{
if( pGlobal && *pGlobal )
{
if ( HGLOBAL_DATA_PASSING(*pFlags) )
GlobalFree( *pGlobal);
}
}
#if defined(_WIN64)
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserSize64
//
// Synopsis: Get the wire size the HGLOBAL handle and data.
//
// Derivation: Union around a pointer to a conformant struct with a
// flag field.
//
// history: Dec-00 JohnDoty Created from 32bit function
//
//--------------------------------------------------------------------------
unsigned long __RPC_USER
HGLOBAL_UserSize64 (
unsigned long * pFlags,
unsigned long Offset,
HGLOBAL * pGlobal)
{
if ( !pGlobal )
return Offset;
// userHGLOBAL: the encapsulated union.
// Discriminant and then handle or pointer from the union arm.
// Union discriminent is 4 bytes, but it contains a pointer, so
// align on union is 8 bytes.
LENGTH_ALIGN( Offset, 7 );
Offset += sizeof( long );
LENGTH_ALIGN( Offset, 7 );
// Handle represented by a polymorphic type - for inproc case only!
if ( HGLOBAL_HANDLE_PASSING(*pFlags) )
{
// Doesn't matter which arm we take inproc, it's size of native
// HGLOBAL.
Offset += sizeof( HGLOBAL );
}
else
{
// Pointer representation...
Offset += 8;
}
if ( ! *pGlobal )
return Offset;
if ( HGLOBAL_DATA_PASSING(*pFlags) )
{
// Struct must be aligned on 8, but already aligned on
// 8...
unsigned long ulDataSize = (ULONG) GlobalSize( *pGlobal );
Offset += 8 + 2 * sizeof(long) + ulDataSize;
}
return( Offset );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserMarshal64
//
// Synopsis: Marshalls an HGLOBAL object into the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// history: Dec-00 JohnDoty Created from 32bit function
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
HGLOBAL_UserMarshal64 (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal)
{
if ( !pGlobal )
return pBuffer;
// We marshal a null handle, too.
UserNdrDebugOut((UNDR_OUT4, "HGLOBAL_UserMarshal\n"));
ALIGN( pBuffer, 7 );
// Discriminant of the encapsulated union and union arm.
if ( HGLOBAL_DATA_PASSING(*pFlags) )
{
unsigned long ulDataSize;
// userHGLOBAL
*( PULONG_LV_CAST pBuffer)++ = WDT_DATA_MARKER;
ALIGN( pBuffer, 7 );
*( PHYPER_LV_CAST pBuffer)++ = (hyper)*pGlobal;
if ( ! *pGlobal )
return pBuffer;
// FLAGGED_BYTE_BLOB
ulDataSize = (ULONG) GlobalSize( *pGlobal );
*( PHYPER_LV_CAST pBuffer)++ = ulDataSize;
// Handle is the non-null flag
*( PLONG_LV_CAST pBuffer)++ = HandleToLong( *pGlobal );
*( PULONG_LV_CAST pBuffer)++ = ulDataSize;
if( ulDataSize )
{
void * pData = GlobalLock( *pGlobal);
memcpy( pBuffer, pData, ulDataSize );
GlobalUnlock( *pGlobal);
}
pBuffer += ulDataSize;
}
else
{
// Sending a handle.
// For WIN64 HGLOBALs, 64 bits may by significant (e.i. GPTR).
*( PULONG_LV_CAST pBuffer)++ = WDT_HANDLE64_MARKER;
ALIGN( pBuffer, 7 );
*( PHYPER_LV_CAST pBuffer)++ = *(__int64 *)pGlobal;
}
return( pBuffer );
}
//+-------------------------------------------------------------------------
//
// Function: WdtpGlobalUnmarshal64
//
// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// Note: Reallocation is forbidden when the hglobal is part of
// an [in,out] STGMEDIUM in IDataObject::GetDataHere.
// This affects only data passing with old handles being
// non null.
//
// history: Dec-00 JohnDoty Created from 32bit function
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
WdtpGlobalUnmarshal64 (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal,
BOOL fCanReallocate,
ULONG_PTR BufferSize )
{
CarefulBufferReader stream(pBuffer, BufferSize);
unsigned long ulDataSize, fHandle, UnionDisc;
HGLOBAL hGlobal;
// Align the buffer and save the fixup size.
stream.Align(8);
// Get the tag from buffer.
UnionDisc = stream.ReadULONGNA();
// Get the marker from the buffer.
hGlobal = (HGLOBAL)stream.ReadHYPER();
if ( IS_DATA_MARKER(UnionDisc) )
{
// If the handle was NULL, return out now.
if (!hGlobal)
{
if (*pGlobal)
GlobalFree(*pGlobal);
*pGlobal = NULL;
return stream.GetBuffer();
}
// Get the rest of the header from the buffer.
ulDataSize = (ULONG)stream.ReadHYPERNA();
LONG hGlobalDup = stream.ReadLONGNA();
ULONG ulDataSizeDup = stream.ReadULONGNA();
// Validate the header: handle and size are put on wire twice, make
// sure both instances of each are the same.
if ( (hGlobalDup != HandleToLong(hGlobal)) ||
(ulDataSizeDup != ulDataSize) )
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA );
if ( *pGlobal )
{
// Check for reallocation
if ( GlobalSize( *pGlobal ) == ulDataSize )
hGlobal = *pGlobal;
else
{
if ( fCanReallocate )
{
GlobalFree( *pGlobal );
hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
}
else
{
if ( GlobalSize(*pGlobal) < ulDataSize )
{
RAISE_RPC_EXCEPTION( STG_E_MEDIUMFULL );
}
else
hGlobal = *pGlobal;
}
}
}
else
{
// allocate a new block
hGlobal = GlobalAlloc( GMEM_MOVEABLE, ulDataSize );
}
if ( hGlobal == NULL )
{
RAISE_RPC_EXCEPTION(E_OUTOFMEMORY);
}
else
{
// Check for EOB before accessing data.
stream.CheckSize(ulDataSize);
// Get the data from the buffer.
void * pData = GlobalLock( hGlobal);
memcpy( pData, stream.GetBuffer(), ulDataSize );
GlobalUnlock( hGlobal);
stream.Advance(ulDataSize);
}
}
else if (IS_HANDLE64_MARKER( UnionDisc ))
{
// Make sure the old stuff is cleaned up...
if ( *pGlobal != hGlobal && *pGlobal )
GlobalFree( *pGlobal );
}
else
{
RAISE_RPC_EXCEPTION( RPC_S_INVALID_TAG );
}
*pGlobal = hGlobal;
return( stream.GetBuffer() );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserUnmarshal64
//
// Synopsis: Unmarshalls an HGLOBAL object from the RPC buffer.
//
// Derivation: Conformant struct with a flag field:
// align, size, null flag, size, data (bytes, if any)
//
// history: Dec-00 JohnDoty Created from 32bit function
//
//--------------------------------------------------------------------------
unsigned char __RPC_FAR * __RPC_USER
HGLOBAL_UserUnmarshal64 (
unsigned long * pFlags,
unsigned char * pBuffer,
HGLOBAL * pGlobal)
{
// Get the buffer size and the start of the buffer.
CUserMarshalInfo MarshalInfo( pFlags, pBuffer );
ULONG_PTR BufferSize = MarshalInfo.GetBufferSize();
UCHAR* pBufferStart = MarshalInfo.GetBuffer();
pBuffer = WdtpGlobalUnmarshal64( pFlags,
pBufferStart,
pGlobal,
TRUE, // reallocation possible
BufferSize );
return( pBuffer );
}
//+-------------------------------------------------------------------------
//
// Function: HGLOBAL_UserFree64
//
// Synopsis: Free an HGLOBAL.
//
// history: Dec-00 JohnDoty Created from 32bit function
//
//--------------------------------------------------------------------------
void __RPC_USER
HGLOBAL_UserFree64 (
unsigned long * pFlags,
HGLOBAL * pGlobal)
{
if( pGlobal && *pGlobal )
{
if ( HGLOBAL_DATA_PASSING(*pFlags) )
GlobalFree( *pGlobal);
}
}
#endif