//+------------------------------------------------------------------------- // // 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 #include #include "transmit.hxx" #include #include #include #include #include #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