Home | History | Annotate | Download | only in base
      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, &param);
     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