exe_server.h

Go to the documentation of this file.
00001 00004 /* 00005 * Copyright © 2001, 2002 Mikael Lindgren, Sofus Mortensen 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_EXE_SERVER_H 00020 #define COMET_EXE_SERVER_H 00021 00022 #include <comet/server.h> 00023 #include <comet/static_assert.h> 00024 00025 namespace comet { 00026 00027 namespace impl { 00028 template <typename CLS_LIST> struct register_class_entry 00029 { 00030 typedef COMET_STRICT_TYPENAME CLS_LIST::head CLASS; 00031 typedef COMET_STRICT_TYPENAME CLS_LIST::tail NEXT; 00032 00033 template <typename CLS> struct register_info 00034 { 00035 DWORD id; 00036 }; 00037 00038 static register_info<CLASS>& get_register_info() 00039 { 00040 static register_info<CLASS> info; 00041 return info; 00042 } 00043 COMET_FORCEINLINE static HRESULT register_class_object(DWORD context, DWORD flags) 00044 { 00045 const IID& clsid = comtype<CLASS>::uuid(); 00046 ::IUnknown* p = COMET_STRICT_TYPENAME impl::coclass_table_entry<CLASS, false>::factory::get(clsid); 00047 if (p) 00048 { 00049 HRESULT hr = ::CoRegisterClassObject(clsid, p, context, flags, &get_register_info().id); 00050 p->Release(); 00051 if (hr != S_OK) 00052 return hr; 00053 } 00054 return register_class_entry<NEXT>::register_class_object(context, flags); 00055 } 00056 00057 COMET_FORCEINLINE static void revoke_class_object() 00058 { 00059 ::CoRevokeClassObject(get_register_info().id); 00060 register_class_entry<NEXT>::revoke_class_object(); 00061 } 00062 }; 00063 00064 template <> struct register_class_entry<nil> 00065 { 00066 COMET_FORCEINLINE static HRESULT register_class_object(DWORD context, DWORD flags) 00067 { 00068 return S_OK; 00069 } 00070 00071 COMET_FORCEINLINE static void revoke_class_object() 00072 { 00073 } 00074 }; 00075 }; 00076 00080 00082 template<typename TYPELIB, bool FREE_THREADED = false, typename TRAITS = com_server_traits<0> > class exe_server : private thread 00083 { 00084 #if !(_WIN32_WINNT >= 0x0400 ) && !defined(_WIN32_DCOM) 00085 // Implementing a free threaded exe server requires NT 4.0 or better. 00086 COMET_STATIC_ASSERT(FREE_THREADED == false); 00087 #endif 00088 00089 typedef coclass_table<typename TYPELIB::coclasses, false> COCLASS_TABLE; 00090 00091 enum { terminate_pause = 1000, idle_shutdown_time = 5000 }; 00092 00093 public: 00094 exe_server(HINSTANCE instance); 00095 exe_server(HINSTANCE instance, const GUID& appid, const tstring& appid_descr); 00096 ~exe_server(); 00097 00098 HRESULT run(); 00099 00100 HRESULT register_server(); 00101 HRESULT unregister_server(); 00102 HRESULT register_class_objects(DWORD context, DWORD flags); 00103 void revoke_class_objects(); 00104 00105 private: 00106 event shutdown_event_; 00107 DWORD main_thread_id_; 00108 const GUID* appid_; 00109 tstring appid_descr_; 00110 00111 virtual DWORD thread_main(); 00112 }; 00114 00115 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00116 exe_server<TYPELIB, FREE_THREADED, TRAITS>::exe_server(HINSTANCE instance): 00117 main_thread_id_(::GetCurrentThreadId()), 00118 appid_(0) 00119 { 00120 module_t& m = module(); 00121 00122 m.instance(instance); 00123 m.set_shutdown_event(shutdown_event_); 00124 00125 // initialize static variables in factory::get to avoid potential thread safety problem. 00126 ::IUnknown* cf = COCLASS_TABLE::find(IID_NULL); 00127 } 00128 00129 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00130 exe_server<TYPELIB, FREE_THREADED, TRAITS>::exe_server(HINSTANCE instance, const GUID& appid, const tstring& appid_descr): 00131 main_thread_id_(::GetCurrentThreadId()), 00132 appid_(&appid), appid_descr_(appid_descr) 00133 { 00134 module_t& m = module(); 00135 00136 m.instance(instance); 00137 m.set_shutdown_event(shutdown_event_); 00138 00139 // initialize static variables in factory::get to avoid potential thread safety problem. 00140 ::IUnknown* cf = COCLASS_TABLE::find(IID_NULL); 00141 } 00142 00143 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00144 exe_server<TYPELIB, FREE_THREADED, TRAITS>::~exe_server() 00145 { 00146 module().clear_shutdown_event(); 00147 } 00148 00149 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00150 HRESULT exe_server<TYPELIB, FREE_THREADED, TRAITS>::run() 00151 { 00152 thread::start(); 00153 00154 HRESULT hr; 00155 #if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM 00156 if (FREE_THREADED) 00157 { 00158 hr = register_class_objects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE|REGCLS_SUSPENDED); 00159 if (SUCCEEDED(hr)) 00160 hr = ::CoResumeClassObjects(); 00161 } 00162 else 00163 #endif 00164 hr = register_class_objects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE); 00165 00166 if (SUCCEEDED(hr)) 00167 { 00168 MSG msg; 00169 while (::GetMessage(&msg, 0, 0, 0)) 00170 ::DispatchMessage(&msg); 00171 } 00172 else if (thread::running()) 00173 { 00174 shutdown_event_.set(); 00175 thread::wait(0); 00176 } 00177 00178 revoke_class_objects(); 00179 Sleep(terminate_pause); //wait for any threads to finish 00180 00181 module().shutdown(); 00182 00183 return hr; 00184 } 00185 00186 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00187 HRESULT exe_server<TYPELIB, FREE_THREADED, TRAITS>::register_server() 00188 { 00189 TCHAR filename[MAX_PATH]; 00190 00191 GetModuleFileName(module().instance(), filename, MAX_PATH); 00192 00193 { 00194 HRESULT hr = impl::typelibrary_registration<TRAITS::embedded_tlb>::perform(filename, false); 00195 if(FAILED(hr)) return SELFREG_E_TYPELIB; 00196 } 00197 00198 try { 00199 if (appid_) 00200 { 00201 tstring key(_T("AppID\\{") + uuid_t(*appid_).str() + _T("}")); 00202 00203 regkey rkey(HKEY_CLASSES_ROOT); 00204 rkey.create(key)[_T("")] = appid_descr_; 00205 } 00206 COCLASS_TABLE::registration(filename, false, false, appid_); 00207 } 00208 catch (const com_error &e) 00209 { 00210 unregister_server(); 00211 return impl::return_com_error(e); 00212 } 00213 catch (const std::exception &e) 00214 { 00215 unregister_server(); 00216 ::OutputDebugStringA(e.what()); 00217 return E_FAIL; 00218 } 00219 00220 return S_OK; 00221 } 00222 00223 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00224 HRESULT exe_server<TYPELIB, FREE_THREADED, TRAITS>::unregister_server() 00225 { 00226 TCHAR filename[MAX_PATH]; 00227 GetModuleFileName(module().instance(), filename, MAX_PATH); 00228 00229 impl::typelibrary_registration<TRAITS::embedded_tlb>::perform(filename, true); 00230 00231 if (appid_) 00232 { 00233 tstring key(_T("AppID\\{") + uuid_t(*appid_).str() + _T("}")); 00234 00235 regkey rkey(HKEY_CLASSES_ROOT); 00236 rkey.delete_subkey_nothrow(key); 00237 } 00238 COCLASS_TABLE::registration(filename, true, false, appid_); 00239 return S_OK; 00240 } 00241 00242 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00243 HRESULT exe_server<TYPELIB, FREE_THREADED, TRAITS>::register_class_objects(DWORD context, DWORD flags) 00244 { 00245 return impl::register_class_entry<TYPELIB::coclasses>::register_class_object(context, flags); 00246 } 00247 00248 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00249 void exe_server<TYPELIB, FREE_THREADED, TRAITS>::revoke_class_objects() 00250 { 00251 impl::register_class_entry<TYPELIB::coclasses>::revoke_class_object(); 00252 } 00253 00254 template<typename TYPELIB, bool FREE_THREADED, typename TRAITS> 00255 DWORD exe_server<TYPELIB, FREE_THREADED, TRAITS>::thread_main() 00256 { 00257 module_t& m = module(); 00258 00259 while (1) 00260 { 00261 shutdown_event_.wait(); 00262 do 00263 { 00264 m.reset_activity_flag(); 00265 } while (shutdown_event_.wait(idle_shutdown_time)); 00266 // timed out 00267 00268 if (!m.has_activity()) // if no activity let's really bail 00269 { 00270 #if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM 00271 if (FREE_THREADED) 00272 { 00273 ::CoSuspendClassObjects(); 00274 if (!m.has_activity()) 00275 break; 00276 } 00277 else 00278 break; 00279 #else 00280 break; 00281 #endif 00282 } 00283 } 00284 ::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0); 00285 return 0; 00286 } 00287 }; 00288 00289 00290 #endif