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
211
|
$$ This is a pump file for generating file templates. Pump is a python
$$ script that is part of the Google Test suite of utilities. Description
$$ can be found here:
$$
$$ http://code.google.com/p/googletest/wiki/PumpManual
$$ MAX_ARITY controls the number of arguments that dispatch::Invoke() supports.
$$ It is choosen to match the number of arguments base::Bind() supports.
$var MAX_ARITY = 7
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// 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/template_util.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() {
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;
}
DISALLOW_COPY_AND_ASSIGN(ScopedVariantArg);
};
// Make sure the layouts of |VARIANTARG| and |ScopedVariantArg| are identical.
COMPILE_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,
LPOLESTR 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;
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_
|