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