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
5 $$ http://code.google.com/p/googletest/wiki/PumpManual
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.
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.
14 #ifndef REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_
15 #define REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_
19 #include "base/basictypes.h"
20 #include "base/template_util.h"
21 #include "base/win/scoped_variant.h"
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.
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
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 {
57 // Wrap() routines pack the input parameters into VARIANTARG structures so
58 // that they can be passed to IDispatch::Invoke.
60 HRESULT Wrap(const VARIANT& param) {
61 DCHECK(vt == VT_EMPTY);
62 return VariantCopy(this, ¶m);
65 HRESULT Wrap(VARIANT* const & param) {
66 DCHECK(vt == VT_EMPTY);
68 // Make the input value of an [in] [out] parameter visible to
69 // IDispatch::Invoke().
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.
78 // Unwrap() routines unpack the output parameters from VARIANTARG structures
79 // to the locations specified by the caller.
81 void Unwrap(const VARIANT& param_out) {
82 // Do nothing for an [in] parameter.
85 void Unwrap(VARIANT* const & param_out) {
86 // Return the output value of an [in] [out] parameter to the caller.
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;
96 *static_cast<VARIANTARG*>(this) = temp;
99 DISALLOW_COPY_AND_ASSIGN(ScopedVariantArg);
102 // Make sure the layouts of |VARIANTARG| and |ScopedVariantArg| are identical.
103 static_assert(sizeof(ScopedVariantArg) == sizeof(VARIANTARG),
104 "scoped variant arg should not add data members");
106 } // namespace internal
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.
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.
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
128 $if ARITY > 0 [[template <$for ARG , [[typename P$(ARG)]]>]]
130 HRESULT Invoke(IDispatch* object,
131 LPCOLESTR const_name,
135 const P$(ARG)& p$(ARG),
138 VARIANT* const & result_out) {
139 // Retrieve the ID of the method to be called.
141 LPOLESTR name = const_cast<LPOLESTR>(const_name);
142 HRESULT hr = object->GetIDsOfNames(
143 IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &disp_id);
147 // Request the return value if asked by the caller.
148 internal::ScopedVariantArg result;
149 VARIANT* disp_result = NULL;
150 if (result_out != NULL)
151 disp_result = &result;
155 // Wrap the parameters into an array of VARIANT structures.
156 internal::ScopedVariantArg disp_args[$(ARITY)];
159 hr = disp_args[$(ARITY) - $(ARG)].Wrap(p$(ARG));
166 // Invoke the method passing the parameters via the DISPPARAMS structure.
167 // DISPATCH_PROPERTYPUT and DISPATCH_PROPERTYPUTREF require the parameter of
168 // the property setter to be named, so |cNamedArgs| and |rgdispidNamedArgs|
169 // structure members should be initialized.
172 DISPPARAMS disp_params = { disp_args, NULL, $(ARITY), 0 };
174 DISPPARAMS disp_params = { NULL, NULL, 0, 0 };
177 DISPID dispid_named = DISPID_PROPERTYPUT;
178 if (flags == DISPATCH_PROPERTYPUT || flags == DISPATCH_PROPERTYPUTREF) {
179 disp_params.cNamedArgs = 1;
180 disp_params.rgdispidNamedArgs = &dispid_named;
183 hr = object->Invoke(disp_id, IID_NULL, LOCALE_USER_DEFAULT, flags,
184 &disp_params, disp_result, NULL, NULL);
190 // Unwrap the parameters.
193 disp_args[$(ARITY) - $(ARG)].Unwrap(p$(ARG));
198 // Unwrap the return value.
199 if (result_out != NULL) {
200 result.Unwrap(result_out);
208 } // namespace dispatch
210 } // namespace remoting
212 #endif // REMOTING_BASE_IDISPATCH_DRIVER_WIN_H_