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