• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &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.
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