server.h

Go to the documentation of this file.
00001 00004 /* 00005 * Copyright © 2000-2002 Sofus Mortensen, Paul Hollingsworth, Michael Geddes, Mikael Lindgren 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_SERVER_H 00020 #define COMET_SERVER_H 00021 00022 #include <comet/config.h> 00023 #ifdef COMET_GCC_HEADERS 00024 #include <windows.h> 00025 #else // COMET_GCC_HEADERS 00026 #include <olectl.h> 00027 #endif // COMET_GCC_HEADERS 00028 00029 #include <malloc.h> 00030 #include <string> 00031 #include <vector> 00032 00033 #include <comet/impqi.h> 00034 #include <comet/interface.h> 00035 #include <comet/regkey.h> 00036 #include <comet/threading.h> 00037 #include <comet/tstring.h> 00038 #include <comet/handle_except.h> 00039 #include <comet/module.h> 00040 00084 00119 template<typename CLASS> 00120 class custom_registration 00121 { 00122 public: 00123 void on_register(const TCHAR *) {} 00124 void on_unregister(const TCHAR *) {} 00125 }; 00127 00128 namespace comet { 00129 00130 00131 namespace impl { 00132 00133 inline void create_record_info( const IID& lib_guid, const IID& rec_guid, unsigned short major_version, unsigned short minor_version, IRecordInfo*& ri ) 00134 { 00135 auto_cs lock( module().cs() ); 00136 00137 if (!ri) { 00138 com_ptr<ITypeLib> tl; 00139 LoadRegTypeLib(lib_guid, 00140 major_version, 00141 minor_version, 00142 GetUserDefaultLCID(), 00143 tl.out()) | raise_exception; 00144 com_ptr<ITypeInfo> ti; 00145 tl->GetTypeInfoOfGuid(rec_guid, ti.out()) | raise_exception; 00146 GetRecordInfoFromTypeInfo(ti.in(), &ri) | raise_exception; 00147 module().add_object_to_dispose( impl::create_itf_releaser( ri ) ); 00148 } 00149 } 00150 00151 template<typename T> struct interface_wrapper : public T 00152 { 00153 typedef T interface_is; 00154 }; 00155 00156 template<typename T> class ATL_NO_VTABLE simple_object_aux : 00157 public implement_qi< typelist::append< T, 00158 make_list<impl::interface_wrapper<ISupportErrorInfo> >::result > > 00159 { 00160 public: 00161 // enum { factory_type = ft_standard }; 00162 00163 STDMETHOD_(ULONG, AddRef)() 00164 { 00165 if (rc_ == 0) module().lock(); 00166 return InterlockedIncrement(&rc_); 00167 } 00168 00169 STDMETHOD_(ULONG, Release)() 00170 { 00171 LONG rc = InterlockedDecrement(&rc_); 00172 if (rc == 0) { 00173 try { 00174 delete this; 00175 } COMET_CATCH_UNKNOWN( L"Release", IID_IUnknown, bstr_t()); 00176 module().unlock(); 00177 } 00178 return rc; 00179 } 00180 00181 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID) 00182 { 00183 return S_OK; 00184 } 00185 00186 void so_internal_addref() { ++rc_; } 00187 void so_internal_release() { --rc_; } 00188 00189 protected: 00190 simple_object_aux() : rc_(0) {} 00191 virtual ~simple_object_aux() {} 00192 private: 00193 long rc_; 00194 00195 // non-copyable 00196 simple_object_aux(const simple_object_aux&); 00197 simple_object_aux& operator=(const simple_object_aux&); 00198 }; 00199 00200 } 00207 template<class C> 00208 struct aggregate_inner_unknown : IUnknown 00209 { 00210 aggregate_inner_unknown() : rc_(0) {} 00211 00212 STDMETHOD_(ULONG, AddRef)() 00213 { 00214 if (rc_ == 0) module().lock(); 00215 return InterlockedIncrement(&rc_); 00216 } 00217 00218 STDMETHOD_(ULONG, Release)() 00219 { 00220 size_t rc = InterlockedDecrement(&rc_); 00221 if (rc == 0) { 00222 try { 00223 delete static_cast<C *>(this); 00224 } 00225 COMET_CATCH_UNKNOWN( L"Release", IID_IUnknown, bstr_t()); 00226 module().unlock(); 00227 } 00228 return rc; 00229 } 00230 00231 STDMETHOD(QueryInterface)(REFIID riid, void **pv) 00232 { 00233 if(riid == IID_IUnknown) 00234 { 00235 *pv=get_inner(); 00236 AddRef(); 00237 return S_OK; 00238 } 00239 return static_cast<C *>(this)->QueryInterfaceInternal(riid, pv); 00240 } 00241 00242 IUnknown *get_inner() { return static_cast<IUnknown *>(this); } 00243 00244 private: 00245 long rc_; 00246 }; 00247 00253 template<typename T> 00254 class aggregate_outer_unknown : public implement_internal_qi< 00255 typelist::append<T, make_list<impl::interface_wrapper<ISupportErrorInfo> >::result > 00256 > 00257 { 00258 public: 00259 aggregate_outer_unknown(): outer_(NULL) {} 00260 00261 STDMETHOD_(ULONG, AddRef)() 00262 { 00263 //assert(outer_!=NULL); 00264 return outer_->AddRef(); 00265 } 00266 00267 STDMETHOD_(ULONG, Release)() 00268 { 00269 //assert(outer_!=NULL); 00270 return outer_->Release(); 00271 } 00272 STDMETHOD(QueryInterface)(REFIID riid, void** ppv) 00273 { 00274 //assert(outer_!=NULL); 00275 return outer_->QueryInterface(riid, ppv); 00276 } 00277 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID) 00278 { 00279 return S_OK; 00280 } 00281 void set_outer_(IUnknown *outer){ outer_ = outer;} 00282 00283 00284 private: 00285 IUnknown *outer_; 00286 }; 00288 00289 namespace impl { 00290 00291 template<typename T> class ATL_NO_VTABLE aggregateable_object_aux : public aggregate_outer_unknown<T>, public aggregate_inner_unknown<aggregateable_object_aux<T> > 00292 { 00293 public: 00294 aggregateable_object_aux() 00295 { 00296 set_outer_(static_cast<IUnknown *>(static_cast< aggregate_inner_unknown<impl::aggregateable_object_aux<T> > *>(this))); 00297 } 00298 00299 protected: 00300 virtual ~aggregateable_object_aux() {} 00301 friend struct aggregate_inner_unknown<aggregateable_object_aux<T> >; 00302 private: 00303 // non-copyable 00304 aggregateable_object_aux(const aggregateable_object_aux&); 00305 aggregateable_object_aux& operator=(const aggregateable_object_aux&); 00306 }; 00307 00308 } 00309 00323 template<COMET_LIST_TEMPLATE> class ATL_NO_VTABLE aggregateable_object : public impl::aggregateable_object_aux< typename make_list<COMET_LIST_ARG_1>::result > 00324 { 00325 public: 00326 enum { factory_type = impl::ft_aggregateable }; 00327 }; 00328 00339 template<COMET_LIST_TEMPLATE> class ATL_NO_VTABLE simple_object : public impl::simple_object_aux< typename make_list<COMET_LIST_ARG_1>::result > 00340 { 00341 public: 00342 enum { factory_type = impl::ft_standard }; 00343 }; 00345 00346 namespace impl { 00347 00348 enum factory_type_t { ft_standard, ft_aggregateable, ft_singleton }; 00349 00350 template<typename T> class ATL_NO_VTABLE static_object_aux : 00351 public implement_qi< typelist::append< T, make_list<impl::interface_wrapper<ISupportErrorInfo> >::result > > 00352 { 00353 public: 00354 STDMETHOD_(ULONG, AddRef)() 00355 { 00356 module().lock(); 00357 return 2; 00358 } 00359 00360 STDMETHOD_(ULONG, Release)() 00361 { 00362 module().unlock(); 00363 return 1; 00364 } 00365 00366 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID) 00367 { 00368 return S_OK; 00369 } 00370 protected: 00371 static_object_aux() {} 00372 virtual ~static_object_aux() {} 00373 }; 00374 00375 } 00376 00390 template<COMET_LIST_TEMPLATE> class ATL_NO_VTABLE static_object : public impl::static_object_aux< typename make_list<COMET_LIST_ARG_1>::result > 00391 { 00392 }; 00393 00404 template<COMET_LIST_TEMPLATE> class ATL_NO_VTABLE singleton_object : public impl::static_object_aux< typename make_list<COMET_LIST_ARG_1>::result > 00405 { 00406 public: 00407 enum { factory_type = impl::ft_singleton }; 00408 void set_dispose_command_( impl::cmd_t *) { } 00409 }; 00410 00411 00417 template<typename PARENT, COMET_LIST_TEMPLATE> class ATL_NO_VTABLE embedded_object : 00418 public implement_qi< typelist::append< typename make_list<COMET_LIST_ARG_1>::result, typename make_list<impl::interface_wrapper<ISupportErrorInfo> >::result > > 00419 { 00420 public: 00421 STDMETHOD_(ULONG, AddRef)() 00422 { 00423 return parent_->AddRef(); 00424 } 00425 00426 STDMETHOD_(ULONG, Release)() 00427 { 00428 return parent_->Release(); 00429 } 00430 00431 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID) 00432 { 00433 return S_OK; 00434 } 00435 00436 protected: 00437 explicit embedded_object(PARENT* parent) : parent_(parent) {} 00438 00439 PARENT* get_parent() const { return parent_; } 00440 00441 typedef embedded_object base_class; 00442 private: 00443 PARENT* parent_; 00444 00445 // non-copyable 00446 embedded_object(const embedded_object&); 00447 embedded_object& operator=(const embedded_object&); 00448 }; 00449 00455 template<typename PARENT, COMET_LIST_TEMPLATE> class ATL_NO_VTABLE embedded_object2 : 00456 public implement_qi< typelist::append< typename make_list<COMET_LIST_ARG_1>::result, make_list<impl::interface_wrapper<ISupportErrorInfo> >::result > > 00457 { 00458 public: 00459 STDMETHOD_(ULONG, AddRef)() 00460 { 00461 if (rc_ == 0) module().lock(); 00462 long r = InterlockedIncrement(&rc_); 00463 if (is_connected_) return parent_->AddRef(); 00464 return r; 00465 } 00466 00467 STDMETHOD_(ULONG, Release)() 00468 { 00469 size_t rc = InterlockedDecrement(&rc_); 00470 00471 if (is_connected_) return parent_->Release(); 00472 00473 if (rc == 0) { 00474 try { 00475 delete this; 00476 } 00477 COMET_CATCH_UNKNOWN( L"Release", IID_IUnknown, bstr_t()); 00478 module().unlock(); 00479 } 00480 return rc; 00481 } 00482 00483 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID) 00484 { 00485 return S_OK; 00486 } 00487 00488 void disconnect() 00489 { 00490 // todo make thread safe! 00491 00492 if (is_connected_) { 00493 is_connected_ = false; 00494 00495 for (long i=0; i<rc_; ++i) parent_->Release(); 00496 00497 // Provoke destruction if necessary. 00498 AddRef(); 00499 Release(); 00500 } 00501 } 00502 00503 protected: 00504 explicit embedded_object2(PARENT* parent) : parent_(parent), rc_(0), is_connected_(true) {} 00505 00506 virtual ~embedded_object2() {} 00507 00508 PARENT* get_parent() const { return parent_; } 00509 00510 typedef embedded_object2 base_class; 00511 private: 00512 PARENT* parent_; 00513 bool is_connected_; 00514 long rc_; 00515 00516 // non-copyable 00517 embedded_object2(const embedded_object2&); 00518 embedded_object2& operator=(const embedded_object2&); 00519 }; 00521 00523 template<typename T, bool LOCK_MODULE> class class_factory_base : public IClassFactory 00524 { 00525 public: 00526 STDMETHOD_(ULONG, AddRef)() 00527 { 00528 if (LOCK_MODULE) module().lock(); 00529 return 2; 00530 } 00531 00532 STDMETHOD_(ULONG, Release)() 00533 { 00534 if (LOCK_MODULE) module().unlock(); 00535 return 1; 00536 } 00537 00538 STDMETHOD(QueryInterface)(REFIID riid, void **pv) 00539 { 00540 if (!pv) return E_POINTER; 00541 *pv = 0; 00542 if (riid == IID_IClassFactory) *pv = static_cast<IClassFactory*>(this); 00543 if (riid == IID_IUnknown) *pv = this; 00544 00545 if (*pv == NULL) return E_NOINTERFACE; 00546 00547 AddRef(); 00548 return S_OK; 00549 } 00550 00551 STDMETHOD(LockServer)(BOOL bLock) 00552 { 00553 if (bLock) 00554 module().lock(); 00555 else 00556 module().unlock(); 00557 return S_OK; 00558 } 00559 protected: 00560 HRESULT handle_exception( const bstr_t &src ) 00561 { 00562 #ifndef COMET_DISABLE_EXCEPTION_RETHROW_CATCH 00563 return comet_exception_handler<true>::rethrow( source_info_t( src, IID_IUnknown, L"ClassFactory") ); 00564 #else // COMET_DISABLE_EXCEPTION_RETHROW_CATCH 00565 return comet_exception_handler<true>::catcher_hr(E_FAIL, source_info_t(src, IID_IUnknown, L"ClassFactory") ); 00566 #endif // COMET_DISABLE_EXCEPTION_RETHROW_CATCH 00567 } 00568 }; 00569 00571 template<typename T, bool LOCK_MODULE> class class_factory : public class_factory_base<T, LOCK_MODULE> 00572 { 00573 public: 00574 STDMETHOD(CreateInstance)(::IUnknown *pUnkOuter, REFIID riid, void **ppv) 00575 { 00576 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 00577 *ppv = 0; 00578 00579 if (!LOCK_MODULE) module().lock(); 00580 00581 T::coclass_type* t; 00582 try { 00583 t = new T; 00584 } 00585 catch (...) 00586 { 00587 if (!LOCK_MODULE) module().unlock(); 00588 return handle_exception( bstr_t(L"CreateInstance(") + bstr_t(uuid_t::create_const_reference(riid),true ) + ")" ); 00589 } 00590 00591 t->AddRef(); 00592 HRESULT hr = t->QueryInterface(riid, ppv); 00593 t->Release(); 00594 00595 if (!LOCK_MODULE) module().unlock(); 00596 00597 return hr; 00598 } 00599 00600 }; 00601 00603 template<typename T, bool LOCK_MODULE> class class_factory_agg : public class_factory_base<T, LOCK_MODULE> 00604 { 00605 STDMETHOD(CreateInstance)(::IUnknown *pUnkOuter, REFIID riid, void **ppv) 00606 { 00607 *ppv = 0; 00608 00609 if (!LOCK_MODULE) module().lock(); 00610 00611 T* t; 00612 try { 00613 t = new T; 00614 } 00615 catch (...) 00616 { 00617 if (!LOCK_MODULE) module().unlock(); 00618 return handle_exception( bstr_t(L"CreateInstance(") + bstr_t(uuid_t::create_const_reference(riid),true ) + ")" ); 00619 } 00620 if(pUnkOuter!=NULL) 00621 { 00622 if(riid!=IID_IUnknown) 00623 { 00624 if (!LOCK_MODULE) module().unlock(); 00625 return CLASS_E_NOAGGREGATION; 00626 } 00627 t->set_outer_(pUnkOuter); 00628 } 00629 00630 t->get_inner()->AddRef(); 00631 HRESULT hr = t->get_inner()->QueryInterface(riid, ppv); 00632 t->get_inner()->Release(); 00633 00634 if (!LOCK_MODULE) module().unlock(); 00635 00636 return hr; 00637 } 00638 }; 00639 00641 template<typename T, bool LOCK_MODULE> class class_factory_singleton : public class_factory_base<T, LOCK_MODULE> 00642 { 00643 public: 00644 class_factory_singleton() : obj_(NULL), primed_(0) 00645 { } 00646 00647 STDMETHOD(CreateInstance)(::IUnknown *pUnkOuter, REFIID riid, void **ppv) 00648 { 00649 *ppv = 0; 00650 if(pUnkOuter!=NULL) 00651 return CLASS_E_NOAGGREGATION; 00652 00653 if (!LOCK_MODULE) module().lock(); 00654 00655 // Add this to the list to get the object disposed on 00656 // moudle terminate. 00657 if (0==InterlockedExchange(&primed_, 1)) 00658 { 00659 module().add_object_to_dispose( create_object_disposer(this) ); 00660 } 00661 00662 if (obj_ == NULL ) 00663 { 00664 00665 try { 00666 // Create a new instance, but make sure only one is 00667 // used if there is contention. 00668 T *newVal = new T; 00669 newVal->set_dispose_command_( create_object_disposer(this)); 00670 #ifndef InterlockedCompareExchangePointer 00671 InterlockedCompareExchange( &(void *&)obj_, newVal, 0); 00672 #else 00673 InterlockedCompareExchangePointer( &(void *&)obj_, newVal, 0); 00674 #endif 00675 } 00676 catch (...) 00677 { 00678 if (!LOCK_MODULE) module().unlock(); 00679 return handle_exception( bstr_t(L"CreateInstance(") + bstr_t(uuid_t::create_const_reference(riid),true ) + ")" ); 00680 } 00681 } 00682 00683 HRESULT hr = obj_->QueryInterface(riid, ppv); 00684 00685 if (!LOCK_MODULE) module().unlock(); 00686 00687 return hr; 00688 } 00689 00690 // Called by object_disposer on module terminate. 00691 void object_dispose() 00692 { 00693 if (obj_ != NULL) 00694 { 00695 T *t= obj_; 00696 obj_ = NULL; 00697 CoDisconnectObject(t->get_unknown(), 0); 00698 delete t; 00699 } 00700 } 00701 00702 T *obj_; 00703 long primed_; 00704 private: 00705 }; 00706 00707 00713 namespace thread_model { 00716 enum thread_model_t { 00717 Apartment = 0, 00718 Free = 1, 00719 Both = 2, 00720 Neutral = 3 00721 }; 00722 } 00724 00726 template<long tm> 00727 struct tm_properties; 00728 00729 template<> struct tm_properties<thread_model::Apartment> 00730 { 00731 COMET_FORCEINLINE static const TCHAR *string() { return _T("Apartment"); } 00732 }; 00733 00734 template<> struct tm_properties<thread_model::Free> 00735 { 00736 COMET_FORCEINLINE static const TCHAR *string() { return _T("Free"); } 00737 }; 00738 00739 template<> struct tm_properties<thread_model::Both> 00740 { 00741 COMET_FORCEINLINE static const TCHAR *string() { return _T("Both"); } 00742 }; 00743 00744 template<> struct tm_properties<thread_model::Neutral> 00745 { 00746 COMET_FORCEINLINE static const TCHAR *string() { return _T("Neutral"); } 00747 }; 00748 00761 template<typename COCLASS> class IProvideClassInfoImpl : public IProvideClassInfo, public handle_exception_default<COCLASS> 00762 { 00763 public: 00764 typedef IProvideClassInfo interface_is; 00765 STDMETHOD(GetClassInfo)(ITypeInfo **ppTypeInfo) throw() 00766 { 00767 if(!ppTypeInfo) return E_POINTER; 00768 *ppTypeInfo = 0; 00769 ITypeLib *pTypeLib; 00770 typedef typename COCLASS::type_library COCLASS_typelib; 00771 HRESULT hr = typelibrary_loader<COCLASS_typelib>::load(&pTypeLib); 00772 00773 if(FAILED(hr)) return hr; 00774 hr = pTypeLib->GetTypeInfoOfGuid(uuidof<COCLASS>(), ppTypeInfo); 00775 pTypeLib->Release(); 00776 return hr; 00777 } 00778 }; 00803 /* template<typename T, enum thread_model::thread_model_t TM = thread_model::Apartment> struct ATL_NO_VTABLE coclass : public impl::simple_object_aux< typelist::append<typename T::interface_impls,typename make_list<IProvideClassInfoImpl<T> >::result > > { 00804 enum { thread_model = TM }; 00805 static const TCHAR* get_progid() { return 0; } 00806 };*/ 00808 00812 template<typename T, enum thread_model::thread_model_t TM = thread_model::Apartment, COMET_LIST_TEMPLATE> struct ATL_NO_VTABLE coclass : public impl::simple_object_aux< typelist::append< typelist::append< typename T::interface_impls, typename make_list<COMET_LIST_ARG_1>::result>, typename make_list<IProvideClassInfoImpl<T> >::result > > { 00813 typedef coclass coclass_type; 00814 enum { factory_type = impl::ft_standard }; 00815 enum { thread_model = TM }; 00816 static const TCHAR* get_progid() { return 0; } 00817 }; 00819 00820 // COMET_WRAP_EACH_DECLARE(aggregates_interface); 00821 00822 namespace impl { 00823 template<typename T1, typename T2, typename T3> 00824 struct append3 00825 { 00826 typedef typelist::append<T1, T2> first_two; 00827 typedef typelist::append<first_two, T3> list; 00828 }; 00829 } 00830 #ifdef NOTNOW 00831 00851 /* template<typename T, typename AGG_LST, enum thread_model::thread_model_t TM = thread_model::Apartment> 00852 struct ATL_NO_VTABLE coclass_aggregates : public impl::simple_object_aux<impl::append3< typename T::interface_impls, COMET_WRAP_EACH(aggregates_interface, AGG_LST), make_list<IProvideClassInfoImpl<T> >::result > > 00853 { 00854 enum { thread_model = TM }; 00855 static const TCHAR* get_progid() { return 0; } 00856 };*/ 00857 #endif //0 00858 00876 template<typename T, enum thread_model::thread_model_t TM = thread_model::Apartment> 00877 struct ATL_NO_VTABLE aggregateable_coclass : public impl::aggregateable_object_aux< typelist::append< typename T::interface_impls, typename make_list<IProvideClassInfoImpl<T> >::result > > 00878 { 00879 typedef aggregateable_coclass coclass_type; 00880 enum { thread_model = TM }; 00881 enum { factory_type = impl::ft_aggregateable }; 00882 static const TCHAR* get_progid() { return 0; } 00883 aggregateable_coclass() {} 00884 protected: 00885 ~aggregateable_coclass() {} 00886 private: 00887 aggregateable_coclass(const aggregateable_coclass&); 00888 aggregateable_coclass& operator=(const aggregateable_coclass&); 00889 }; 00890 00904 template< typename T, enum thread_model::thread_model_t TM = thread_model::Apartment> 00905 struct ATL_NO_VTABLE singleton_coclass : public impl::static_object_aux< 00906 typelist::append< typename T::interface_impls, typename make_list<typename IProvideClassInfoImpl<T> >::result > 00907 > 00908 { 00909 typedef singleton_coclass coclass_type; 00910 enum { thread_model = TM }; 00911 enum { factory_type = impl::ft_singleton }; 00912 void set_dispose_command_( impl::cmd_t *) { } 00913 static const TCHAR* get_progid() { return 0; } 00914 singleton_coclass() {} 00915 ~singleton_coclass() {} 00916 00917 private: 00918 singleton_coclass(const singleton_coclass&); 00919 singleton_coclass& operator=(const singleton_coclass&); 00920 }; 00921 00922 template< typename T, enum thread_model::thread_model_t TM = thread_model::Apartment> 00923 struct ATL_NO_VTABLE singleton_autorelease_coclass : public impl::static_object_aux< 00924 typelist::append< typename T::interface_impls, typename make_list<typename IProvideClassInfoImpl<T> >::result > 00925 > 00926 { 00927 singleton_autorelease_coclass() : rc_(0), dispose_(0) {} 00928 ~singleton_autorelease_coclass() 00929 { delete dispose_; } 00930 00931 STDMETHOD_(ULONG, AddRef)() 00932 { 00933 if (rc_ == 0) module().lock(); 00934 return InterlockedIncrement(&rc_); 00935 } 00936 00937 STDMETHOD_(ULONG, Release)() 00938 { 00939 LONG rc = InterlockedDecrement(&rc_); 00940 if (rc == 0) { 00941 try { 00942 if (dispose_!=NULL) 00943 dispose_->cmd(); 00944 00945 } COMET_CATCH_UNKNOWN( L"Release", IID_IUnknown, bstr_t()); 00946 module().unlock(); 00947 } 00948 return rc; 00949 } 00950 00951 typedef singleton_autorelease_coclass coclass_type; 00952 enum { thread_model = TM }; 00953 enum { factory_type = impl::ft_singleton }; 00954 static const TCHAR* get_progid() { return 0; } 00955 00956 void set_dispose_command_( impl::cmd_t *p) 00957 { 00958 delete dispose_; 00959 dispose_ = p; 00960 } 00961 00962 private: 00963 singleton_autorelease_coclass(const singleton_autorelease_coclass&); 00964 singleton_autorelease_coclass& operator=(const singleton_autorelease_coclass&); 00965 long rc_; 00966 impl::cmd_t *dispose_; 00967 }; 00969 00970 00971 namespace impl { 00972 template<typename T> 00973 class reghelper_t 00974 { 00975 // convert_string is overloaded to select the correct 00976 // behaviour based on argument type. 00977 // dest_size is the number of bytes, not the number of characters. 00978 COMET_FORCEINLINE static void convert_string(wchar_t *dest, size_t dest_size, const wchar_t *src) 00979 { 00980 ::memcpy(dest, src, dest_size); 00981 } 00982 00983 COMET_FORCEINLINE static void convert_string(char *dest, size_t dest_size, const wchar_t *src) 00984 { 00985 ::WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_size, 0, 0); 00986 } 00987 00988 static void removekey(const tstring& key); 00989 static void addkey(const tstring& key, const tstring& valueName, const tstring& value); 00990 static void addkey(const tstring& key, const tstring& value); 00991 static tstring StringFromUUID(REFCLSID rclsid); 00992 static void updatekey(bool unregister, const tstring &key, const tstring &valueName, const tstring &value); 00993 static void updatekey(bool unregister, const tstring &key, const tstring &value); 00994 public: 00995 static void update_coclass(bool unregister, 00996 const CLSID &rclsid, 00997 const TCHAR *filename, 00998 const TCHAR *thread_model, 00999 const TCHAR *coclass_name, 01000 const TCHAR *progid, 01001 unsigned long version, 01002 const GUID &rlibid, 01003 bool inproc_server, 01004 const GUID* appid); 01005 }; // reghelper_t 01006 01007 template<typename T> 01008 void reghelper_t<T>::removekey(const tstring& key) 01009 { 01010 regkey rkey(HKEY_CLASSES_ROOT); 01011 rkey.delete_subkey_nothrow(key); 01012 } 01013 01014 template<typename T> 01015 void reghelper_t<T>::addkey(const tstring& key, const tstring& valueName, const tstring& value) 01016 { 01017 regkey rkey(HKEY_CLASSES_ROOT); 01018 rkey.create(key)[valueName] = value; 01019 } 01020 01021 template<typename T> 01022 void reghelper_t<T>::addkey(const tstring& key, const tstring& value) 01023 { 01024 regkey rkey(HKEY_CLASSES_ROOT); 01025 rkey.create(key)[_T("")] = value; 01026 } 01027 01028 template<typename T> 01029 tstring reghelper_t<T>::StringFromUUID(REFCLSID rclsid) 01030 { 01031 wchar_t *ws; 01032 ::StringFromCLSID(rclsid, &ws); 01033 size_t num_chars = wcslen(ws) + 1; 01034 size_t bytes = num_chars * sizeof (TCHAR); 01035 TCHAR *s = static_cast<TCHAR*>(_alloca(bytes)); 01036 convert_string(s, bytes, ws); 01037 CoTaskMemFree(ws); 01038 return s; 01039 } 01040 01041 template<typename T> 01042 void reghelper_t<T>::updatekey(bool unregister, const tstring &key, const tstring &valueName, const tstring &value) 01043 { 01044 if(unregister) 01045 removekey(key); 01046 else 01047 addkey(key, valueName, value); 01048 } 01049 01050 template<typename T> 01051 void reghelper_t<T>::updatekey(bool unregister, const tstring &key, const tstring &value) 01052 { 01053 if(unregister) 01054 removekey(key); 01055 else 01056 addkey(key, value); 01057 } 01058 01059 template<typename T> 01060 void reghelper_t<T>::update_coclass(bool unregister, 01061 const CLSID &rclsid, 01062 const TCHAR *filename, 01063 const TCHAR *thread_model, 01064 const TCHAR *coclass_name, 01065 const TCHAR *progid, 01066 unsigned long version, 01067 const GUID &rlibid, 01068 bool inproc_server, 01069 const GUID* /*appid*/) 01070 { 01071 tstring clsid = StringFromUUID(rclsid); 01072 tstring name = _T("CLSID\\") + clsid; 01073 tstring typelib = StringFromUUID(rlibid); 01074 // On WinNT/Win2000, subkeys must be deleted before parent keys. 01075 // Therefore, be sure to specify changes to subkeys before 01076 // changes to parent keys - otherwise the server will not 01077 // cleanly remove all keys when it is unregistered. 01078 if (inproc_server) 01079 { 01080 updatekey(unregister, name + _T("\\InprocServer32"), filename); 01081 updatekey(unregister, name + _T("\\InprocServer32"), _T("ThreadingModel"), thread_model); 01082 } 01083 else 01084 { 01085 updatekey(unregister, name + _T("\\LocalServer32"), filename); 01086 updatekey(unregister, name + _T("\\Programmable"), _T("")); 01087 } 01088 updatekey(unregister, name + _T("\\TypeLib"), typelib); 01089 // updatekey(unregister, name, coclass_name); 01090 01091 if (progid != 0) 01092 { 01093 tstring prgid(progid); 01094 01095 if (version != 0) 01096 { 01097 TCHAR buffer[35]; 01098 tstring prgid_ver(prgid + _T(".") + _ultot(version, buffer, 10)); 01099 01100 updatekey(unregister, name + _T("\\ProgID"), prgid_ver); 01101 updatekey(unregister, prgid + _T("\\CurVer"), prgid_ver); 01102 updatekey(unregister, prgid_ver + _T("\\CLSID"), clsid); 01103 updatekey(unregister, prgid_ver, coclass_name); 01104 } 01105 else 01106 { 01107 updatekey(unregister, name + _T("\\ProgID"), prgid); 01108 } 01109 01110 updatekey(unregister, prgid + _T("\\CLSID"), clsid); 01111 updatekey(unregister, prgid, coclass_name); 01112 } 01113 01114 updatekey(unregister, name, coclass_name); 01115 01116 // if (progid != 0) { 01117 // updatekey(unregister, name + _T("\\ProgID"), progid); 01118 // updatekey(unregister, tstring(progid) + _T("\\CLSID"), clsid); 01119 // updatekey(unregister, progid, coclass_name); 01120 // } 01121 } 01122 01123 typedef reghelper_t<void> reghelper; 01124 01125 #ifndef COMET_PARTIAL_SPECIALISATION 01126 01127 template<bool undefined> 01128 struct entry_builder; 01129 01130 template<typename T> struct THE_FOLLOWING_COCLASS_HAS_NOT_BEEN_IMPLEMENTED; 01131 template<> struct THE_FOLLOWING_COCLASS_HAS_NOT_BEEN_IMPLEMENTED<nil> {}; 01132 01133 template<> struct entry_builder<true> 01134 { 01135 template<typename CLASS> 01136 struct registration 01137 { 01138 COMET_FORCEINLINE static void perform(const TCHAR*, bool, bool, const GUID* ) 01139 { 01140 #ifndef COMET_ALLOW_UNIMPLEMENTED_COCLASSES 01141 THE_FOLLOWING_COCLASS_HAS_NOT_BEEN_IMPLEMENTED<CLASS> x; 01142 #endif 01143 } 01144 }; 01145 01146 template<typename CLASS, bool LOCK_MODULE> 01147 struct factory 01148 { 01149 COMET_FORCEINLINE static ::IUnknown* get(const CLSID&) 01150 { 01151 return 0; 01152 } 01153 }; 01154 }; // entry_builder<true> 01155 01156 template<> struct entry_builder<false> 01157 { 01158 template<typename CLASS> 01159 struct registration 01160 { 01161 static void perform(const TCHAR *filename, bool unregister, bool inproc_server, const GUID* appid) 01162 { 01163 if(unregister) { 01164 try { 01165 custom_registration<CLASS>().on_unregister(filename); 01166 } 01167 catch(...) 01168 { 01169 01170 } 01171 } 01172 01173 reghelper::update_coclass(unregister, 01174 uuidof<CLASS>(), 01175 filename, 01176 tm_properties<coclass_implementation<CLASS>::thread_model>::string(), 01177 CLASS::name(), 01178 coclass_implementation<CLASS>::get_progid(), 01179 CLASS::major_version, 01180 uuidof<CLASS::type_library>(), 01181 inproc_server, 01182 appid); 01183 01184 if(!unregister) 01185 custom_registration<CLASS>().on_register(filename); 01186 } // perform 01187 }; // registration 01188 01189 01190 template<int> 01191 struct factory_builder { }; 01192 01193 template<> struct factory_builder<ft_standard> 01194 { 01195 template<typename CLASS, bool LOCK_MODULE> 01196 struct factory 01197 { 01198 typedef class_factory<CLASS, LOCK_MODULE> is_factory; 01199 }; 01200 }; 01201 template<> struct factory_builder<ft_aggregateable> 01202 { 01203 template<typename CLASS, bool LOCK_MODULE> 01204 struct factory 01205 { 01206 typedef class_factory_agg<CLASS, LOCK_MODULE> is_factory; 01207 }; 01208 }; 01209 template<> struct factory_builder<ft_singleton> 01210 { 01211 template<typename CLASS, bool LOCK_MODULE> 01212 struct factory 01213 { 01214 typedef class_factory_singleton<CLASS, LOCK_MODULE> is_factory; 01215 }; 01216 }; 01217 01218 template<typename CLASS, bool LOCK_MODULE> 01219 struct factory_type 01220 { 01221 typedef COMET_STRICT_TYPENAME factory_builder< CLASS::factory_type >::factory<CLASS, LOCK_MODULE>::is_factory factory; 01222 }; 01223 template<typename CLASS, bool LOCK_MODULE> 01224 struct factory 01225 { 01226 typedef typename factory_type< coclass_implementation<CLASS>, LOCK_MODULE >::factory CLASS_FACTORY; 01227 01228 COMET_FORCEINLINE static ::IUnknown* get(const CLSID& clsid) 01229 { 01230 static CLASS_FACTORY class_factory_; 01231 01232 // NB: This might cause problems if CLASS_FACTORY 01233 // implemented more than one interface. If so, this logic will 01234 // have to be changed to inline the QueryInterface call instead. 01235 if (clsid == uuidof<CLASS>()) 01236 return &class_factory_; 01237 return 0; 01238 } // get 01239 }; // factory 01240 }; // entry_builder<false> 01241 01242 template<typename CLASS, bool FACTORY_LOCK_MODULE> 01243 struct coclass_table_entry 01244 { 01245 // We use sizeof here to determine if there is a specialization of coclass_implementation. 01246 // It is relying on the fact that any real implementation of coclass_implementation 01247 // must be at least sizeof IUnknown, whereas the default sizeof implementation 01248 // is always just a dummy class. 01249 enum { is_undefined = sizeof (coclass_implementation<CLASS>) == sizeof( coclass_implementation<nil>) }; 01250 01251 typedef typename entry_builder<is_undefined>::factory<CLASS, FACTORY_LOCK_MODULE> factory; 01252 typedef typename entry_builder<is_undefined>::registration<CLASS> registration; 01253 }; 01254 01255 #else // COMET_PARTIAL_SPECIALISATION 01256 template<bool undefined, typename CLASS, bool FACTORY_LOCK_MODULE> 01257 struct entry_builder 01258 { 01259 typedef nil factory; 01260 typedef nil registration; 01261 }; 01262 01263 template<typename CLASS, bool FACTORY_LOCK_MODULE> struct entry_builder<true, CLASS, FACTORY_LOCK_MODULE> 01264 { 01265 struct registration 01266 { 01267 COMET_FORCEINLINE static void perform(const TCHAR*, bool, bool, const GUID* ) {} 01268 }; 01269 01270 struct factory 01271 { 01272 COMET_FORCEINLINE static ::IUnknown* get(const CLSID&) 01273 { 01274 return 0; 01275 } 01276 }; 01277 }; // entry_builder<true> 01278 01279 template<int, typename CLASS, bool LOCK_MODULE> 01280 struct factory_builder_aux { }; 01281 01282 template<typename CLASS, bool LOCK_MODULE> struct factory_builder_aux<ft_standard,CLASS, LOCK_MODULE> 01283 { 01284 typedef class_factory<CLASS, LOCK_MODULE> is_factory; 01285 }; 01286 template<typename CLASS, bool LOCK_MODULE> struct factory_builder_aux<ft_aggregateable,CLASS, LOCK_MODULE> 01287 { 01288 typedef class_factory_agg<CLASS, LOCK_MODULE> is_factory; 01289 }; 01290 template<typename CLASS, bool LOCK_MODULE> struct factory_builder_aux<ft_singleton,CLASS, LOCK_MODULE> 01291 { 01292 typedef class_factory_singleton<CLASS, LOCK_MODULE> is_factory; 01293 }; 01294 01295 01296 template<typename CLASS, bool FACTORY_LOCK_MODULE> struct entry_builder<false, CLASS, FACTORY_LOCK_MODULE> 01297 { 01298 struct registration 01299 { 01300 static void perform(const TCHAR *filename, bool unregister, bool inproc_server, const GUID* appid) 01301 { 01302 if(unregister) { 01303 try { 01304 custom_registration<CLASS>().on_unregister(filename); 01305 } catch(...) {} 01306 } 01307 01308 reghelper::update_coclass(unregister, 01309 uuidof<CLASS>(), 01310 filename, 01311 tm_properties<coclass_implementation<CLASS>::thread_model>::string(), 01312 CLASS::name(), 01313 coclass_implementation<CLASS>::get_progid(), 01314 CLASS::major_version, 01315 uuidof<CLASS::type_library>(), 01316 inproc_server, 01317 appid); 01318 01319 if(!unregister) 01320 custom_registration<CLASS>().on_register(filename); 01321 } // perform 01322 }; // registration 01323 01324 struct factory_type 01325 { 01326 enum {type_ = coclass_implementation<CLASS>::factory_type }; 01327 typedef typename factory_builder_aux< type_, coclass_implementation<CLASS>, FACTORY_LOCK_MODULE >::is_factory factory; 01328 }; 01329 struct factory 01330 { 01331 typedef typename factory_type::factory CLASS_FACTORY; 01332 01333 COMET_FORCEINLINE static ::IUnknown* get(const CLSID& clsid) 01334 { 01335 static CLASS_FACTORY class_factory_; 01336 01337 // NB: This might cause problems if CLASS_FACTORY 01338 // implemented more than one interface. If so, this logic will 01339 // have to be changed to inline the QueryInterface call instead. 01340 if (clsid == uuidof<CLASS>()) 01341 return &class_factory_; 01342 return 0; 01343 } // get 01344 }; // factory 01345 }; // entry_builder<false> 01346 01347 template<typename CLASS, bool FACTORY_LOCK_MODULE> 01348 struct coclass_table_entry 01349 { 01350 // We use sizeof here to determine if there is a specialization of coclass_implementation. 01351 // It is relying on the fact that any real implementation of coclass_implementation 01352 // must be at least sizeof IUnknown, whereas the default sizeof implementation 01353 // is always just a dummy class. 01354 enum { is_undefined = (sizeof(coclass_implementation<CLASS>) == sizeof(coclass_implementation<nil>)) }; 01355 01356 typedef typename entry_builder<is_undefined,CLASS, FACTORY_LOCK_MODULE>::factory factory; 01357 typedef typename entry_builder<is_undefined,CLASS, FACTORY_LOCK_MODULE>::registration registration; 01358 }; 01359 #endif // COMET_PARTIAL_SPECIALISATION 01360 01361 } // namespace impl 01362 01366 template<typename CLS_LIST, bool FACTORY_SHOULD_LOCK_MODULE = true> 01367 class coclass_table 01368 { 01369 public: 01370 COMET_FORCEINLINE static ::IUnknown* find(const CLSID& clsid) 01371 { 01372 ::IUnknown *ret = COMET_STRICT_TYPENAME impl::coclass_table_entry<COMET_STRICT_TYPENAME CLS_LIST::head, FACTORY_SHOULD_LOCK_MODULE>::factory::get(clsid); 01373 return ret ? ret : coclass_table<COMET_STRICT_TYPENAME CLS_LIST::tail, FACTORY_SHOULD_LOCK_MODULE>::find(clsid); 01374 } 01375 01376 COMET_FORCEINLINE static void registration(const TCHAR* filename, bool unregister, bool inproc_server = true, const GUID* appid = 0) 01377 { 01378 COMET_STRICT_TYPENAME impl::coclass_table_entry<COMET_STRICT_TYPENAME CLS_LIST::head, FACTORY_SHOULD_LOCK_MODULE>::registration::perform(filename, unregister, inproc_server, appid); 01379 coclass_table<COMET_STRICT_TYPENAME CLS_LIST::tail, FACTORY_SHOULD_LOCK_MODULE>::registration(filename, unregister, inproc_server, appid); 01380 } 01381 }; 01382 01383 struct coclass_term 01384 { 01385 COMET_FORCEINLINE static ::IUnknown* find(const IID&) 01386 { 01387 return 0; 01388 } 01389 COMET_FORCEINLINE static void registration(const TCHAR*, bool, bool = true, const GUID* = 0) {} 01390 }; 01391 01392 // template<> class coclass_table<make_list<> > : public coclass_term {}; 01393 template<> class coclass_table<nil, true> : public coclass_term {}; 01394 template<> class coclass_table<nil, false> : public coclass_term {}; 01395 01396 enum { NO_EMBEDDED_TLB = 1}; 01397 01398 template<size_t FL> 01399 struct com_server_traits { 01400 enum { flags = FL }; 01401 enum { embedded_tlb = !(flags & NO_EMBEDDED_TLB) }; 01402 }; 01408 template<typename TYPELIB, typename TRAITS = com_server_traits<0> > class com_server 01409 { 01410 typedef coclass_table<typename TYPELIB::coclasses, true> COCLASS_TABLE; 01411 public: 01412 static BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID); 01413 static HRESULT DllCanUnloadNow(); 01414 static HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); 01415 static HRESULT DllRegisterServer(); 01416 static HRESULT DllUnregisterServer(); 01417 }; 01419 template<typename TYPELIB, typename TRAITS> 01420 BOOL WINAPI com_server<TYPELIB, TRAITS>::DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) 01421 { 01422 if (dwReason == DLL_PROCESS_ATTACH) 01423 { 01424 module().instance(hInstance); 01425 DisableThreadLibraryCalls(hInstance); 01426 01427 // initialize static variables in factory::get to avoid potential thread safety problem. 01428 ::IUnknown* cf = COCLASS_TABLE::find(IID_NULL); 01429 /* prevent warning */ cf; 01430 } 01431 else if (dwReason == DLL_PROCESS_DETACH) 01432 { 01433 module().shutdown(); 01434 } 01435 return TRUE; 01436 } 01437 01438 template<typename TYPELIB, typename TRAITS> 01439 HRESULT com_server<TYPELIB, TRAITS>::DllCanUnloadNow() 01440 { 01441 return module().rc() == 0 ? S_OK : S_FALSE; 01442 } 01443 01444 template<typename TYPELIB, typename TRAITS> 01445 HRESULT com_server<TYPELIB, TRAITS>::DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) 01446 { 01447 ::IUnknown* cf = COCLASS_TABLE::find(rclsid); 01448 if (cf == 0) return CLASS_E_CLASSNOTAVAILABLE; 01449 01450 return cf->QueryInterface(riid, ppv); 01451 } 01452 01453 namespace impl { 01454 template<size_t embedded> 01455 struct typelibrary_registration 01456 { 01457 static void convert(wchar_t *dest, const char *src) 01458 { 01459 ::mbstowcs(dest, src, MAX_PATH); 01460 } 01461 static void convert(wchar_t *dest, const wchar_t *src) 01462 { 01463 ::wcscpy(dest, src); 01464 } 01465 static HRESULT perform(const TCHAR *filename, bool unregister) throw() 01466 { 01467 wchar_t wfilename[MAX_PATH]; 01468 convert(wfilename, filename); 01469 ITypeLib* tl; 01470 HRESULT hr = LoadTypeLib(wfilename, &tl); 01471 if (SUCCEEDED(hr)) { 01472 if(unregister) { 01473 TLIBATTR *tla = 0; 01474 hr = tl->GetLibAttr(&tla); 01475 if (SUCCEEDED(hr)) { 01476 hr = UnRegisterTypeLib(tla->guid, tla->wMajorVerNum, tla->wMinorVerNum, tla->lcid, tla->syskind); 01477 tl->ReleaseTLibAttr(tla); 01478 } 01479 } 01480 else 01481 hr = RegisterTypeLib(tl, wfilename, 0); 01482 tl->Release(); 01483 } 01484 return hr; 01485 } 01486 }; 01487 01488 template<> struct typelibrary_registration<0> 01489 { 01490 COMET_FORCEINLINE static HRESULT perform(const TCHAR *, bool) 01491 { 01492 return S_OK; 01493 } 01494 }; 01495 } // namespace impl 01496 01497 template<typename TYPELIB, typename TRAITS> 01498 HRESULT com_server<TYPELIB, TRAITS>::DllRegisterServer() 01499 { 01500 TCHAR filename[MAX_PATH]; 01501 01502 GetModuleFileName(module().instance(), filename, MAX_PATH); 01503 01504 { 01505 HRESULT hr = impl::typelibrary_registration<TRAITS::embedded_tlb>::perform(filename, false); 01506 if(FAILED(hr)) return SELFREG_E_TYPELIB; 01507 } 01508 01509 try { 01510 COCLASS_TABLE::registration(filename, false); 01511 } 01512 catch (const com_error &e) 01513 { 01514 DllUnregisterServer(); 01515 return impl::return_com_error(e); 01516 } 01517 catch (const std::exception &e) 01518 { 01519 DllUnregisterServer(); 01520 ::OutputDebugStringA(e.what()); 01521 return E_FAIL; 01522 } 01523 01524 return S_OK; 01525 } 01526 01527 template<typename TYPELIB, typename TRAITS> 01528 HRESULT com_server<TYPELIB, TRAITS>::DllUnregisterServer() 01529 { 01530 TCHAR filename[MAX_PATH]; 01531 GetModuleFileName(module().instance(), filename, MAX_PATH); 01532 01533 impl::typelibrary_registration<TRAITS::embedded_tlb>::perform(filename, true); 01534 01535 COCLASS_TABLE::registration(filename, true); 01536 return S_OK; 01537 } 01543 #define COMET_DECLARE_DLL_FUNCTIONS(SERVER) \ 01544 extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) \ 01545 { \ 01546 return SERVER::DllMain(hInstance, dwReason, 0); \ 01547 } \ 01548 \ 01549 STDAPI DllCanUnloadNow() \ 01550 { \ 01551 return SERVER::DllCanUnloadNow(); \ 01552 } \ 01553 \ 01554 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) \ 01555 { \ 01556 return SERVER::DllGetClassObject(rclsid, riid, ppv); \ 01557 } \ 01558 \ 01559 STDAPI DllRegisterServer() \ 01560 { \ 01561 return SERVER::DllRegisterServer(); \ 01562 } \ 01563 \ 01564 STDAPI DllUnregisterServer() \ 01565 { \ 01566 return SERVER::DllUnregisterServer(); \ 01567 } 01568 01569 } 01570 01571 #endif