Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages
impqi.h
Go to the documentation of this file.00001 00004 /* 00005 * Copyright © 2000-2002 Sofus Mortensen, Michael Geddes 00006 * 00007 * This material is provided "as is", with absolutely no warranty 00008 * expressed or implied. Any use is at your own risk. Permission to 00009 * use or copy this software for any purpose is hereby granted without 00010 * fee, provided the above notices are retained on all copies. 00011 * Permission to modify the code and to distribute modified code is 00012 * granted, provided the above notices are retained, and a notice that 00013 * the code was modified is included with the above copyright notice. 00014 * 00015 * This header is part of comet. 00016 * http://www.lambdasoft.dk/comet 00017 */ 00018 00019 #ifndef COMET_IMPQI_H 00020 #define COMET_IMPQI_H 00021 00022 #include <wtypes.h> 00023 00024 #include <comet/config.h> 00025 00026 #include <comet/ptr.h> 00027 #include <comet/typelist.h> 00028 #include <comet/common.h> 00029 #include <comet/type_traits.h> 00030 #include <comet/uuid_fwd.h> 00031 00032 namespace comet { 00036 00037 namespace impl { 00038 00039 template<typename Itf> COMET_FORCEINLINE bool is_interface_compatible(const uuid_t& iid, Itf*) 00040 { 00041 if (iid == uuidof<Itf>()) return true; 00042 else return is_interface_compatible<comtype<Itf>::base>(iid, 0); 00043 }; 00044 00045 template<> COMET_FORCEINLINE bool is_interface_compatible< ::IUnknown >(const uuid_t&, ::IUnknown*) 00046 { 00047 return false; 00048 }; 00049 00050 template<> COMET_FORCEINLINE bool is_interface_compatible<nil>(const uuid_t&, nil*) 00051 { 00052 return false; 00053 }; 00054 enum use_cast_t {uc_false=0, uc_static, uc_static_op, uc_qi_hook_itf, uc_qi_hook }; 00055 00056 template< enum use_cast_t > 00057 struct find_compatibility_aux 00058 { 00059 template<typename T> 00060 struct with 00061 { 00062 enum { is = false }; 00063 00064 template<typename T> inline static bool qi(T *, const uuid_t& , com_ptr<::IUnknown>& ) 00065 { 00066 return false; 00067 }; 00068 }; 00069 }; 00070 00071 template<> 00072 struct find_compatibility_aux<uc_static> 00073 { 00074 template<typename Itf> struct with { 00075 template<typename T> static bool qi(T *This, const uuid_t& iid, com_ptr<::IUnknown>& unk) 00076 { 00077 if (is_interface_compatible<Itf>(iid, 0)) 00078 { 00079 unk = static_cast< ::IUnknown* >(static_cast<Itf*>(This)); 00080 return true; 00081 } 00082 return false; 00083 } 00084 }; 00085 }; 00086 00087 template<> 00088 struct find_compatibility_aux<uc_qi_hook_itf> 00089 { 00090 template<typename Itf> struct with { 00091 template<typename T> static bool qi(T *This, const uuid_t& iid, com_ptr<::IUnknown>& unk) 00092 { 00093 if (is_interface_compatible<Itf::exposes>(iid,0)) { 00094 unk = static_cast<qi_hook_itf<Itf::exposes>*>(This)->get_interface_ptr( cast_to_unknown(This) ); 00095 return true; 00096 } 00097 return false; 00098 } 00099 }; 00100 }; 00101 00102 template<> 00103 struct find_compatibility_aux<uc_qi_hook> 00104 { 00105 template<typename Itf> struct with { 00106 template<typename T> static bool qi(T *This, const uuid_t& iid, com_ptr<::IUnknown>& unk) 00107 { 00108 if ( static_cast<Itf*>(This)->qi(This, iid, unk) ) 00109 return true; 00110 else 00111 return false; 00112 } 00113 }; 00114 }; 00115 00116 /* template<> 00117 struct find_compatibility_aux<uc_qi_hook_itf> 00118 { 00119 template<typename U> 00120 struct with 00121 { 00122 static bool is( const uuid_t &iid){ return is_interface_compatible<U::exposes>(iid,0);} 00123 template<class T> 00124 static com_ptr<::IUnknown> cast_from(T *This) 00125 { 00126 #ifndef NDEBUG 00127 try { 00128 #endif 00129 return static_cast<qi_hook_itf<Itf::exposes>*>(This)->get_interface_ptr( cast_to_unknown(This) ); 00130 #ifndef NDEBUG 00131 } catch (...) { 00132 // get_interface_ptr is not allowed to throw. Return null pointer on failure 00133 COMET_ASSERT(0); 00134 return 0; 00135 } 00136 #endif 00137 } 00138 }; 00139 }; 00140 00141 template<> 00142 struct find_compatibility_aux<uc_qi_hook> 00143 { 00144 template<typename U> 00145 struct with 00146 { 00147 static bool is( const uuid_t &iid){ return true; } 00148 00149 template<class T> 00150 static com_ptr<::IUnknown> cast_from(T *This) 00151 { 00152 Itf:: 00153 } 00154 }; 00155 };*/ 00156 00157 template< typename Itf> 00158 struct use_cast_aux 00159 { 00160 enum { is_static = (type_traits::conversion<Itf*, ::IUnknown*>::exists) }; 00161 enum { is_static_op =(type_traits::is_cast_operator_compatible<Itf, ::IUnknown>::is)}; 00162 enum { is_qi_hook_itf = (type_traits::conversion<Itf*, qi_hook_itf_tag*>::exists) }; 00163 enum { is_qi_hook = (type_traits::conversion<Itf*, qi_hook*>::exists) }; 00164 // GCC Doesn't handle evaluation of ?: opeators in templates yet. 00165 // enum { is = (int)( is_static ? uc_static: ( is_static_op ? uc_static_op : uc_false)) 00166 enum { is = is_static * uc_static + 00167 is_qi_hook_itf * uc_qi_hook_itf + 00168 is_qi_hook * uc_qi_hook + 00169 is_static_op * uc_static_op }; 00170 }; 00171 00172 template<typename Itf> 00173 struct find_compatibility 00174 { 00175 enum { needs_cast_ = use_cast_aux<Itf>::is }; 00176 typedef find_compatibility_aux< (use_cast_t)needs_cast_ > compatible; 00177 00178 COMET_FORCEINLINE static bool with(const uuid_t &iid) 00179 { return compatible::with<Itf>::is(iid); }; 00180 template<typename T> 00181 COMET_FORCEINLINE static com_ptr<::IUnknown> cast_from( T *This) 00182 { return compatible::with<Itf>::cast_from(This); }; 00183 }; 00184 00185 template<typename ITF_LIST> struct interface_finder 00186 { 00187 template<typename T> COMET_FORCEINLINE static bool find_interface(T* This, const uuid_t& iid, com_ptr<::IUnknown>& rv) 00188 { 00189 typedef find_compatibility_aux< (use_cast_t)use_cast_aux< COMET_STRICT_TYPENAME ITF_LIST::head >::is >::with<COMET_STRICT_TYPENAME ITF_LIST::head> fc; 00190 if ( fc::qi(This, iid, rv) ) 00191 return true; 00192 else 00193 return interface_finder< COMET_STRICT_TYPENAME ITF_LIST::tail>::find_interface(This, iid, rv); 00194 } 00195 00196 COMET_FORCEINLINE static bool find_interface_2(const uuid_t& iid) 00197 { 00198 if (is_interface_compatible<COMET_STRICT_TYPENAME ITF_LIST::head>(iid, 0)) return true; 00199 return interface_finder< COMET_STRICT_TYPENAME ITF_LIST::tail>::find_interface_2(iid); 00200 } 00201 }; 00202 00203 template<> struct interface_finder<nil> 00204 { 00205 template<typename T> COMET_FORCEINLINE static bool find_interface(T*, const uuid_t&, com_ptr<::IUnknown>&) 00206 { return false; } 00207 00208 COMET_FORCEINLINE static bool find_interface_2(const uuid_t&) 00209 { 00210 return false; 00211 } 00212 }; 00213 00214 /* template<> struct interface_finder<make_list<> > 00215 { 00216 template<typename T> COMET_FORCEINLINE static ::IUnknown* find_interface(T*, const uuid_t&) 00217 { 00218 return 0; 00219 } 00220 };*/ 00221 00222 } 00223 00229 template<typename TL> 00230 struct typelibrary_loader 00231 { 00233 00237 static inline HRESULT load( ITypeLib **pTypeLib) 00238 { return LoadRegTypeLib(uuidof<TL>(), TL::major_version, TL::minor_version, LANG_NEUTRAL, pTypeLib); } 00239 }; 00240 00246 template<typename ITF_LIST> class ATL_NO_VTABLE implement_qi : public typelist::inherit_all<ITF_LIST> 00247 { 00248 private: 00249 // Hide qi 00250 void qi(); 00251 public: 00256 ::IUnknown* get_unknown()const 00257 { return static_cast< typename ITF_LIST::head * >(const_cast<implement_qi<ITF_LIST> *>(this)); } 00258 00259 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) 00260 { 00261 const uuid_t& iid = uuid_t::create_const_reference(riid); 00262 com_ptr<::IUnknown> p; 00263 00264 impl::interface_finder<ITF_LIST>::find_interface(this, iid, p); 00265 00266 if (!p) { 00267 if (riid != IID_IUnknown) return E_NOINTERFACE; 00268 p = get_unknown(); 00269 // p = static_cast< ::IUnknown* >(static_cast< typename ITF_LIST::head * >(this)); 00270 } 00271 00272 *ppv = reinterpret_cast<void*>(p.detach()); 00273 00274 return S_OK; 00275 } 00276 }; 00277 00283 template<typename ITF_LIST> class ATL_NO_VTABLE implement_internal_qi : public typelist::inherit_all<ITF_LIST> 00284 { 00285 private: 00286 void qi(); 00287 public: 00292 ::IUnknown* get_unknown()const 00293 { return static_cast< typename ITF_LIST::head * >( const_cast<implement_internal_qi<ITF_LIST> *>(this)); } 00294 00295 HRESULT QueryInterfaceInternal(REFIID riid, void** ppv) 00296 { 00297 const IID& iid = riid; 00298 com_ptr<::IUnknown> p; 00299 00300 impl::interface_finder<ITF_LIST>::find_interface(this, iid, p); 00301 00302 if (!p) { 00303 if (riid != IID_IUnknown) return E_NOINTERFACE; 00304 // p = cast_to_unknown(this); 00305 p = static_cast< ::IUnknown* >(static_cast<typename ITF_LIST::head*>(this)); 00306 } 00307 00308 *ppv = reinterpret_cast<void*>(p.detach()); 00309 00310 return S_OK; 00311 } 00312 }; 00313 00314 namespace impl { 00315 template<typename ITF_LIST> ::IUnknown* cast_to_unknown(implement_qi<ITF_LIST>* iq) 00316 { return static_cast< typename ITF_LIST::head*>(iq); } 00317 } 00318 00322 template<typename BASE, typename TL> class ATL_NO_VTABLE impl_dispatch : public BASE 00323 { 00324 private: 00326 00327 STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo** ti) 00328 { 00329 *ti = get_ti(); 00330 if (*ti) 00331 { 00332 (*ti)->AddRef(); 00333 return S_OK; 00334 } 00335 return E_NOTIMPL; 00336 } 00337 00338 STDMETHOD(GetTypeInfoCount)(UINT *it) 00339 { *it = 1; return S_OK; } 00340 00341 STDMETHOD(GetIDsOfNames)(REFIID, OLECHAR** pNames, UINT cNames, LCID, DISPID* pdispids) 00342 { 00343 ITypeInfo* ti = get_ti(); 00344 if (ti) 00345 return ti->GetIDsOfNames(pNames, cNames, pdispids); 00346 else 00347 return E_NOTIMPL; 00348 } 00349 00350 STDMETHOD(Invoke)(DISPID id, REFIID, LCID, WORD wFlags, DISPPARAMS *pd, VARIANT* pVarResult, EXCEPINFO* pe, UINT* pu) 00351 { 00352 ITypeInfo* ti = get_ti(); 00353 if (ti) 00354 { 00355 void* pThis = static_cast<BASE*>(this); 00356 return ti->Invoke(pThis, id, wFlags, pd, pVarResult, pe, pu); 00357 } 00358 else 00359 return E_NOTIMPL; 00360 } 00362 private: 00363 ITypeInfo* get_ti() 00364 { 00365 static ITypeInfo* ti_; 00366 if (ti_ == 0) 00367 { 00368 auto_cs lock(module().cs()); 00369 if (ti_ == 0) 00370 { 00371 com_ptr<ITypeLib> ptl; 00372 00373 typelibrary_loader<TL>::load(ptl.out()); 00374 if (ptl) ptl->GetTypeInfoOfGuid(uuidof<BASE>(), &ti_); 00375 00376 if (ti_ != 0) module().add_object_to_dispose( impl::create_itf_releaser(ti_) ); 00377 } 00378 } 00379 return ti_; 00380 } 00381 00382 // static ITypeInfo* ti_; 00383 }; 00384 00385 template<typename Itf> class com_ptr; 00386 00387 #if 0 00388 00392 template< typename Itf > 00393 class aggregates_interface 00394 { 00395 public: 00398 void set_aggregate(const com_ptr<::IUnknown>& aggobj) { ag_object_ = com_cast(aggobj); } 00402 typedef Itf exposes; 00403 00404 operator Itf*() throw() 00405 { 00406 com_ptr<::IUnknown> test = ag_object_; 00407 return ag_object_.in(); 00408 // return com_ptr<Itf>( com_cast(ag_object_) ); 00409 } 00410 protected: 00411 com_ptr<Itf> ag_object_; 00412 00413 }; 00414 #endif 00415 00416 namespace impl { 00420 class qi_hook_itf_tag {}; 00421 } 00422 00423 class qi_hook {}; 00424 00425 template<typename Itf> class qi_hook_itf : public impl::qi_hook_itf_tag 00426 { 00427 public: 00428 typedef Itf exposes; 00429 virtual com_ptr<Itf> get_interface_ptr(const com_ptr<::IUnknown>&) throw() = 0; 00430 }; 00431 00432 /* class FTM : public qi_hook_itf<IMarshal> 00433 { 00434 private: 00435 com_ptr<IMarshal> get_interface_ptr(const com_ptr<::IUnknown>& This) throw() 00436 { 00437 ::IUnknown* ftm = 0; 00438 CoCreateFreeThreadedMarshaler(This.in(), &ftm); 00439 return com_cast(ftm); 00440 } 00441 };*/ 00442 00453 struct FTM : public qi_hook 00454 { 00455 template<typename T> 00456 bool qi(T *This, const uuid_t& iid, com_ptr<::IUnknown>& unk) 00457 { 00458 if (iid != uuidof<IMarshal>()) return false; 00459 ::IUnknown* ftm = 0; 00460 CoCreateFreeThreadedMarshaler(impl::cast_to_unknown(This), &ftm); 00461 unk = com_ptr<::IMarshal>( com_cast(ftm) ); 00462 return unk != 0; 00463 } 00464 }; 00465 00481 template<typename COCLASS, COMET_LIST_TEMPLATE> class aggregates : public qi_hook 00482 { 00483 com_ptr<::IUnknown> inner_; 00484 public: 00485 template<typename T> bool qi(T *This, const uuid_t& iid, com_ptr<::IUnknown>& unk) 00486 { 00487 typedef make_list<COMET_LIST_ARG_1>::result TL; 00488 if (typelist::length<TL>::value > 0) { 00489 if (impl::interface_finder<TL>::find_interface_2(iid) == false) return false; 00490 } 00491 if (inner_ == 0) return false; 00492 ::IUnknown* p; 00493 if (SUCCEEDED(inner_.raw()->QueryInterface(iid, reinterpret_cast<void**>(&p)))) 00494 { 00495 unk = auto_attach(p); 00496 return true; 00497 } 00498 return false; 00499 } 00500 protected: 00501 template<typename T> void create_aggregate(T *This, DWORD dwClsContext = CLSCTX_ALL) 00502 { ::IUnknown* unk_this = impl::cast_to_unknown(This); inner_ = com_ptr<::IUnknown>(uuidof<COCLASS>(), com_ptr<::IUnknown>::create_reference(unk_this), dwClsContext); } 00503 }; 00504 00505 /* template<typename Itf> class aggregates_interface : public qi_hook_itf<Itf> 00506 { 00507 private: 00508 com_ptr<::IUnknown> inner_; 00509 com_ptr<Itf> get_interface_ptr(const com_ptr<::IUnknown>&) 00510 { return com_cast(inner_); } 00511 protected: 00512 template<typename ITF_LIST> void create_aggregate(const CLSID& clsid, implement_qi<ITF_LIST>* This, DWORD dwClsContext = CLSCTX_ALL) 00513 { 00514 ::IUnknown* unk_this = static_cast< typename ITF_LIST::head*>(This); 00515 inner_ = com_ptr<::IUnknown>(clsid, com_ptr<::IUnknown>::create_reference(unk_this), dwClsContext); 00516 } 00517 00518 template<typename ITF_LIST> void create_aggregate(const wchar_t* progid, implement_qi<ITF_LIST>* This, DWORD dwClsContext = CLSCTX_ALL) 00519 { 00520 ::IUnknown* unk_this = static_cast< typename ITF_LIST::head*>(This); 00521 inner_ = com_ptr<::IUnknown>(progid, com_ptr<::IUnknown>::create_reference(unk_this), dwClsContext); 00522 } 00523 };*/ 00524 00526 } 00527 00528 #endif