1$$ This is a pump file for generating file templates. Pump is a python 2$$ script that is part of the Google Test suite of utilities. Description 3$$ can be found here: 4$$ 5$$ http://code.google.com/p/googletest/wiki/PumpManual 6 7$$ MAX_ARITY controls the number of arguments that dispatch::Invoke() supports. 8$$ It is choosen to match the number of arguments base::Bind() supports. 9$var MAX_ARITY = 7 10// Copyright (c) 2012 The Chromium Authors. All rights reserved. 11// Use of this source code is governed by a BSD-style license that can be 12// found in the LICENSE file. 13 14#ifndef REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_ 15#define REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_ 16 17#include <oaidl.h> 18 19#include "base/basictypes.h" 20#include "base/template_util.h" 21#include "base/win/scoped_variant.h" 22 23namespace remoting { 24 25namespace dispatch { 26 27namespace internal { 28 29// A helper wrapper for |VARIANTARG| that is used to pass parameters to and from 30// IDispatch::Invoke(). The latter accepts parameters as an array of 31// |VARIANTARG| structures. The calling convention of IDispatch::Invoke() is: 32// - [in] parameters are initialized and freed if needed by the caller. 33// - [out] parameters are initialized by IDispatch::Invoke(). It is up to 34// the caller to free leakable variants (such as VT_DISPATCH). 35// - [in] [out] parameters are combination of both: the caller initializes 36// them before the call and the callee assigns new values correctly 37// freeing leakable variants. 38// 39// Using |ScopedVariantArg| instead of naked |VARIANTARG| ensures that 40// the resources allocated during the call will be properly freed. It also 41// provides wrapping methods that convert between C++ types and VARIANTs. 42// At the moment the only supported parameter type is |VARIANT| (or 43// |VARIANTARG|). 44// 45// It must be possible to cast a pointer to an array of |ScopedVariantArg| to 46// a pointer to an array of |VARIANTARG| structures. 47class ScopedVariantArg : public VARIANTARG { 48 public: 49 ScopedVariantArg() { 50 vt = VT_EMPTY; 51 } 52 53 ~ScopedVariantArg() { 54 VariantClear(this); 55 } 56 57 // Wrap() routines pack the input parameters into VARIANTARG structures so 58 // that they can be passed to IDispatch::Invoke. 59 60 HRESULT Wrap(const VARIANT& param) { 61 DCHECK(vt == VT_EMPTY); 62 return VariantCopy(this, ¶m); 63 } 64 65 HRESULT Wrap(VARIANT* const & param) { 66 DCHECK(vt == VT_EMPTY); 67 68 // Make the input value of an [in] [out] parameter visible to 69 // IDispatch::Invoke(). 70 // 71 // N.B. We treat both [out] and [in] [out] parameters as [in] [out]. In 72 // other words the caller is always responsible for initializing and freeing 73 // [out] and [in] [out] parameters. 74 Swap(param); 75 return S_OK; 76 } 77 78 // Unwrap() routines unpack the output parameters from VARIANTARG structures 79 // to the locations specified by the caller. 80 81 void Unwrap(const VARIANT& param_out) { 82 // Do nothing for an [in] parameter. 83 } 84 85 void Unwrap(VARIANT* const & param_out) { 86 // Return the output value of an [in] [out] parameter to the caller. 87 Swap(param_out); 88 } 89 90 private: 91 // Exchanges the value (and ownership) of the passed VARIANT with the one 92 // wrapped by |ScopedVariantArg|. 93 void Swap(VARIANT* other) { 94 VARIANT temp = *other; 95 *other = *this; 96 *static_cast<VARIANTARG*>(this) = temp; 97 } 98 99 DISALLOW_COPY_AND_ASSIGN(ScopedVariantArg); 100}; 101 102// Make sure the layouts of |VARIANTARG| and |ScopedVariantArg| are identical. 103COMPILE_ASSERT(sizeof(ScopedVariantArg) == sizeof(VARIANTARG), 104 scoped_variant_arg_should_not_add_data_members); 105 106} // namespace internal 107 108// Invoke() is a convenience wrapper for IDispatch::Invoke. It takes care of 109// calling the desired method by its ID and implements logic for passing 110// a variable number of in/out parameters to the called method. 111// 112// The calling convention is: 113// - [in] parameters are passsed as a constant reference or by value. 114// - [out] and [in] [out] parameters are passed by pointer. The pointed value 115// is overwritten when the function returns. The pointed-to value must 116// be initialized before the call, and will be replaced when it returns. 117// [out] parameters may be initialized to VT_EMPTY. 118// 119// Current limitations: 120// - more than $(MAX_ARITY) parameters are not supported. 121// - the method ID cannot be cached and reused. 122// - VARIANT is the only supported parameter type at the moment. 123$range ARITY 0..MAX_ARITY 124$for ARITY [[ 125$range ARG 1..ARITY 126 127 128$if ARITY > 0 [[template <$for ARG , [[typename P$(ARG)]]>]] 129 130HRESULT Invoke(IDispatch* object, 131 LPOLESTR name, 132 WORD flags, 133$for ARG [[ 134 135 const P$(ARG)& p$(ARG), 136]] 137 138 VARIANT* const & result_out) { 139 // Retrieve the ID of the method to be called. 140 DISPID disp_id; 141 HRESULT hr = object->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_USER_DEFAULT, 142 &disp_id); 143 if (FAILED(hr)) 144 return hr; 145 146 // Request the return value if asked by the caller. 147 internal::ScopedVariantArg result; 148 VARIANT* disp_result = NULL; 149 if (result_out != NULL) 150 disp_result = &result; 151 152$if ARITY > 0 [[ 153 154 // Wrap the parameters into an array of VARIANT structures. 155 internal::ScopedVariantArg disp_args[$(ARITY)]; 156$for ARG [[ 157 158 hr = disp_args[$(ARITY) - $(ARG)].Wrap(p$(ARG)); 159 if (FAILED(hr)) 160 return hr; 161]] 162]] 163 164 165 // Invoke the method passing the parameters via the DISPPARAMS structure. 166 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of 167 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs| 168 // structure members should be initialized. 169 170$if ARITY > 0 [[ 171 DISPPARAMS disp_params = { disp_args, NULL, $(ARITY), 0 }; 172]] $else [[ 173 DISPPARAMS disp_params = { NULL, NULL, 0, 0 }; 174]] 175 176 DISPID dispid_named = DISPID_PROPERTYPUT; 177 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) { 178 disp_params.cNamedArgs = 1; 179 disp_params.rgdispidNamedArgs = &dispid_named; 180 } 181 182 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags, 183 &disp_params, disp_result, NULL, NULL); 184 if (FAILED(hr)) 185 return hr; 186 187$if ARITY > 0 [[ 188 189 // Unwrap the parameters. 190$for ARG [[ 191 192 disp_args[$(ARITY) - $(ARG)].Unwrap(p$(ARG)); 193]] 194]] 195 196 197 // Unwrap the return value. 198 if (result_out != NULL) { 199 result.Unwrap(result_out); 200 } 201 202 return S_OK; 203} 204 205]] 206 207} // namespace dispatch 208 209} // namespace remoting 210 211#endif // REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_ 212