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 23 namespace remoting { 24 25 namespace dispatch { 26 27 namespace 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. 47 class 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. 103 COMPILE_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 130 HRESULT 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