/** \file * Implementation of QueryInterface. */ /* * Copyright © 2000-2002 Sofus Mortensen, Michael Geddes * * This material is provided "as is", with absolutely no warranty * expressed or implied. Any use is at your own risk. Permission to * use or copy this software for any purpose is hereby granted without * fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is * granted, provided the above notices are retained, and a notice that * the code was modified is included with the above copyright notice. * * This header is part of Comet version 2. * https://github.com/alamaison/comet */ #ifndef COMET_IMPQI_H #define COMET_IMPQI_H #include #include #include #include #include #include #include #include #include namespace comet { /*! \addtogroup Interfaces */ //@{ namespace impl { /** Base class for recognising qi hook. * \internal */ class qi_hook_itf_tag {}; } class qi_hook {}; template class qi_hook_itf : public impl::qi_hook_itf_tag{ public: typedef Itf exposes; virtual com_ptr get_interface_ptr(const com_ptr< ::IUnknown>&) throw() = 0; }; namespace impl { template COMET_FORCEINLINE bool is_interface_compatible(const uuid_t& iid, Itf*) { if (iid == uuidof()) return true; else return is_interface_compatible::base>(iid, 0); } template<> COMET_FORCEINLINE bool is_interface_compatible< ::IUnknown >(const uuid_t&, ::IUnknown*) { return false; } template<> COMET_FORCEINLINE bool is_interface_compatible(const uuid_t&, nil*) { return false; } enum use_cast_t {uc_false=0, uc_static, uc_static_op, uc_qi_hook_itf, uc_qi_hook }; // remove enum for VC2005B2 template struct find_compatibility_aux { template struct with { enum { is = false }; template inline static bool qi(P *, const uuid_t& , com_ptr< ::IUnknown>& ) { return false; } }; }; template<> struct find_compatibility_aux { template struct with { template static bool qi(T *This, const uuid_t& iid, com_ptr< ::IUnknown>& unk) { if (is_interface_compatible(iid, 0)) { unk = static_cast< ::IUnknown* >(static_cast(This)); return true; } return false; } }; }; template<> struct find_compatibility_aux { template struct with { template static bool qi(T *This, const uuid_t& iid, com_ptr< ::IUnknown>& unk) { if (is_interface_compatible(iid,0)) { unk = static_cast*>(This)->get_interface_ptr( cast_to_unknown(This) ); return true; } return false; } }; }; template<> struct find_compatibility_aux { template struct with { template static bool qi(T *This, const uuid_t& iid, com_ptr< ::IUnknown>& unk) { if ( static_cast(This)->qi(This, iid, unk) ) return true; else return false; } }; }; /* template<> struct find_compatibility_aux { template struct with { static bool is( const uuid_t &iid){ return is_interface_compatible(iid,0);} template static com_ptr< ::IUnknown> cast_from(T *This) { #ifndef NDEBUG try { #endif return static_cast*>(This)->get_interface_ptr( cast_to_unknown(This) ); #ifndef NDEBUG } catch (...) { // get_interface_ptr is not allowed to throw. Return null pointer on failure COMET_ASSERT(0); return 0; } #endif } }; }; template<> struct find_compatibility_aux { template struct with { static bool is( const uuid_t &iid){ return true; } template static com_ptr< ::IUnknown> cast_from(T *This) { Itf:: } }; };*/ template< typename Itf> struct use_cast_aux { enum { is_static = (type_traits::conversion::exists) }; enum { is_static_op =(type_traits::is_cast_operator_compatible::is)}; enum { is_qi_hook_itf = (type_traits::conversion::exists) }; enum { is_qi_hook = (type_traits::conversion::exists) }; // GCC Doesn't handle evaluation of ?: opeators in templates yet. // enum { is = (int)( is_static ? uc_static: ( is_static_op ? uc_static_op : uc_false)) enum { is = is_static * uc_static + is_qi_hook_itf * uc_qi_hook_itf + is_qi_hook * uc_qi_hook + is_static_op * uc_static_op }; }; template struct find_compatibility { enum { needs_cast_ = use_cast_aux::is }; typedef find_compatibility_aux< (use_cast_t)needs_cast_ > compatible; COMET_FORCEINLINE static bool with(const uuid_t &iid) { return compatible::template with::is(iid); }; template COMET_FORCEINLINE static com_ptr< ::IUnknown> cast_from( T *This) { return compatible::template with::cast_from(This); } }; template struct interface_finder { template COMET_FORCEINLINE static bool find_interface(T* This, const uuid_t& iid, com_ptr< ::IUnknown>& rv) { typedef typename find_compatibility_aux< (use_cast_t)use_cast_aux< COMET_STRICT_TYPENAME ITF_LIST::head >::is >::template with fc; if ( fc::qi(This, iid, rv) ) return true; else return interface_finder< COMET_STRICT_TYPENAME ITF_LIST::tail>::find_interface(This, iid, rv); } COMET_FORCEINLINE static bool find_interface_2(const uuid_t& iid) { if (is_interface_compatible(iid, 0)) return true; return interface_finder< COMET_STRICT_TYPENAME ITF_LIST::tail>::find_interface_2(iid); } }; template<> struct interface_finder { template COMET_FORCEINLINE static bool find_interface(T*, const uuid_t&, com_ptr< ::IUnknown>&) { return false; } COMET_FORCEINLINE static bool find_interface_2(const uuid_t&) { return false; } }; /* template<> struct interface_finder > { template COMET_FORCEINLINE static ::IUnknown* find_interface(T*, const uuid_t&) { return 0; } };*/ } /** \struct typelibrary_loader impqi.h comet/impqi.h * Type Library Loader. * Allow provision for different means of loading a type-library. * \param TL A \e Comet type-library. */ template struct typelibrary_loader { //! Load the type-library. /** Create a different template instantiation of this to load * type-libraries from a different source (example - from a second * resource in the dll). */ static inline HRESULT load( ITypeLib **pTypeLib) { return LoadRegTypeLib(uuidof(), TL::major_version, TL::minor_version, LANG_NEUTRAL, pTypeLib); } }; /** \struct implement_qi impqi.h comet/impqi.h * Implementation of QueryInterface. Inherits from all the types defined * in \p ITF_LIST. * \param ITF_LIST interface implementation list. */ template class ATL_NO_VTABLE implement_qi : public typelist::inherit_all { private: // Hide qi void qi(); public: /** Get at the unknown for this class. Is here for compatibility when using * implement_internal_qi via aggregateable_coclass for getting at a * pointer from which to QueryInterface from. */ ::IUnknown* get_unknown()const { return static_cast< typename ITF_LIST::head * >(const_cast *>(this)); } STDMETHOD(QueryInterface)(REFIID riid, void** ppv) { const uuid_t& iid = uuid_t::create_const_reference(riid); com_ptr< ::IUnknown> p; impl::interface_finder::find_interface(this, iid, p); if (!p) { if (riid != IID_IUnknown) { *ppv = 0; return E_NOINTERFACE; } p = get_unknown(); // p = static_cast< ::IUnknown* >(static_cast< typename ITF_LIST::head * >(this)); } *ppv = reinterpret_cast(p.detach()); return S_OK; } }; /** \struct implement_internal_qi impqi.h comet/impqi.h * Implementation of QueryInterfaceInternal. Inherits from all the types defined * in \p ITF_LIST. This implementation is used in aggregation. * \param ITF_LIST interface implementation list. */ template class ATL_NO_VTABLE implement_internal_qi : public typelist::inherit_all { private: void qi(); public: /** Get at the unknown for this class. Is especially useful using * aggregateable_coclass in getting at a pointer from which to * QueryInterface from. */ ::IUnknown* get_unknown()const { return static_cast< typename ITF_LIST::head * >( const_cast *>(this)); } HRESULT QueryInterfaceInternal(REFIID riid, void** ppv) { const IID& iid = riid; com_ptr< ::IUnknown> p; impl::interface_finder::find_interface(this, iid, p); if (!p) { if (riid != IID_IUnknown) { *ppv = 0; return E_NOINTERFACE; } // p = cast_to_unknown(this); p = static_cast< ::IUnknown* >(static_cast(this)); } *ppv = reinterpret_cast(p.detach()); return S_OK; } }; namespace impl { template ::IUnknown* cast_to_unknown(implement_qi* iq) { return static_cast< typename ITF_LIST::head*>(iq); } } /** \class impl_dispatch impqi.h comet/impqi.h * Implement IDispatch via type-library. */ template class ATL_NO_VTABLE impl_dispatch : public BASE { protected: /// \name IDispatch Interface //@{ STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo** ti) { *ti = get_ti(); if (*ti) { (*ti)->AddRef(); return S_OK; } return E_NOTIMPL; } STDMETHOD(GetTypeInfoCount)(UINT *it) { *it = 1; return S_OK; } STDMETHOD(GetIDsOfNames)(REFIID, OLECHAR** pNames, UINT cNames, LCID, DISPID* pdispids) { ITypeInfo* ti = get_ti(); if (ti) return ti->GetIDsOfNames(pNames, cNames, pdispids); else return E_NOTIMPL; } STDMETHOD(Invoke)(DISPID id, REFIID, LCID, WORD wFlags, DISPPARAMS *pd, VARIANT* pVarResult, EXCEPINFO* pe, UINT* pu) { ITypeInfo* ti = get_ti(); if (ti) { void* pThis = static_cast(this); return ti->Invoke(pThis, id, wFlags, pd, pVarResult, pe, pu); } else return E_NOTIMPL; } //@} private: ITypeInfo* get_ti() { static ITypeInfo* ti_; if (ti_ == 0) { auto_cs lock(module().cs()); if (ti_ == 0) { com_ptr ptl; typelibrary_loader::load(ptl.out()); if (ptl) ptl->GetTypeInfoOfGuid(uuidof(), &ti_); if (ti_ != 0) module().add_object_to_dispose( impl::create_itf_releaser(ti_) ); } } return ti_; } // static ITypeInfo* ti_; }; template class com_ptr; #if 0 /** \class aggregates_interface impqi.h comet/impqi.h * Used as an implementation for an interface to Aggregate the required * interface. */ template< typename Itf > class aggregates_interface { public: /** Set the inner-unknown returned from the call to CoCreateInstance. */ void set_aggregate(const com_ptr< ::IUnknown>& aggobj) { ag_object_ = com_cast(aggobj); } /** Used by QueryInteface algorithms to work out the interface * exposed by this class. */ typedef Itf exposes; operator Itf*() throw() { com_ptr< ::IUnknown> test = ag_object_; return ag_object_.in(); // return com_ptr( com_cast(ag_object_) ); } protected: com_ptr ag_object_; }; #endif /* class FTM : public qi_hook_itf { private: com_ptr get_interface_ptr(const com_ptr< ::IUnknown>& This) throw() { ::IUnknown* ftm = 0; CoCreateFreeThreadedMarshaler(This.in(), &ftm); return com_cast(ftm); } };*/ /** \struct FTM impqi.h comet/impqi.h * Aggregate the Free Threaded Marshaller. * \code class coclass_implementation : public coclass { ... }; \endcode */ struct FTM : public qi_hook { template bool qi(T *This, const uuid_t& iid, com_ptr< ::IUnknown>& unk) { if (iid != uuidof()) return false; ::IUnknown* ftm = 0; CoCreateFreeThreadedMarshaler(impl::cast_to_unknown(This), &ftm); unk = com_ptr< ::IMarshal>( com_cast(ftm) ); return unk != 0; } }; /** \struct aggregates impqi.h comet/impqi.h * Aggregate an interface. * \code class coclass_implementation : public coclass > { coclass_implementation() { aggregatescreate_aggregate::create_aggregate(this, CLSCTX_ALL); } }; \endcode \sa coclass */ template class aggregates : public qi_hook { com_ptr< ::IUnknown> inner_; public: template bool qi(T *This, const uuid_t& iid, com_ptr< ::IUnknown>& unk) { typedef typename make_list::result TL; if (typelist::length::value > 0) { if (impl::interface_finder::find_interface_2(iid) == false) return false; } if (inner_ == 0) return false; ::IUnknown* p; if (SUCCEEDED(inner_.raw()->QueryInterface(iid, reinterpret_cast(&p)))) { unk = auto_attach(p); return true; } return false; } protected: template void create_aggregate(T *This, DWORD dwClsContext = CLSCTX_ALL) { ::IUnknown* unk_this = impl::cast_to_unknown(This); inner_ = com_ptr< ::IUnknown>(uuidof(), com_ptr< ::IUnknown>::create_reference(unk_this), dwClsContext); } }; /* template class aggregates_interface : public qi_hook_itf { private: com_ptr< ::IUnknown> inner_; com_ptr get_interface_ptr(const com_ptr< ::IUnknown>&) { return com_cast(inner_); } protected: template void create_aggregate(const CLSID& clsid, implement_qi* This, DWORD dwClsContext = CLSCTX_ALL) { ::IUnknown* unk_this = static_cast< typename ITF_LIST::head*>(This); inner_ = com_ptr< ::IUnknown>(clsid, com_ptr< ::IUnknown>::create_reference(unk_this), dwClsContext); } template void create_aggregate(const wchar_t* progid, implement_qi* This, DWORD dwClsContext = CLSCTX_ALL) { ::IUnknown* unk_this = static_cast< typename ITF_LIST::head*>(This); inner_ = com_ptr< ::IUnknown>(progid, com_ptr< ::IUnknown>::create_reference(unk_this), dwClsContext); } };*/ //@} } #endif