634 lines
20 KiB
C
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) );
|
|
}
|
|
|
|
|