|
|
//+-------------------------------------------------------------------------
//
// 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 <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) ) { if ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { // Hey, you can't send us one of these!
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); }
// 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 ( HGLOBAL_DATA_PASSING(*pFlags) ) { // Hey, you can't send us one of these!
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); } 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 ( HGLOBAL_HANDLE_PASSING(*pFlags) ) { // Hey, you can't send us one of these!
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); }
// 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 )) { if ( HGLOBAL_DATA_PASSING(*pFlags) ) { // Hey, you can't send us one of these!
RAISE_RPC_EXCEPTION( RPC_X_BAD_STUB_DATA ); }
// 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
|