$$ 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_