mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1881 lines
54 KiB
1881 lines
54 KiB
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
wdt.cxx
|
|
|
|
Abstract:
|
|
|
|
Windows Data Type Support by means of [user_marshal] attribute.
|
|
|
|
Covers:
|
|
BSTR
|
|
LPSAFEARRAY
|
|
VARIANT
|
|
DIPPARAMS
|
|
EXCEPINFO
|
|
|
|
|
|
Author:
|
|
|
|
Ryszard K. Kott (ryszardk) Feb 14, 1995
|
|
|
|
Revision History:
|
|
|
|
-------------------------------------------------------------------*/
|
|
|
|
|
|
//#include "stdrpc.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include <wtypes.h>
|
|
#include <objbase.h>
|
|
#include <oleauto.h>
|
|
#include <oaidl.h>
|
|
|
|
//#include "..\ndr20\ndrole.h"
|
|
|
|
#include "wdtp.h"
|
|
#include <rpcwdt.h>
|
|
#include <winerror.h>
|
|
|
|
|
|
// #########################################################################
|
|
//
|
|
// BSTR
|
|
//
|
|
// #########################################################################
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BSTR_UserSize
|
|
//
|
|
// Synopsis: Get the wire size for the BSTR handle and data.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align + 12 + data size.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned long __RPC_USER
|
|
BSTR_UserSize (
|
|
unsigned long * pFlags,
|
|
unsigned long Offset,
|
|
BSTR * pBstr)
|
|
{
|
|
// Null bstr doesn't get marshalled.
|
|
|
|
if ( pBstr == NULL || *pBstr == NULL )
|
|
return Offset;
|
|
|
|
unsigned long ulDataSize;
|
|
|
|
LENGTH_ALIGN( Offset, 3 );
|
|
|
|
// Takes the byte length of a unicode string
|
|
|
|
ulDataSize = (*pBstr) ? SysStringByteLen( *pBstr )
|
|
: 0;
|
|
|
|
return( Offset + 12 + ulDataSize) ;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BSTR_UserMarshall
|
|
//
|
|
// Synopsis: Marshalls an BSTR object into the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
BSTR_UserMarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
BSTR * pBstr)
|
|
{
|
|
// A null Bstr is not marshalled, the engine will take care of it.
|
|
|
|
if ( pBstr == NULL || *pBstr == NULL )
|
|
return pBuffer;
|
|
|
|
unsigned long ulDataSize;
|
|
|
|
// Data size (in bytes): a null bstr gets a data size of zero.
|
|
|
|
ulDataSize = (*pBstr) ? SysStringByteLen( *pBstr )
|
|
: 0;
|
|
|
|
// Conformant size.
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulDataSize >> 1);
|
|
|
|
// FLAGGED_WORD_BLOB: Handle is the null/non-null flag
|
|
|
|
*( PULONG_LV_CAST pBuffer)++ = (unsigned long)*pBstr;
|
|
|
|
// Length on wire is in words.
|
|
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulDataSize >> 1);
|
|
|
|
if( ulDataSize )
|
|
{
|
|
// we don't put the terminating string on wire
|
|
|
|
WdtpMemoryCopy( pBuffer, *pBstr, ulDataSize );
|
|
}
|
|
|
|
return( pBuffer + ulDataSize );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BSTR_UserUnmarshall
|
|
//
|
|
// Synopsis: Unmarshalls an BSTR object from the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
BSTR_UserUnmarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
BSTR * pBstr)
|
|
{
|
|
unsigned long ulDataSize, fHandle;
|
|
BSTR Bstr = NULL; // Default to NULL BSTR
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
|
|
ulDataSize = *( PULONG_LV_CAST pBuffer)++;
|
|
fHandle = *(ulong *)pBuffer;
|
|
pBuffer += 8;
|
|
|
|
if ( fHandle )
|
|
{
|
|
// Length on wire is in words, and the string is unicode.
|
|
|
|
if ( *pBstr &&
|
|
*(((ulong *)*pBstr) -1) == (ulDataSize << 1) )
|
|
WdtpMemoryCopy( *pBstr, pBuffer, (ulDataSize << 1) );
|
|
else
|
|
{
|
|
if (! SysReAllocStringLen( pBstr,
|
|
(OLECHAR *)pBuffer,
|
|
ulDataSize ) )
|
|
RpcRaiseException( E_OUTOFMEMORY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// free the old one, make it NULL.
|
|
|
|
SysFreeString( *pBstr );
|
|
*pBstr = NULL;
|
|
}
|
|
|
|
return( pBuffer + (ulDataSize << 1) );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: BSTR_UserFree
|
|
//
|
|
// Synopsis: Free an BSTR.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void __RPC_USER
|
|
BSTR_UserFree(
|
|
unsigned long * pFlags,
|
|
BSTR * pBstr)
|
|
{
|
|
if( pBstr && *pBstr )
|
|
{
|
|
SysFreeString(* pBstr);
|
|
*pBstr = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// #########################################################################
|
|
//
|
|
// VARIANT
|
|
//
|
|
// #########################################################################
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: VARIANT_UserSize
|
|
//
|
|
// Synopsis: Get the wire size the VARIANT handle and data.
|
|
//
|
|
// Derivation:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned long __RPC_USER
|
|
VARIANT_UserSize (
|
|
unsigned long * pFlags,
|
|
unsigned long Offset,
|
|
VARIANT * pVariant )
|
|
{
|
|
if ( pVariant == NULL )
|
|
return Offset;
|
|
|
|
// alignment for the structure: DCE union is assumed for alignment.
|
|
|
|
LENGTH_ALIGN( Offset, 7 );
|
|
|
|
// Data size: common fields + switch
|
|
|
|
Offset += 4 * sizeof(short) + sizeof(long);
|
|
|
|
// Alignment for the union arm
|
|
|
|
switch ( pVariant->vt )
|
|
{
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
LENGTH_ALIGN( Offset, 7 );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
|
|
// now the field
|
|
// Account for the pointer, if there is one.
|
|
|
|
if ( pVariant->vt & VT_BYREF )
|
|
{
|
|
if ( NULL == pVariant->plVal )
|
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|
Offset += 4;
|
|
}
|
|
|
|
VARTYPE vtDiscr = pVariant->vt;
|
|
|
|
if ( vtDiscr & VT_ARRAY )
|
|
vtDiscr = vtDiscr & (VT_ARRAY | VT_BYREF);
|
|
|
|
switch ( vtDiscr )
|
|
{
|
|
case VT_UI1:
|
|
case VT_UI1|VT_BYREF:
|
|
Offset += 1;
|
|
break;
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
case VT_I2 | VT_BYREF:
|
|
case VT_BOOL | VT_BYREF:
|
|
Offset += 2;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_ERROR:
|
|
case VT_I4 | VT_BYREF:
|
|
case VT_R4 | VT_BYREF:
|
|
case VT_ERROR | VT_BYREF:
|
|
Offset += 4;
|
|
break;
|
|
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
case VT_I8 | VT_BYREF:
|
|
case VT_CY | VT_BYREF:
|
|
case VT_UI8 | VT_BYREF:
|
|
case VT_R8 | VT_BYREF:
|
|
case VT_DATE | VT_BYREF:
|
|
Offset += 8;
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
Offset += 4;
|
|
if ( pVariant->bstrVal )
|
|
Offset = BSTR_UserSize( pFlags, Offset, & pVariant->bstrVal );
|
|
break;
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
Offset += 4;
|
|
if ( * (pVariant->pbstrVal) )
|
|
Offset = BSTR_UserSize( pFlags, Offset, pVariant->pbstrVal );
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
Offset += 4;
|
|
if ( pVariant->punkVal )
|
|
Offset = WdtpInterfacePointer_UserSize(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
Offset,
|
|
pVariant->punkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
break;
|
|
|
|
case VT_UNKNOWN | VT_BYREF:
|
|
case VT_DISPATCH | VT_BYREF:
|
|
Offset += 4;
|
|
if ( *(pVariant->ppunkVal) )
|
|
Offset = WdtpInterfacePointer_UserSize(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
Offset,
|
|
*pVariant->ppunkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
break;
|
|
|
|
case VT_ARRAY:
|
|
Offset += 4;
|
|
Offset = LPSAFEARRAY_UserSize( pFlags,
|
|
Offset,
|
|
& pVariant->parray );
|
|
break;
|
|
|
|
case VT_ARRAY | VT_BYREF:
|
|
Offset += 4;
|
|
Offset = LPSAFEARRAY_UserSize( pFlags,
|
|
Offset,
|
|
pVariant->pparray );
|
|
break;
|
|
|
|
case VT_VARIANT:
|
|
RpcRaiseException( ERROR_BAD_ARGUMENTS );
|
|
break;
|
|
|
|
case VT_VARIANT|VT_BYREF:
|
|
Offset += 4;
|
|
Offset = VARIANT_UserSize( pFlags, Offset, pVariant->pvarVal );
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
break;
|
|
|
|
default:
|
|
RpcRaiseException( ERROR_BAD_ARGUMENTS );
|
|
break;
|
|
}
|
|
|
|
return( Offset );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: VARIANT_UserMarshal
|
|
//
|
|
// Synopsis: Marshalls an VARIANT object into the RPC buffer.
|
|
//
|
|
// Derivation:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
VARIANT_UserMarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
VARIANT * pVariant )
|
|
{
|
|
if ( ! pVariant )
|
|
return pBuffer;
|
|
|
|
// userVARIANT: alignment for the structure
|
|
|
|
ALIGN( pBuffer, 7 );
|
|
|
|
// common fields: vt + 3 reserved shorts
|
|
|
|
WdtpMemoryCopy( pBuffer, pVariant, 4 * sizeof(short) );
|
|
pBuffer += 4 * sizeof(short);
|
|
|
|
// union switch
|
|
|
|
*( PULONG_LV_CAST pBuffer )++ = pVariant->vt;
|
|
|
|
// Alignment for the union arm
|
|
|
|
switch ( pVariant->vt )
|
|
{
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
ALIGN( pBuffer, 7 );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
|
|
// now the field
|
|
// Put the pointer, if there is one, as it has to go there, no matter what.
|
|
|
|
if ( pVariant->vt & VT_BYREF )
|
|
{
|
|
if ( NULL == pVariant->plVal )
|
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|
*( PLONG_LV_CAST pBuffer )++ = (long)pVariant->plVal;
|
|
}
|
|
|
|
VARTYPE vtDiscr = pVariant->vt;
|
|
|
|
if ( vtDiscr & VT_ARRAY )
|
|
vtDiscr = vtDiscr & (VT_ARRAY | VT_BYREF);
|
|
|
|
switch ( vtDiscr )
|
|
{
|
|
case VT_UI1:
|
|
*( PCHAR_LV_CAST pBuffer )++ = pVariant->bVal;
|
|
break;
|
|
|
|
case VT_UI1|VT_BYREF:
|
|
*( PCHAR_LV_CAST pBuffer )++ = *pVariant->pbVal;
|
|
break;
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
*( PSHORT_LV_CAST pBuffer )++ = pVariant->iVal;
|
|
break;
|
|
|
|
case VT_I2 | VT_BYREF:
|
|
case VT_BOOL | VT_BYREF:
|
|
*( PSHORT_LV_CAST pBuffer )++ = * pVariant->piVal;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_ERROR:
|
|
*( PLONG_LV_CAST pBuffer )++ = pVariant->lVal;
|
|
break;
|
|
|
|
case VT_I4 | VT_BYREF:
|
|
case VT_R4 | VT_BYREF:
|
|
case VT_ERROR | VT_BYREF:
|
|
*( PLONG_LV_CAST pBuffer )++ = * pVariant->plVal;
|
|
break;
|
|
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
ALIGN( pBuffer, 7 );
|
|
WdtpMemoryCopy( pBuffer, & pVariant->dblVal, sizeof(double) );
|
|
pBuffer += sizeof(double);
|
|
break;
|
|
|
|
case VT_I8 | VT_BYREF:
|
|
case VT_CY | VT_BYREF:
|
|
case VT_UI8 | VT_BYREF:
|
|
case VT_R8 | VT_BYREF:
|
|
case VT_DATE | VT_BYREF:
|
|
// already aligned at 8
|
|
WdtpMemoryCopy( pBuffer, & pVariant->dblVal, sizeof(double) );
|
|
pBuffer += sizeof(double);
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulong) pVariant->bstrVal;
|
|
if ( pVariant->bstrVal )
|
|
pBuffer = BSTR_UserMarshal( pFlags, pBuffer, & pVariant->bstrVal );
|
|
break;
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
// pbstrVal is already on the wire.
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulong) *(pVariant->pbstrVal);
|
|
if ( * (pVariant->pbstrVal) )
|
|
pBuffer = BSTR_UserMarshal( pFlags, pBuffer, pVariant->pbstrVal );
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
*( PULONG_LV_CAST pBuffer)++ = (unsigned long) pVariant->punkVal;
|
|
if ( pVariant->punkVal )
|
|
pBuffer = WdtpInterfacePointer_UserMarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
pBuffer,
|
|
pVariant->punkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
break;
|
|
|
|
case VT_UNKNOWN | VT_BYREF:
|
|
case VT_DISPATCH | VT_BYREF:
|
|
// ppunkVal is already on the wire.
|
|
*( PULONG_LV_CAST pBuffer)++ = (unsigned long) *(pVariant->ppunkVal);
|
|
if ( * (pVariant->ppunkVal) )
|
|
pBuffer = WdtpInterfacePointer_UserMarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
pBuffer,
|
|
* pVariant->ppunkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
break;
|
|
|
|
case VT_ARRAY:
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulong) pVariant->parray;
|
|
pBuffer = LPSAFEARRAY_UserMarshal( pFlags,
|
|
pBuffer,
|
|
& pVariant->parray );
|
|
break;
|
|
|
|
case VT_ARRAY | VT_BYREF:
|
|
// pparray is already on the wire.
|
|
*( PULONG_LV_CAST pBuffer)++ = (ulong) * (pVariant->pparray);
|
|
pBuffer = LPSAFEARRAY_UserMarshal( pFlags,
|
|
pBuffer,
|
|
pVariant->pparray );
|
|
break;
|
|
|
|
case VT_VARIANT|VT_BYREF:
|
|
*( PULONG_LV_CAST pBuffer)++ = USER_MARSHAL_MARKER;
|
|
pBuffer = VARIANT_UserMarshal( pFlags,
|
|
pBuffer,
|
|
pVariant->pvarVal );
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
break;
|
|
|
|
default:
|
|
RpcRaiseException( ERROR_BAD_ARGUMENTS );
|
|
break;
|
|
}
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: VARIANT_UserUnmarshall
|
|
//
|
|
// Synopsis: Unmarshalls an VARIANT object from the RPC buffer.
|
|
//
|
|
// Derivation:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
VARIANT_UserUnmarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
VARIANT * pVariant)
|
|
{
|
|
VARTYPE NewVt;
|
|
|
|
// alignment for the structure
|
|
|
|
ALIGN( pBuffer, 7 );
|
|
|
|
// See if we are going to reuse the variant.
|
|
|
|
NewVt = *(short*)pBuffer;
|
|
|
|
if ( pVariant->vt != VT_EMPTY && pVariant->vt != NewVt )
|
|
{
|
|
// We cannot use VARIANT_UserFree on the client,
|
|
// as it would attempt to free too much.
|
|
|
|
VariantClear( pVariant );
|
|
}
|
|
|
|
// common fields: vt and Res'es
|
|
|
|
WdtpMemoryCopy( pVariant, pBuffer, 4 * sizeof(short) );
|
|
pBuffer += 4 * sizeof(short);
|
|
|
|
// union switch: same as pVariant->vt
|
|
|
|
pBuffer += 4;
|
|
|
|
// Alignment for the union arm
|
|
|
|
switch ( pVariant->vt )
|
|
{
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
ALIGN( pBuffer, 7 );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
|
|
// now the field
|
|
// Skip the pointer, if there is one, as it is there, no matter what.
|
|
|
|
if ( pVariant->vt & VT_BYREF )
|
|
{
|
|
if ( NULL == *( PLONG_LV_CAST pBuffer)++ )
|
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|
}
|
|
|
|
VARTYPE vtDiscr = pVariant->vt;
|
|
|
|
if ( vtDiscr & VT_ARRAY )
|
|
vtDiscr = vtDiscr & (VT_ARRAY | VT_BYREF);
|
|
|
|
switch ( vtDiscr )
|
|
{
|
|
case VT_UI1:
|
|
pVariant->bVal = *pBuffer++;
|
|
break;
|
|
|
|
case VT_UI1|VT_BYREF:
|
|
if ( ! pVariant->pbVal )
|
|
pVariant->pbVal = (unsigned char*)
|
|
WdtpAllocate( pFlags, sizeof(char) );
|
|
*pVariant->pbVal = *pBuffer++;
|
|
break;
|
|
|
|
case VT_I2:
|
|
case VT_BOOL:
|
|
pVariant->iVal = *( PSHORT_LV_CAST pBuffer)++;
|
|
break;
|
|
|
|
case VT_I2 | VT_BYREF:
|
|
case VT_BOOL | VT_BYREF:
|
|
if ( ! pVariant->piVal )
|
|
pVariant->piVal = (short *)
|
|
WdtpAllocate( pFlags, sizeof(short) );
|
|
*pVariant->piVal = *( PSHORT_LV_CAST pBuffer)++;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_R4:
|
|
case VT_ERROR:
|
|
pVariant->lVal = *( PLONG_LV_CAST pBuffer)++;
|
|
break;
|
|
|
|
case VT_I4 | VT_BYREF:
|
|
case VT_R4 | VT_BYREF:
|
|
case VT_ERROR | VT_BYREF:
|
|
if ( ! pVariant->plVal )
|
|
pVariant->plVal = (long *) WdtpAllocate( pFlags, sizeof(long));
|
|
*pVariant->plVal = *( PLONG_LV_CAST pBuffer)++;
|
|
break;
|
|
|
|
case VT_I8:
|
|
case VT_CY:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_DATE:
|
|
WdtpMemoryCopy( & pVariant->dblVal, pBuffer, sizeof(double) );
|
|
pBuffer += sizeof(double);
|
|
break;
|
|
|
|
case VT_I8 | VT_BYREF:
|
|
case VT_CY | VT_BYREF:
|
|
case VT_UI8 | VT_BYREF:
|
|
case VT_R8 | VT_BYREF:
|
|
case VT_DATE | VT_BYREF:
|
|
if ( ! pVariant->pdblVal )
|
|
pVariant->pdblVal = (double *)
|
|
WdtpAllocate( pFlags, sizeof(double) );
|
|
WdtpMemoryCopy( pVariant->pdblVal, pBuffer, sizeof(double) );
|
|
pBuffer += sizeof(double);
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
// bstr value.
|
|
if ( *( PLONG_LV_CAST pBuffer)++ )
|
|
pBuffer = BSTR_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pVariant->bstrVal );
|
|
else
|
|
BSTR_UserFree( pFlags, & pVariant->bstrVal );
|
|
break;
|
|
|
|
case VT_BSTR | VT_BYREF:
|
|
if ( ! pVariant->pbstrVal )
|
|
{
|
|
pVariant->pbstrVal = (BSTR *)
|
|
WdtpAllocate( pFlags, sizeof(void*) );
|
|
*pVariant->pbstrVal = NULL;
|
|
}
|
|
|
|
// bstr value from the wire
|
|
if ( *( PLONG_LV_CAST pBuffer)++ )
|
|
pBuffer = BSTR_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
pVariant->pbstrVal );
|
|
else
|
|
BSTR_UserFree( pFlags, pVariant->pbstrVal );
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
pVariant->punkVal = (IUnknown*) *(PULONG_LV_CAST pBuffer)++;
|
|
if ( pVariant->punkVal )
|
|
{
|
|
pVariant->punkVal = NULL;
|
|
pBuffer = WdtpInterfacePointer_UserUnmarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
pBuffer,
|
|
& pVariant->punkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
}
|
|
else
|
|
WdtpInterfacePointer_UserFree( pVariant->punkVal );
|
|
break;
|
|
|
|
case VT_UNKNOWN | VT_BYREF:
|
|
case VT_DISPATCH | VT_BYREF:
|
|
if ( ! pVariant->ppunkVal )
|
|
{
|
|
pVariant->ppunkVal = (IUnknown **)
|
|
WdtpAllocate( pFlags, sizeof(void*));
|
|
*pVariant->ppunkVal = (IUnknown*) *(PULONG_LV_CAST pBuffer)++;
|
|
}
|
|
|
|
// pointer from the wire
|
|
if ( *( PLONG_LV_CAST pBuffer)++ )
|
|
{
|
|
pBuffer = WdtpInterfacePointer_UserUnmarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
pBuffer,
|
|
pVariant->ppunkVal,
|
|
((pVariant->vt & VT_DISPATCH) ? IID_IDispatch
|
|
: IID_IUnknown) );
|
|
}
|
|
else
|
|
WdtpInterfacePointer_UserFree( * (pVariant->ppunkVal) );
|
|
break;
|
|
|
|
case VT_ARRAY:
|
|
// Skip user marshal marker.
|
|
pBuffer += 4;
|
|
pBuffer = LPSAFEARRAY_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pVariant->parray );
|
|
break;
|
|
|
|
case VT_ARRAY | VT_BYREF:
|
|
if ( ! pVariant->pparray )
|
|
{
|
|
pVariant->pparray = (SAFEARRAY **)
|
|
WdtpAllocate( pFlags, sizeof(void*));
|
|
*pVariant->pparray = NULL;
|
|
}
|
|
|
|
pBuffer = LPSAFEARRAY_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
pVariant->pparray );
|
|
break;
|
|
|
|
case VT_VARIANT|VT_BYREF:
|
|
if ( ! pVariant->pvarVal )
|
|
{
|
|
pVariant->pvarVal = (VARIANT *)
|
|
WdtpAllocate( pFlags, sizeof(VARIANT) );
|
|
WdtpZeroMemory( pVariant->pvarVal, sizeof(VARIANT) );
|
|
}
|
|
|
|
pBuffer = VARIANT_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
pVariant->pvarVal );
|
|
break;
|
|
|
|
case VT_EMPTY:
|
|
case VT_NULL:
|
|
break;
|
|
|
|
default:
|
|
RpcRaiseException( ERROR_BAD_ARGUMENTS );
|
|
break;
|
|
}
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: VARIANT_UserFree
|
|
//
|
|
// Synopsis: Free a VARIANT.
|
|
//
|
|
// Note: We can't use VariantClear, as this one does not clean up
|
|
// the way we need at the server side.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void __RPC_USER
|
|
VARIANT_UserFree(
|
|
unsigned long * pFlags,
|
|
VARIANT * pVariant)
|
|
{
|
|
if( pVariant)
|
|
{
|
|
long * pl = NULL;
|
|
|
|
// Account for the pointer, if there is one.
|
|
|
|
if ( pVariant->vt & VT_BYREF )
|
|
{
|
|
if ( NULL == pVariant->plVal )
|
|
RpcRaiseException( RPC_X_NULL_REF_POINTER );
|
|
pl = pVariant->plVal;
|
|
|
|
// remove the indirection in the variant
|
|
|
|
pVariant->bstrVal = * pVariant->pbstrVal;
|
|
}
|
|
|
|
VARTYPE vtDiscr = pVariant->vt;
|
|
|
|
if ( vtDiscr & VT_ARRAY )
|
|
vtDiscr = vtDiscr & (VT_ARRAY | VT_BYREF);
|
|
|
|
switch ( vtDiscr )
|
|
{
|
|
case VT_BSTR:
|
|
case VT_BSTR | VT_BYREF:
|
|
if ( pVariant->bstrVal )
|
|
BSTR_UserFree( pFlags, & pVariant->bstrVal );
|
|
break;
|
|
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
case VT_UNKNOWN | VT_BYREF:
|
|
case VT_DISPATCH | VT_BYREF:
|
|
if ( pVariant->punkVal )
|
|
pVariant->punkVal->Release();
|
|
break;
|
|
|
|
case VT_ARRAY:
|
|
case VT_ARRAY | VT_BYREF:
|
|
LPSAFEARRAY_UserFree( pFlags, & pVariant->parray );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// if there was BYREF, free the pointer itself.
|
|
|
|
if ( pl )
|
|
WdtpFree( pFlags, pl );
|
|
WdtpZeroMemory( pVariant, sizeof(VARIANT) );
|
|
}
|
|
}
|
|
|
|
|
|
// #########################################################################
|
|
//
|
|
// SAFEARRAY
|
|
//
|
|
// #########################################################################
|
|
|
|
SF_TYPE
|
|
GetSafeArrayDiscr( LPSAFEARRAY pSafeArray )
|
|
/*
|
|
Finds out what type of olelment the safe array has.
|
|
SF_* constants are set to their VARTYPE (i.e. VT_*) equivalents.
|
|
*/
|
|
{
|
|
SF_TYPE sfDiscr = SF_ERROR;
|
|
|
|
switch ( pSafeArray->cbElements )
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
sfDiscr = SF_I1;
|
|
break;
|
|
case 2:
|
|
sfDiscr = SF_I2;
|
|
break;
|
|
case 4:
|
|
{
|
|
sfDiscr = SF_I4;
|
|
|
|
ulong Feature = pSafeArray->fFeatures & 0x0f00;
|
|
|
|
switch ( Feature )
|
|
{
|
|
case FADF_BSTR:
|
|
sfDiscr = SF_BSTR;
|
|
break;
|
|
case FADF_UNKNOWN:
|
|
sfDiscr = SF_UNKNOWN;
|
|
break;
|
|
case FADF_DISPATCH:
|
|
sfDiscr = SF_DISPATCH;
|
|
break;
|
|
case FADF_VARIANT:
|
|
sfDiscr = SF_VARIANT;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 8:
|
|
sfDiscr = SF_I8;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( SF_ERROR == sfDiscr )
|
|
RpcRaiseException( ERROR_BAD_ARGUMENTS );
|
|
|
|
return sfDiscr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LPSAFEARRAY_UserSize
|
|
//
|
|
// Synopsis: Get the wire size the SAFEARRAY handle and data.
|
|
//
|
|
// Derivation:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned long __RPC_USER
|
|
LPSAFEARRAY_UserSize (
|
|
unsigned long * pFlags,
|
|
unsigned long Offset,
|
|
LPSAFEARRAY * pPSafeArray )
|
|
{
|
|
if ( NULL == pPSafeArray )
|
|
return Offset;
|
|
|
|
LENGTH_ALIGN( Offset, 3 );
|
|
Offset += 4;
|
|
|
|
if ( ! *pPSafeArray )
|
|
return Offset;
|
|
|
|
// userSAFEARRAY object
|
|
|
|
LPSAFEARRAY pSafeArray = *pPSafeArray;
|
|
|
|
// Data size: conf size, common fields, switch, union arm;
|
|
// then array bounds, and the array of pointers.
|
|
// Union arm is always a struct with a size field and the other field being
|
|
// a pointer to a conformant array.
|
|
|
|
Offset += sizeof(long) + 2 * sizeof(short) + 2 * sizeof(long) +
|
|
sizeof(SAFEARRAYUNION);
|
|
|
|
// Size of bounds
|
|
|
|
Offset += pSafeArray->cDims * sizeof(SAFEARRAYBOUND);
|
|
|
|
// Elements of the array pointed to by the arm.
|
|
|
|
long lElemCount = 1;
|
|
|
|
for (int i = 0; i < pSafeArray->cDims; i++)
|
|
lElemCount *= pSafeArray->rgsabound[i].cElements;
|
|
|
|
SF_TYPE sfDiscr = GetSafeArrayDiscr( pSafeArray );
|
|
|
|
// Size of the array itself.
|
|
// Size of elem is eaither size of data, pointer or user marshal marker.
|
|
|
|
long WireElemSize = pSafeArray->cbElements;
|
|
|
|
if ( pSafeArray->cbElements == sizeof(VARIANT) )
|
|
WireElemSize = sizeof(long);
|
|
|
|
if ( SF_I8 == sfDiscr )
|
|
{
|
|
LENGTH_ALIGN( Offset, 7 );
|
|
}
|
|
|
|
if ( lElemCount == 0 )
|
|
return Offset;
|
|
|
|
Offset += lElemCount * WireElemSize;
|
|
|
|
// Now the pointees: only for "non-integer" cases.
|
|
|
|
if ( sfDiscr != SF_BSTR && sfDiscr != SF_VARIANT &&
|
|
sfDiscr != SF_UNKNOWN && sfDiscr != SF_DISPATCH )
|
|
return( Offset );
|
|
|
|
for (i = 0; i < lElemCount; i++)
|
|
{
|
|
switch ( sfDiscr )
|
|
{
|
|
case SF_BSTR:
|
|
// an element is a BSTR
|
|
Offset = BSTR_UserSize( pFlags,
|
|
Offset,
|
|
& ((BSTR*)(pSafeArray->pvData))[i]);
|
|
break;
|
|
case SF_UNKNOWN:
|
|
// an element is a IUnknown *
|
|
Offset = WdtpInterfacePointer_UserSize(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
Offset,
|
|
((IUnknown**)(pSafeArray->pvData))[i],
|
|
IID_IUnknown );
|
|
break;
|
|
case SF_DISPATCH:
|
|
// an element is a IDispatch *
|
|
Offset = WdtpInterfacePointer_UserSize(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
Offset,
|
|
((IUnknown**)(pSafeArray->pvData))[i],
|
|
IID_IDispatch );
|
|
break;
|
|
case SF_VARIANT:
|
|
// an element is a VARIANT (not a pointer to it!)
|
|
Offset = VARIANT_UserSize( pFlags,
|
|
Offset,
|
|
& ((VARIANT*)(pSafeArray->pvData))[i] );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( Offset );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SAFEARRAY_UserMarshal
|
|
//
|
|
// Synopsis: Marshalls an SAFEARRAY object into the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
LPSAFEARRAY_UserMarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
LPSAFEARRAY * pPSafeArray)
|
|
{
|
|
if ( NULL == pPSafeArray )
|
|
return pBuffer;
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
*( PULONG_LV_CAST pBuffer )++ = (ulong) *pPSafeArray;
|
|
|
|
if ( ! *pPSafeArray )
|
|
return pBuffer;
|
|
|
|
// userSAFEARRAY object
|
|
// See the sizing routine descr for the list of things to marshall.
|
|
|
|
LPSAFEARRAY pSafeArray = *pPSafeArray;
|
|
|
|
*( PULONG_LV_CAST pBuffer )++ = pSafeArray->cDims; // conf size
|
|
|
|
*( PUSHORT_LV_CAST pBuffer )++ = pSafeArray->cDims;
|
|
*( PUSHORT_LV_CAST pBuffer )++ = pSafeArray->fFeatures;
|
|
*( PULONG_LV_CAST pBuffer )++ = pSafeArray->cbElements;
|
|
*( PULONG_LV_CAST pBuffer )++ = pSafeArray->cLocks;
|
|
|
|
// Union switch: This cannot be just pSafeArray->fFeatures
|
|
// as this doesn't cover all that we need.
|
|
|
|
SF_TYPE sfDiscr = GetSafeArrayDiscr( pSafeArray );
|
|
|
|
*( PULONG_LV_CAST pBuffer )++ = sfDiscr;
|
|
|
|
// Compute the size of the array pointed to by the arm.
|
|
|
|
long lElemCount = 1;
|
|
|
|
for (int i = 0; i < pSafeArray->cDims; i++)
|
|
lElemCount *= pSafeArray->rgsabound[i].cElements;
|
|
|
|
// union arm
|
|
|
|
NDR_ASSERT( lElemCount == 0 && pSafeArray->pvData == 0 ||
|
|
lElemCount != 0 && pSafeArray->pvData != 0,
|
|
"Size and pointer inconsistent" );
|
|
|
|
*( PULONG_LV_CAST pBuffer )++ = lElemCount;
|
|
*( PULONG_LV_CAST pBuffer )++ = (ULONG) pSafeArray->pvData;
|
|
|
|
// the safe array bounds
|
|
|
|
for (i = 0; i < pSafeArray->cDims; i++)
|
|
{
|
|
*( PULONG_LV_CAST pBuffer )++ = pSafeArray->rgsabound[ i ].cElements;
|
|
*( PULONG_LV_CAST pBuffer )++ = pSafeArray->rgsabound[ i ].lLbound;
|
|
}
|
|
|
|
// Now the array of data, pointers, or markers.
|
|
|
|
if ( lElemCount )
|
|
{
|
|
unsigned char * pPointee;
|
|
unsigned long WireElemSize = pSafeArray->cbElements;
|
|
void * pvData;
|
|
|
|
if ( pSafeArray->cbElements == sizeof(VARIANT) )
|
|
WireElemSize = sizeof(long);
|
|
|
|
// This is a conformant array of something.
|
|
|
|
*( PULONG_LV_CAST pBuffer )++ = lElemCount;
|
|
|
|
// The array has either pointers (for interface ptrs) or
|
|
// user marshal markers (for BSTR and VARIANT) or plain data.
|
|
|
|
if ( S_OK != SafeArrayAccessData( pSafeArray, & pvData ))
|
|
RpcRaiseException( E_OUTOFMEMORY );
|
|
|
|
if ( sfDiscr != SF_BSTR && sfDiscr != SF_VARIANT &&
|
|
sfDiscr != SF_UNKNOWN && sfDiscr != SF_DISPATCH )
|
|
{
|
|
// A block copy of plain data.
|
|
|
|
unsigned long cbArraySize = lElemCount * WireElemSize;
|
|
|
|
if ( SF_I8 == sfDiscr )
|
|
{
|
|
ALIGN( pBuffer, 7 );
|
|
}
|
|
|
|
WdtpMemoryCopy( pBuffer, pvData, cbArraySize );
|
|
pBuffer += cbArraySize;
|
|
SafeArrayUnaccessData( pSafeArray );
|
|
return( pBuffer );
|
|
}
|
|
|
|
// We locked the array, to try finally is needed to unlock it
|
|
// in face of exception in the marshalling code.
|
|
|
|
__try
|
|
{
|
|
// Only pointers or user marshal markers in the array.
|
|
|
|
pPointee = pBuffer + sizeof(long) * WireElemSize;
|
|
|
|
for (i = 0; i < lElemCount; i++)
|
|
{
|
|
if ( ((BSTR*)pvData)[i] == NULL )
|
|
{
|
|
*( PULONG_LV_CAST pBuffer )++ = 0;
|
|
}
|
|
else
|
|
{
|
|
switch ( sfDiscr )
|
|
{
|
|
case SF_BSTR:
|
|
*( PULONG_LV_CAST pBuffer )++ = USER_MARSHAL_MARKER;
|
|
pPointee = BSTR_UserMarshal(
|
|
pFlags,
|
|
pPointee,
|
|
& ((BSTR*)(pvData))[i] );
|
|
break;
|
|
|
|
case SF_UNKNOWN:
|
|
*( PULONG_LV_CAST pBuffer )++ = ((ulong*)(pvData))[i];
|
|
pPointee = WdtpInterfacePointer_UserMarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
pPointee,
|
|
((IUnknown**)(pvData))[i],
|
|
IID_IUnknown );
|
|
break;
|
|
|
|
case SF_DISPATCH:
|
|
*( PULONG_LV_CAST pBuffer )++ = ((ulong*)(pvData))[i];
|
|
pPointee = WdtpInterfacePointer_UserMarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
*pFlags,
|
|
pPointee,
|
|
((IUnknown**)(pvData))[i],
|
|
IID_IDispatch );
|
|
break;
|
|
|
|
case SF_VARIANT:
|
|
*( PULONG_LV_CAST pBuffer )++ = USER_MARSHAL_MARKER;
|
|
pPointee = VARIANT_UserMarshal(
|
|
pFlags,
|
|
pPointee,
|
|
& ((VARIANT*)(pvData))[i] );
|
|
break;
|
|
|
|
default:
|
|
RpcRaiseException(ERROR_BAD_ARGUMENTS);
|
|
break;
|
|
}
|
|
}
|
|
} // for
|
|
|
|
pBuffer = pPointee;
|
|
|
|
}
|
|
__finally
|
|
{
|
|
SafeArrayUnaccessData( pSafeArray );
|
|
}
|
|
|
|
} // if lElemCount
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SAFEARRAY_UserUnmarshal
|
|
//
|
|
// Synopsis: Unmarshalls an SAFEARRAY object from the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
LPSAFEARRAY_UserUnmarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
LPSAFEARRAY * pPSafeArray)
|
|
{
|
|
unsigned long ulDataSize, fNullHandle;
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
SAFEARRAY * pSafeArray = (SAFEARRAY*)( PULONG_LV_CAST pBuffer )++;
|
|
|
|
if ( ! pSafeArray )
|
|
{
|
|
// A null safe array coming. Release the old one.
|
|
|
|
if ( *pPSafeArray )
|
|
SafeArrayDestroy( *pPSafeArray );
|
|
|
|
*pPSafeArray = pSafeArray;
|
|
|
|
return pBuffer;
|
|
}
|
|
|
|
// Non-null pointer: allocate a safe array.
|
|
|
|
pBuffer += sizeof(long); // skipping the conf size == cDims
|
|
|
|
unsigned short cDims = *( PUSHORT_LV_CAST pBuffer)++;
|
|
unsigned short fFeatures = *( PUSHORT_LV_CAST pBuffer)++;
|
|
unsigned long cbElements = *( PULONG_LV_CAST pBuffer)++;
|
|
unsigned long cLocks = *( PULONG_LV_CAST pBuffer)++;
|
|
|
|
// The union switch - it's not fFeatures, it's a FS_TYPE, i.e. a VARTYPE.
|
|
// It is set appropriately when marshalling.
|
|
|
|
VARTYPE sfDiscr = (VARTYPE) *( PULONG_LV_CAST pBuffer)++;
|
|
|
|
if ( VT_I8 == sfDiscr )
|
|
sfDiscr = VT_R8;
|
|
|
|
if ( VT_I1 == sfDiscr )
|
|
sfDiscr = VT_UI1;
|
|
|
|
// union arm: SAFEARRAY_*. Size of array pointed to by the arm.
|
|
// We can do for any discriminant: it is always 2 longs on wire.
|
|
|
|
unsigned long ElemCount = *( PULONG_LV_CAST pBuffer)++;
|
|
unsigned long pvData = *( PULONG_LV_CAST pBuffer)++;
|
|
|
|
// Array bounds are in the buffer behind the union.
|
|
|
|
SAFEARRAYBOUND * pBounds = (SAFEARRAYBOUND *) pBuffer;
|
|
|
|
pSafeArray = SafeArrayCreate( sfDiscr, cDims, pBounds );
|
|
|
|
if ( pSafeArray == NULL )
|
|
RpcRaiseException( E_OUTOFMEMORY );
|
|
|
|
// The safe array bounds:
|
|
// just skip them; they have been copied by SafeArrayCreate.
|
|
|
|
pBuffer += cDims * sizeof(SAFEARRAYBOUND);
|
|
|
|
// Fill in the safe object we've got.
|
|
// However, locks reflect this side locks, not he other side locks.
|
|
// BUGBUG: server side flags may be different from the originals.
|
|
|
|
pSafeArray->fFeatures = fFeatures;
|
|
pSafeArray->cbElements = cbElements;
|
|
|
|
// Now the array.
|
|
// This is a conformant array of data, pointers, or markers.
|
|
|
|
if ( ElemCount )
|
|
{
|
|
unsigned char * pPointee;
|
|
void * pvData;
|
|
unsigned long WireElemSize = pSafeArray->cbElements;
|
|
|
|
pBuffer += 4; // skipping the conf size
|
|
|
|
// The array has either pointers (for interface ptrs) or
|
|
// user marshal markers (for BSTR and VARIUANT) or plain data.
|
|
|
|
if ( pSafeArray->cbElements == sizeof(VARIANT) )
|
|
WireElemSize = sizeof(long);
|
|
|
|
if ( S_OK != SafeArrayAccessData( pSafeArray, & pvData ))
|
|
RpcRaiseException( E_OUTOFMEMORY );
|
|
|
|
unsigned long cbArraySize = ElemCount * WireElemSize;
|
|
|
|
if ( sfDiscr != SF_BSTR && sfDiscr != SF_VARIANT &&
|
|
sfDiscr != SF_UNKNOWN && sfDiscr != SF_DISPATCH )
|
|
{
|
|
// A block copy of plain data.
|
|
|
|
if ( VT_R8 == sfDiscr )
|
|
{
|
|
ALIGN( pBuffer, 7 );
|
|
}
|
|
|
|
WdtpMemoryCopy( pvData, pBuffer, cbArraySize );
|
|
pBuffer += cbArraySize;
|
|
SafeArrayUnaccessData( pSafeArray );
|
|
}
|
|
else
|
|
{
|
|
// Only pointers or user marshal markers in the array.
|
|
|
|
// We locked the array, so, try-finally is needed to unlock it
|
|
// in face of exception in the marshalling code.
|
|
|
|
__try
|
|
{
|
|
pPointee = pBuffer + cbArraySize;
|
|
|
|
WdtpZeroMemory( pvData, cbArraySize );
|
|
|
|
for (unsigned int i = 0; i < ElemCount; i++)
|
|
{
|
|
if ( *( PULONG_LV_CAST pBuffer )++ != 0 )
|
|
{
|
|
switch ( pSafeArray->fFeatures & 0x0f00 )
|
|
{
|
|
case SF_BSTR:
|
|
pPointee = BSTR_UserUnmarshal(
|
|
pFlags,
|
|
pPointee,
|
|
& ((BSTR*)(pvData))[i] );
|
|
break;
|
|
|
|
case SF_UNKNOWN:
|
|
pPointee = WdtpInterfacePointer_UserUnmarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
pBuffer,
|
|
& ((IUnknown**)(pvData))[i],
|
|
IID_IUnknown );
|
|
break;
|
|
|
|
case SF_DISPATCH:
|
|
pPointee = WdtpInterfacePointer_UserUnmarshal(
|
|
(USER_MARSHAL_CB *)pFlags,
|
|
pBuffer,
|
|
& ((IUnknown**)(pvData))[i],
|
|
IID_IDispatch );
|
|
break;
|
|
|
|
case SF_VARIANT:
|
|
pPointee = VARIANT_UserUnmarshal(
|
|
pFlags,
|
|
pPointee,
|
|
& ((VARIANT*)(pvData))[i] );
|
|
break;
|
|
|
|
default:
|
|
RpcRaiseException( RPC_X_BAD_STUB_DATA );
|
|
break;
|
|
}
|
|
}
|
|
} // for
|
|
|
|
pBuffer = pPointee;
|
|
|
|
}
|
|
__finally
|
|
{
|
|
SafeArrayUnaccessData( pSafeArray );
|
|
}
|
|
}
|
|
|
|
} // if lElemCount
|
|
|
|
// No reusage, if it exists, the old one should be released.
|
|
|
|
if ( *pPSafeArray )
|
|
SafeArrayDestroy( *pPSafeArray );
|
|
|
|
*pPSafeArray = pSafeArray;
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LPSAFEARRAY_UserFree
|
|
//
|
|
// Synopsis: Free an SAFEARRAY.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void __RPC_USER
|
|
LPSAFEARRAY_UserFree(
|
|
unsigned long * pFlags,
|
|
LPSAFEARRAY * pPSafeArray)
|
|
{
|
|
if( pPSafeArray && *pPSafeArray )
|
|
{
|
|
HRESULT hr = SafeArrayDestroy( *pPSafeArray );
|
|
if ( FAILED(hr) )
|
|
RpcRaiseException( hr );
|
|
}
|
|
}
|
|
|
|
|
|
// #########################################################################
|
|
//
|
|
// DISPPARAMS
|
|
//
|
|
// #########################################################################
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DISPPARAMS_UserSize
|
|
//
|
|
// Synopsis: Get the wire size for the DISPPARAMS handle and data.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align + 12 + data size.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned long __RPC_USER
|
|
DISPPARAMS_UserSize (
|
|
unsigned long * pFlags,
|
|
unsigned long Offset,
|
|
DISPPARAMS * pDispParams)
|
|
{
|
|
if ( !pDispParams )
|
|
return Offset;
|
|
|
|
LENGTH_ALIGN( Offset, 3 );
|
|
|
|
Offset += sizeof(DISPPARAMS);
|
|
|
|
if ( pDispParams->cArgs && pDispParams->rgvarg )
|
|
{
|
|
// conformant size for the variant array.
|
|
Offset += sizeof(unsigned long);
|
|
|
|
// markers
|
|
Offset += pDispParams->cArgs * sizeof(unsigned long);
|
|
|
|
unsigned int carg = pDispParams->cArgs;
|
|
|
|
for (int i = 0; carg-- ; i++)
|
|
{
|
|
Offset = VARIANT_UserSize( pFlags,
|
|
Offset,
|
|
& pDispParams->rgvarg[i] );
|
|
}
|
|
}
|
|
|
|
// conformant size + dispid array.
|
|
|
|
if ( pDispParams->cNamedArgs && pDispParams->rgdispidNamedArgs )
|
|
Offset += sizeof (unsigned long) +
|
|
pDispParams->cNamedArgs * sizeof(DISPID);
|
|
|
|
return( Offset );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DISPPARAMS_UserMarshall
|
|
//
|
|
// Synopsis: Marshalls an DISPPARAMS object into the RPC buffer.
|
|
//
|
|
// Derivation:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
DISPPARAMS_UserMarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
DISPPARAMS * pDispParams)
|
|
{
|
|
if ( !pDispParams )
|
|
return pBuffer;
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
|
|
WdtpMemoryCopy( pBuffer, pDispParams, sizeof(DISPPARAMS) );
|
|
pBuffer += sizeof(DISPPARAMS);
|
|
|
|
if ( pDispParams->cArgs && pDispParams->rgvarg )
|
|
{
|
|
uchar * pPointee;
|
|
|
|
// conformant size for the variant array.
|
|
*( PULONG_LV_CAST pBuffer)++ = pDispParams->cArgs;
|
|
|
|
pPointee = pBuffer + pDispParams->cArgs * sizeof(unsigned long);
|
|
|
|
unsigned int carg = pDispParams->cArgs;
|
|
|
|
for (int i = 0; carg-- ; i++)
|
|
{
|
|
*( PULONG_LV_CAST pBuffer)++ = USER_MARSHAL_MARKER;
|
|
pPointee = VARIANT_UserMarshal( pFlags,
|
|
pPointee,
|
|
& pDispParams->rgvarg[i] );
|
|
}
|
|
|
|
pBuffer = pPointee;
|
|
}
|
|
|
|
if ( pDispParams->cNamedArgs && pDispParams->rgdispidNamedArgs )
|
|
{
|
|
ALIGN( pBuffer, 3 );
|
|
|
|
*( PULONG_LV_CAST pBuffer)++ = pDispParams->cNamedArgs;
|
|
WdtpMemoryCopy( pBuffer,
|
|
pDispParams->rgdispidNamedArgs,
|
|
pDispParams->cNamedArgs * sizeof(DISPID) );
|
|
pBuffer += pDispParams->cNamedArgs * sizeof(DISPID);
|
|
}
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DISPPARAMS_UserUnmarshall
|
|
//
|
|
// Synopsis: Unmarshalls an DISPPARAMS object from the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
DISPPARAMS_UserUnmarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
DISPPARAMS * pDispParams)
|
|
{
|
|
if ( !pDispParams )
|
|
return pBuffer;
|
|
|
|
// see if we can reuse
|
|
|
|
DISPPARAMS TmpDP;
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
WdtpMemoryCopy( & TmpDP, pBuffer, sizeof(DISPPARAMS) );
|
|
pBuffer += sizeof(DISPPARAMS);
|
|
|
|
if ( TmpDP.cArgs != pDispParams->cArgs ||
|
|
TmpDP.cNamedArgs != pDispParams->cNamedArgs )
|
|
{
|
|
// cannot reuse it.
|
|
|
|
if ( pDispParams->cArgs || pDispParams->cNamedArgs )
|
|
DISPPARAMS_UserFree( pFlags, pDispParams );
|
|
|
|
pDispParams->cArgs = TmpDP.cArgs;
|
|
pDispParams->cNamedArgs = TmpDP.cNamedArgs;
|
|
}
|
|
|
|
if ( pDispParams->cArgs && ! pDispParams->rgvarg )
|
|
{
|
|
pDispParams->rgvarg = (VARIANT*) WdtpAllocate(
|
|
pFlags,
|
|
pDispParams->cArgs * sizeof( VARIANT ) );
|
|
WdtpZeroMemory( pDispParams->rgvarg,
|
|
pDispParams->cArgs * sizeof( VARIANT ) );
|
|
}
|
|
|
|
|
|
if ( pDispParams->cArgs && pDispParams->rgvarg )
|
|
{
|
|
// skip the conformant size for the variant array and the markers.
|
|
|
|
pBuffer += sizeof(unsigned long) +
|
|
pDispParams->cArgs * sizeof(unsigned long);
|
|
|
|
unsigned int carg = pDispParams->cArgs;
|
|
|
|
for (int i = 0; carg-- ; i++)
|
|
{
|
|
pBuffer = VARIANT_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pDispParams->rgvarg[i] );
|
|
}
|
|
}
|
|
|
|
if ( pDispParams->cNamedArgs && ! pDispParams->rgdispidNamedArgs )
|
|
{
|
|
pDispParams->rgdispidNamedArgs = (DISPID*) WdtpAllocate(
|
|
pFlags,
|
|
pDispParams->cNamedArgs * sizeof( DISPID ) );
|
|
}
|
|
|
|
if ( pDispParams->cNamedArgs && pDispParams->rgdispidNamedArgs )
|
|
{
|
|
// skip the conformant size.
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
pBuffer += sizeof(unsigned long);
|
|
|
|
WdtpMemoryCopy( pDispParams->rgdispidNamedArgs,
|
|
pBuffer,
|
|
pDispParams->cNamedArgs * sizeof(DISPID) );
|
|
pBuffer += pDispParams->cNamedArgs * sizeof(DISPID);
|
|
}
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DISPPARAMS_UserFree
|
|
//
|
|
// Synopsis: Free an DISPPARAMS.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void __RPC_USER
|
|
DISPPARAMS_UserFree(
|
|
unsigned long * pFlags,
|
|
DISPPARAMS * pDispParams)
|
|
{
|
|
|
|
if( pDispParams)
|
|
{
|
|
if ( pDispParams->rgvarg )
|
|
{
|
|
unsigned int carg = pDispParams->cArgs;
|
|
|
|
for (int i = 0; carg-- ; i++)
|
|
VARIANT_UserFree( pFlags, & pDispParams->rgvarg[i] );
|
|
|
|
WdtpFree( pFlags, pDispParams->rgvarg );
|
|
}
|
|
|
|
if ( pDispParams->rgdispidNamedArgs )
|
|
WdtpFree( pFlags, pDispParams->rgdispidNamedArgs );
|
|
|
|
WdtpZeroMemory( pDispParams, sizeof(DISPPARAMS) );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// #########################################################################
|
|
//
|
|
// EXCEPINFO
|
|
//
|
|
// #########################################################################
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EXCEPINFO_UserSize
|
|
//
|
|
// Synopsis: Get the wire size for the EXCEPINFO handle and data.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align + 12 + data size.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned long __RPC_USER
|
|
EXCEPINFO_UserSize (
|
|
unsigned long * pFlags,
|
|
unsigned long Offset,
|
|
EXCEPINFO * pExcepInfo)
|
|
{
|
|
if ( pExcepInfo == NULL )
|
|
return Offset;
|
|
|
|
if ( pExcepInfo->pvReserved || pExcepInfo->pfnDeferredFillIn )
|
|
RpcRaiseException(ERROR_BAD_ARGUMENTS);
|
|
|
|
LENGTH_ALIGN( Offset, 3 );
|
|
|
|
Offset += sizeof( EXCEPINFO );
|
|
if ( pExcepInfo->bstrSource )
|
|
Offset = BSTR_UserSize( pFlags,
|
|
Offset,
|
|
& pExcepInfo->bstrSource );
|
|
if ( pExcepInfo->bstrDescription )
|
|
Offset = BSTR_UserSize( pFlags,
|
|
Offset,
|
|
& pExcepInfo->bstrDescription );
|
|
if ( pExcepInfo->bstrHelpFile )
|
|
Offset = BSTR_UserSize( pFlags,
|
|
Offset,
|
|
& pExcepInfo->bstrHelpFile );
|
|
|
|
return( Offset );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EXCEPINFO_UserMarshall
|
|
//
|
|
// Synopsis: Marshalls an EXCEPINFO object into the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
EXCEPINFO_UserMarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
EXCEPINFO * pExcepInfo)
|
|
{
|
|
if ( pExcepInfo == NULL )
|
|
return pBuffer;
|
|
|
|
if ( pExcepInfo->pvReserved || pExcepInfo->pfnDeferredFillIn )
|
|
RpcRaiseException(ERROR_BAD_ARGUMENTS);
|
|
|
|
ALIGN( pBuffer, 3 );
|
|
|
|
WdtpMemoryCopy( pBuffer, pExcepInfo, sizeof(EXCEPINFO) );
|
|
pBuffer += sizeof( EXCEPINFO );
|
|
|
|
if ( pExcepInfo->bstrSource )
|
|
pBuffer = BSTR_UserMarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrSource );
|
|
if ( pExcepInfo->bstrDescription )
|
|
pBuffer = BSTR_UserMarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrDescription );
|
|
if ( pExcepInfo->bstrHelpFile )
|
|
pBuffer = BSTR_UserMarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrHelpFile );
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EXCEPINFO_UserUnmarshall
|
|
//
|
|
// Synopsis: Unmarshalls an EXCEPINFO object from the RPC buffer.
|
|
//
|
|
// Derivation: Conformant struct with a flag field:
|
|
// align, size, null flag, size, data (bytes, if any)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
unsigned char __RPC_FAR * __RPC_USER
|
|
EXCEPINFO_UserUnmarshal (
|
|
unsigned long * pFlags,
|
|
unsigned char * pBuffer,
|
|
EXCEPINFO * pExcepInfo)
|
|
{
|
|
ALIGN( pBuffer, 3 );
|
|
|
|
// no reusage for EXCEPINFO struct.
|
|
|
|
EXCEPINFO_UserFree( pFlags, pExcepInfo );
|
|
|
|
WdtpMemoryCopy( pExcepInfo, pBuffer, sizeof(EXCEPINFO) );
|
|
pBuffer += sizeof( EXCEPINFO );
|
|
|
|
if ( pExcepInfo->bstrSource )
|
|
{
|
|
pExcepInfo->bstrSource = NULL;
|
|
pBuffer = BSTR_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrSource );
|
|
}
|
|
|
|
if ( pExcepInfo->bstrDescription )
|
|
{
|
|
pExcepInfo->bstrDescription = NULL;
|
|
pBuffer = BSTR_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrDescription );
|
|
}
|
|
|
|
if ( pExcepInfo->bstrHelpFile )
|
|
{
|
|
pExcepInfo->bstrHelpFile = NULL;
|
|
pBuffer = BSTR_UserUnmarshal( pFlags,
|
|
pBuffer,
|
|
& pExcepInfo->bstrHelpFile );
|
|
}
|
|
|
|
return( pBuffer );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EXCEPINFO_UserFree
|
|
//
|
|
// Synopsis: Free an EXCEPINFO.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void __RPC_USER
|
|
EXCEPINFO_UserFree(
|
|
unsigned long * pFlags,
|
|
EXCEPINFO * pExcepInfo)
|
|
{
|
|
if( pExcepInfo)
|
|
{
|
|
if ( pExcepInfo->bstrSource )
|
|
BSTR_UserFree( pFlags, & pExcepInfo->bstrSource );
|
|
|
|
if ( pExcepInfo->bstrDescription )
|
|
BSTR_UserFree( pFlags, & pExcepInfo->bstrDescription );
|
|
|
|
if ( pExcepInfo->bstrHelpFile )
|
|
BSTR_UserFree( pFlags, & pExcepInfo->bstrHelpFile );
|
|
|
|
pExcepInfo->pfnDeferredFillIn = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|