NT4/private/ole32/stg/props/iprop/call_as.c
2020-09-30 17:12:29 +02:00

634 lines
20 KiB
C

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994.
//
// File: call_as.c
//
// Contents: [call_as] wrapper functions for COMMON\types.
//
// Functions: IEnumSTATPROPSTG_Next_Proxy
// IEnumSTATPROPSTG_Next_Stub
// IEnumSTATPROPSETSTG_Next_Proxy
// IEnumSTATPROPSETSTG_Next_Stub
// IPropertyStorage_WriteMultiple_Proxy
// IPropertyStorage_WriteMultiple_Stub
// IPropertyStorage_ReadMultiple_Proxy
// IPropertyStorage_ReadMultiple_Stub
// IPropertyStorage_DeleteMultiple_Proxy
// IPropertyStorage_DeleteMultiple_Stub
//
// History:
//
//--------------------------------------------------------------------------
#include <rpcproxy.h>
#include <debnot.h>
#include "prstg_ca.h" // For IPropertyStorage [call_as] routines.
#pragma code_seg(".orpc")
#define ASSERT(expr) Win4Assert(expr)
//+-------------------------------------------------------------------------
//
// Function: IEnumSTATPROPSTG_Next_Proxy
//
// Synopsis:
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE IEnumSTATPROPSTG_Next_Proxy(
IEnumSTATPROPSTG __RPC_FAR * This,
/* [in] */ ULONG celt,
/* [out] */ STATPROPSTG __RPC_FAR *rgelt,
/* [unique][out][in] */ ULONG __RPC_FAR *pceltFetched)
{
HRESULT hr;
ULONG celtFetched = 0;
if((celt > 1) && (pceltFetched == 0))
return E_INVALIDARG;
hr = IEnumSTATPROPSTG_RemoteNext_Proxy(This, celt, rgelt, &celtFetched);
if (pceltFetched != 0)
{
*pceltFetched = celtFetched;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: IEnumSTATPROPSTG_Next_Stub
//
// Synopsis:
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE IEnumSTATPROPSTG_Next_Stub(
IEnumSTATPROPSTG __RPC_FAR * This,
/* [in] */ ULONG celt,
/* [length_is][size_is][out] */ STATPROPSTG __RPC_FAR *rgelt,
/* [out] */ ULONG __RPC_FAR *pceltFetched)
{
return This->lpVtbl->Next(This, celt, rgelt, pceltFetched);
}
//+-------------------------------------------------------------------------
//
// Function: IEnumSTATPROPSETSTG_Next_Proxy
//
// Synopsis:
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE IEnumSTATPROPSETSTG_Next_Proxy(
IEnumSTATPROPSETSTG __RPC_FAR * This,
/* [in] */ ULONG celt,
/* [out] */ STATPROPSETSTG __RPC_FAR *rgelt,
/* [unique][out][in] */ ULONG __RPC_FAR *pceltFetched)
{
HRESULT hr;
ULONG celtFetched = 0;
if((celt > 1) && (pceltFetched == 0))
return E_INVALIDARG;
hr = IEnumSTATPROPSETSTG_RemoteNext_Proxy(This, celt, rgelt, &celtFetched);
if (pceltFetched != 0)
{
*pceltFetched = celtFetched;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: IEnumSTATPROPSETSTG_Next_Stub
//
// Synopsis:
//
//--------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE IEnumSTATPROPSETSTG_Next_Stub(
IEnumSTATPROPSETSTG __RPC_FAR * This,
/* [in] */ ULONG celt,
/* [length_is][size_is][out] */ STATPROPSETSTG __RPC_FAR *rgelt,
/* [out] */ ULONG __RPC_FAR *pceltFetched)
{
return This->lpVtbl->Next(This, celt, rgelt, pceltFetched);
}
//+-------------------------------------------------------------------------
//
// Function: IPropertyStorage_WriteMultiple_Proxy
// (See "prstg_ca.c" for an overview)
//
// Synopsis: With a WriteMultiple, we must convert
// the input PropVariant array so that it
// is marshalable. The property which
// makes a PropVariant un-marshalable is the BSTR.
// So we convert BSTRs to BLOBs (actually, BSTR_BLOBs).
//
// We don't modify the caller's PropVariant[],
// since it may not be writable, rather we create a
// copy of the PropVariant[] if there are some BSTRs
// in it. We tell the stub if
// any BSTRs are present, so the stub doesn't
// have to search the PropVariant[] to find out.
//
// Aside from BSTRs, we also assume that non-simple
// properties are not marshalable We assume this
// because we assume that this code will only run
// on systems where OLE doesn't already provide
// the IProperty marshaling code - Win95 & NT 3.51 -
// and on those systems, a bug in the RPC runtime
// prevents interface pointers in unions from
// being marshaled. So, if we discover a non-
// simple property, we return with a failure.
//
// Note: The PROPSPEC and PROPVARIANT arrays
// must be typed in the form of a pointer in
// this interface. See the
// IPropertyStorage_DeleteMultiple_Proxy/Stub
// comments for an explanation.
//
//+-------------------------------------------------------------------------
STDMETHODIMP
IPropertyStorage_WriteMultiple_Proxy(
IPropertyStorage __RPC_FAR *This,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC rgpspec[],
/*[in, size_is(cpspec)]*/
const PROPVARIANT rgpropvar[],
/*[in]*/ PROPID propidNameFirst
)
{
HRESULT hr = S_OK;
ULONG ulVTExists;
// The remotable PropVariant[]
PROPVARIANT *rgpropvarRem = NULL;
// Are there any special properties which we must handle?
if( NULL != rgpropvar
&&
( ulVTExists = ContainsSpecialProperty( cpspec, rgpropvar ))
)
{
// Was there a non-simple property?
if( ulVTExists & NONSIMPLE_EXISTS )
{
hr = RPC_E_CLIENT_CANTMARSHAL_DATA;
goto Exit;
}
// Otherwise, there must have been a BSTR property
else
{
ULONG ulIndex;
// Allocate a new PropVariant[]. We'll copy the
// original PropVariant into this for pre-marshaling
// (we must make a copy because we don't want to modify
// our caller's buffer, which may not even be writable).
rgpropvarRem = CoTaskMemAlloc( cpspec * sizeof(*rgpropvarRem) );
if( NULL == rgpropvarRem )
{
hr = E_OUTOFMEMORY;
goto Exit;
}
memset( rgpropvarRem, 0, cpspec * sizeof(*rgpropvarRem) );
// Copy each element of rgpropvar into rgpropvarRem
for( ulIndex = 0; ulIndex < cpspec; ulIndex++ )
{
hr = PropVariantCopy( &rgpropvarRem[ ulIndex ],
&rgpropvar[ ulIndex ] );
if( FAILED(hr) ) goto Exit;
}
// Pre-marshal this PropVariant[], converting the
// BSTRs to BSTR_BLOBs.
hr = PropVarMarshal( cpspec, rgpropvarRem );
if( FAILED(hr) ) goto Exit;
} // if( ulExists & NONSIMPLE_EXISTS ) ... else
} // if( NULL != rgpropvar ...
else
{
// No pre-marshaling is necessary.
rgpropvarRem = (PROPVARIANT*) rgpropvar;
} // if( NULL != rgpropvar ... else
// Perform the WriteMultiple
hr = IPropertyStorage_RemoteWriteMultiple_Proxy( This,
rgpropvar != rgpropvarRem, // BSTR exists?
cpspec, rgpspec,
rgpropvarRem,
propidNameFirst );
// ----
// Exit
// ----
Exit:
// If we created a pre-marshaled array, free it now
if( NULL != rgpropvarRem
&&
rgpropvar != rgpropvarRem )
{
FreePropVariantArray( cpspec, rgpropvarRem );
CoTaskMemFree( rgpropvarRem );
}
return( hr );
} // IPropertyStorage_WriteMultiple_Proxy
//+-------------------------------------------------------------------------
//
// Function: IPropertyStorage_Write_Multiple_Stub
// (See "prstg_ca.c" for an overview)
//
// Synopsis: This routine finishes the unmarshaling
// of an array of PropVariants by making
// regular BSTRs out of BSTR_BLOBs.
//
// The fBstrPresent flag indicates if any
// such conversion is required. After
// fixing the PropVariant[], we pass
// the call on to the server.
//
// Note: The PROPSPEC and PROPVARIANT arrays
// must be typed in the form of a pointer in
// this interface. See the
// IPropertyStorage_DeleteMultiple_Proxy/Stub
// comments for an explanation.
//
//+-------------------------------------------------------------------------
STDMETHODIMP
IPropertyStorage_WriteMultiple_Stub(
IPropertyStorage __RPC_FAR *This,
/*[in]*/ BOOL fBstrPresent,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC *rgpspec,
/*[in, size_is(cpspec)]*/
const PROPVARIANT *rgpropvarRem,
/*[in]*/ PROPID propidNameFirst
)
{
HRESULT hr = S_OK;
ULONG ulIndex;
// The un-marshaled PropVariant[].
PROPVARIANT *rgpropvar = NULL;
// Is any BSTR-unmarshaling required?
if( fBstrPresent )
{
// Make a copy of the PropVariant[] so that we can
// modify pointers (we're going to need to free buffers
// during PropVarUnmarshal, and rgpropvarRem may not be
// allocated in the IMalloc heap).
rgpropvar = (PROPVARIANT*) CoTaskMemAlloc( cpspec * sizeof(*rgpropvar) );
if( NULL == rgpropvar )
{
hr = E_OUTOFMEMORY;
goto Exit;
}
memset( rgpropvar, 0, cpspec * sizeof(*rgpropvar) );
// Copy the individual PropVariants. BSTR_BLOBs
// in the destination will be in IMalloc heap.
for( ulIndex = 0; ulIndex < cpspec; ulIndex++ )
{
hr = PropVariantCopy( &rgpropvar[ ulIndex ],
&rgpropvarRem[ ulIndex ] );
if( FAILED(hr) ) goto Exit;
}
// Unmarshal the PropVariant[]. BSTRs will be in the
// OleAutomation heap.
hr = PropVarUnmarshal( cpspec,
rgpropvar );
if( FAILED(hr) ) goto Exit;
}
else
{
// No unmarshaling is required.
rgpropvar = (PROPVARIANT*) rgpropvarRem;
} // if( fBstrPresent )
// Write the properties.
hr = This->lpVtbl->WriteMultiple( This, cpspec, rgpspec,
rgpropvar,
propidNameFirst );
// ----
// Exit
// ----
Exit:
// If we allocated a new PropVariant array during the Unmarshaling,
// free it now.
if( rgpropvar != rgpropvarRem
&&
NULL != rgpropvar )
{
FreePropVariantArray( cpspec, rgpropvar );
}
return( hr );
} // IPropertyStorage_WriteMultiple_Stub
//+-----------------------------------------------------------------------
//
// Function: IPropertyStorage_ReadMultiple_Proxy
// (See "prstg_ca.c" for an overview)
//
// Synopsis: This routine first passes the request
// on to the Server. If the Server indicates
// in the return result that the PropVariant
// array has specially-marshaled BSTR
// properties, then this routine restores
// them to normal BSTRs. This is necessary
// because there is no standard marshaling
// support for BSTRs.
//
// BSTR properties are made marshalable
// on the Server side by converting them
// to BLOBs, and changing their type
// from VT_BSTR to VT_BSTR_BLOB.
//
// Note: The PROPSPEC and PROPVARIANT arrays
// must be typed in the form of a pointer in
// this interface. See the
// IPropertyStorage_DeleteMultiple_Proxy/Stub
// comments for an explanation.
//
//+-----------------------------------------------------------------------
STDMETHODIMP
IPropertyStorage_ReadMultiple_Proxy(
IPropertyStorage __RPC_FAR *This,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC rgpspec[],
/*[in, size_is(cpspec)]*/
PROPVARIANT rgpropvar[]
)
{
HRESULT hr = E_FAIL;
HRESULT hrPrivate = S_OK;
BOOL fBstrPresent;
// Pass the call on to the server
hr = IPropertyStorage_RemoteReadMultiple_Proxy( This, &fBstrPresent,
cpspec, rgpspec, rgpropvar );
if( FAILED(hr) ) goto Exit;
// Were there any BSTR properties?
if( fBstrPresent )
{
// Finish un-marshaling the PropVariant[] by
// restoring the BSTRs from BSTR_BLOBs. The BSTRs
// will be allocated from the OleAutomation heap.
// We save into hrPrivate so that if the RemoteReadMultiple
// call returns a success-code, we won't lose it in this
// un-marshaling call.
hrPrivate = PropVarUnmarshal( cpspec,
rgpropvar);
if( FAILED(hrPrivate) )
{
// Free the PropVariant[]; the caller expects
// to get all VT_EMPTYs if there was an error.
hr = hrPrivate;
FreePropVariantArray( cpspec, rgpropvar );
goto Exit;
}
} // if( fBstrPresent )
// ----
// Exit
// ----
Exit:
return( hr );
}
//+---------------------------------------------------------------------------------
//
// Function: IPropertyStorage_ReadMultiple_Stub
// (See "prstg_ca.c" for an overview)
//
// Synopsis: This routine passes the ReadMultiple
// request on to the Server. The result
// is then pre-marshaled; that is, the
// PropVariant is converted so that it is in
// remotable form. This entails converting
// BSTRs (which aren't marshalable) into
// BSTRBLOBs. Note that there could be a BSTR
// property, and/or a vector of BSTRs, and/or
// a vector of Variants where one Variant is a
// BSTR.
//
// Aside from BSTRs, we also assume that non-simple
// properties are not marshalable We assume this
// because we assume that this code will only run
// on systems where OLE doesn't already provide
// the IProperty marshaling code - Win95 & NT 3.51 -
// and on those systems, a bug in the RPC runtime
// prevents interface pointers in unions from
// being marshaled. So, if we discover a non-
// simple property, we return with a failure.
//
// Note: The PROPSPEC and PROPVARIANT arrays
// must be typed in the form of a pointer in
// this interface. See the
// IPropertyStorage_DeleteMultiple_Proxy/Stub
// comments for an explanation.
//
//+---------------------------------------------------------------------------------
STDMETHODIMP
IPropertyStorage_ReadMultiple_Stub(
IPropertyStorage __RPC_FAR *This,
/*[out]*/ BOOL *pfBstrPresent,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC *rgpspec,
/*[out, size_is(cpspec)]*/
PROPVARIANT *rgpropvar
)
{
HRESULT hr = S_OK;
HRESULT hrPrivate = S_OK;
ULONG ulVTExists;
// Assume that there will be no BSTRs read.
*pfBstrPresent = FALSE;
// Pass on the ReadMultiple request to the Server
hr = This->lpVtbl->ReadMultiple( This, cpspec, rgpspec, rgpropvar );
if( FAILED(hr) ) goto Exit;
// Are there special properties that we need to worry about?
if( ulVTExists = ContainsSpecialProperty( cpspec, rgpropvar ))
{
// Yes. Is it a non-simple property? If so, we can't marshal
// it (see the synopsis above).
if( ulVTExists & NONSIMPLE_EXISTS )
{
hr = RPC_E_SERVER_CANTMARSHAL_DATA;
goto Exit;
}
// Otherwise, there must be a BSTR property in the PROPVARIANT[].
else
{
// Let the caller know that post-marshaling will be required.
*pfBstrPresent = TRUE;
// Pre-marshal the read PropVariant[]. BSTRs
// (allocated in the OleAut heap) will be converted
// to BSTR_BLOBs (in the IMalloc heap).
hrPrivate = PropVarMarshal( cpspec,
rgpropvar );
if( FAILED(hrPrivate) )
{
hr = hrPrivate;
goto Exit;
}
} // if( ulVTExists & NONSIMPLE_EXISTS ) ... else
} // if( ulVTExists = ContainsSpecialProperties( cpspec, rgpropvar ))
// ----
// Exit
// ----
Exit:
if( FAILED(hr) )
{
// Free the array, returning all VT_EMPTYs to the
// caller.
FreePropVariantArray( cpspec, rgpropvar );
}
return( hr );
}
//+----------------------------------------------------------------------------------
//
// Function: IPropertyStorage_DeleteMultiple_Proxy/Stub
//
// Synopsis: The purpose of these routines is not obvious.
// Midl can produce "fat" or "skinny" proxies and
// stubs. A fat Proxy/Stub can be generated with the
// "-Os" option. This generates inline Proxy/Stub
// code which uses the RPCRT4 library, and which
// the Client/Server statically link. A skinny
// Proxy/Stub can be generated with the "-Oi[#]"
// option. This generates only a small amount
// of inline code, which calls to dynamically linked
// RPC interperator to do the majority of the work.
//
// The interperated method is preferable. However,
// in order to keep the interperator small, it cannot
// handle certain interfaces which are in some way
// too complicated. In such cases, inline code is
// generated instead. The PROPSPEC array on the
// Delete/Read/WriteMultiple routines is one such
// complication, as is the PROPVARIANT array.
// However, by simply changing these parameters
// to pointers, rather than arrays, the complication
// is removed.
//
// The public ([local]) routines must remain
// array-based, but the remotable routines are
// pointer-based. Thus, the purpose of the DeleteMultiple
// [call_as] code is to simply convert between the
// two types of interfaces. This conversion is handled
// implicitely by the compiler.
//
//+----------------------------------------------------------------------------------
STDMETHODIMP
IPropertyStorage_DeleteMultiple_Proxy(
IPropertyStorage __RPC_FAR *This,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC rgpspec[]
)
{
return( IPropertyStorage_RemoteDeleteMultiple_Proxy( This, cpspec, rgpspec ));
}
STDMETHODIMP
IPropertyStorage_DeleteMultiple_Stub(
IPropertyStorage __RPC_FAR *This,
/*[in]*/ ULONG cpspec,
/*[in, size_is(cpspec)]*/
const PROPSPEC *rgpspec
)
{
return( This->lpVtbl->DeleteMultiple( This, cpspec, rgpspec) );
}