//+------------------------------------------------------------------------- // // 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 #include #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) ); }