| $$ 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: |
| $$ |
| $$ https://github.com/google/googletest/blob/master/googletest/docs/PumpManual.md |
| |
| $$ 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 (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/macros.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. |
| 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_ |