Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages
cp.h
Go to the documentation of this file.00001 00014 /* 00015 * Copyright © 2000 Sofus Mortensen 00016 * 00017 * This material is provided "as is", with absolutely no warranty 00018 * expressed or implied. Any use is at your own risk. Permission to 00019 * use or copy this software for any purpose is hereby granted without 00020 * fee, provided the above notices are retained on all copies. 00021 * Permission to modify the code and to distribute modified code is 00022 * granted, provided the above notices are retained, and a notice that 00023 * the code was modified is included with the above copyright notice. 00024 * 00025 * This header is part of comet. 00026 * http://www.lambdasoft.dk/comet 00027 */ 00028 00029 #ifndef COMET_CP_H 00030 #define COMET_CP_H 00031 00032 #include <comet/config.h> 00033 00034 #include <map> 00035 00036 #include <comet/server.h> 00037 #include <comet/enum.h> 00038 00039 #pragma warning( push ) 00040 #pragma warning( disable : 4355 ) 00041 00124 namespace comet { 00125 00126 template<typename Itf> class connection_point; 00127 00137 template<typename Itf> class ATL_NO_VTABLE simple_cpc : public IConnectionPointContainer 00138 { 00139 public: 00140 typedef IConnectionPointContainer interface_is; 00141 00142 protected: 00144 00145 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints**) 00146 { 00147 return E_NOTIMPL; 00148 } 00149 00150 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP) 00151 { 00152 if (!ppCP) return E_POINTER; 00153 if (riid == uuidof<Itf>()) { 00154 *ppCP = &connection_point; 00155 (*ppCP)->AddRef(); 00156 return S_OK; 00157 } 00158 return CONNECT_E_NOCONNECTION; 00159 } 00161 00162 protected: 00163 simple_cpc() : connection_point(this) {} 00164 00165 connection_point<Itf> connection_point; 00166 }; 00167 00168 00173 template<typename Itf> class connection_point_for 00174 { 00175 public: 00176 connection_point_for(::IUnknown *self) : connection_point(self) {} 00177 connection_point<Itf> connection_point; 00178 }; 00179 00180 00181 namespace impl { 00182 00186 template<typename ITF_LIST> struct connection_point_finder 00187 { 00188 template<typename T> COMET_FORCEINLINE static ::IConnectionPoint* find_connection_point(T* This, const IID& iid) 00189 { 00190 typedef find_compatibility< COMET_STRICT_TYPENAME ITF_LIST::head > compatible; 00191 if (iid == uuidof<COMET_STRICT_TYPENAME ITF_LIST::head>()) 00192 return &((static_cast<connection_point_for< COMET_STRICT_TYPENAME ITF_LIST::head > *>(This))->connection_point) ; 00193 else return connection_point_finder<COMET_STRICT_TYPENAME ITF_LIST::tail>::find_connection_point(This, iid); 00194 } 00195 }; 00196 template<> struct connection_point_finder<nil> 00197 { 00198 template<typename T> COMET_FORCEINLINE static ::IConnectionPoint* find_connection_point(T*, const IID&) 00199 { 00200 return 0; 00201 } 00202 }; 00203 00204 } 00205 00206 namespace impl { 00207 00208 00209 template<typename ITF_LIST> struct ATL_NO_VTABLE inherit_all_ex_unknown; 00210 00211 #ifdef COMET_GOOD_RECURSIVE_STRUCT 00212 // Remove level of indirection. PC-lint cannot handle it, and MSVC7 00213 // should be ale to. 00214 template<typename ITF_LIST> struct ATL_NO_VTABLE inherit_all_ex_unknown 00215 : public ITF_LIST::head, public inherit_all_ex_unknown<typename ITF_LIST::tail > 00216 { 00217 inherit_all_ex_unknown( ::IUnknown *initParam) 00218 : ITF_LIST::head(initParam), inherit_all_ex_unknown< COMET_STRICT_TYPENAME ITF_LIST::tail >(initParam) 00219 {} 00220 }; 00221 template<> struct inherit_all_ex_unknown<nil> { inherit_all_ex_unknown(::IUnknown *) {} }; 00222 00223 #else // COMET_GOOD_RECURSIVE_STRUCT 00224 template<typename HEAD, typename ITF_TAIL> struct ATL_NO_VTABLE inherit_all_ex_aux_unknown 00225 : public HEAD, public inherit_all_ex_unknown<ITF_TAIL> 00226 { 00227 inherit_all_ex_aux_unknown( ::IUnknown *initParam) 00228 : HEAD(initParam), inherit_all_ex_unknown<ITF_TAIL>(initParam) 00229 {} 00230 }; 00231 00232 // COMET_CONFIG_H is always defined! This is just a trick to get Doxygen to ignore the following declaration that 00233 // otherwise seems to be cause an exception in Doxygen 1.2.8 00234 #ifdef COMET_CONFIG_H 00235 template<typename ITF_LIST> struct ATL_NO_VTABLE inherit_all_ex_unknown 00236 : public inherit_all_ex_aux_unknown<typename ITF_LIST::head,typename ITF_LIST::tail > 00237 { 00238 inherit_all_ex_unknown( ::IUnknown *initParam) 00239 :inherit_all_ex_aux_unknown< COMET_STRICT_TYPENAME ITF_LIST::head, COMET_STRICT_TYPENAME ITF_LIST::tail >(initParam) 00240 { 00241 } 00242 }; 00243 template<> struct inherit_all_ex_unknown<nil> { inherit_all_ex_unknown(::IUnknown *) {} }; 00244 #endif // COMET_CONFIG_H 00245 #endif // COMET_GOOD_RECURSIVE_STRUCT 00246 00247 00248 00249 } 00250 00251 00252 COMET_WRAP_EACH_DECLARE( connection_point_for); 00253 00254 00265 template< typename ITF_LST> struct ATL_NO_VTABLE implement_cpc : public IConnectionPointContainer 00266 , public impl::inherit_all_ex_unknown< COMET_WRAP_EACH(connection_point_for, ITF_LST) > 00267 { 00268 typedef IConnectionPointContainer interface_is; 00269 public: 00270 implement_cpc() 00271 : impl::inherit_all_ex_unknown< COMET_WRAP_EACH(connection_point_for, ITF_LST) >((::IUnknown *)this) 00272 {} 00273 00274 protected: 00275 friend struct impl::connection_point_finder<ITF_LST>; 00277 00278 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints**) 00279 { 00280 return E_NOTIMPL; 00281 } 00282 00283 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP) 00284 { 00285 if (!ppCP) return E_POINTER; 00286 00287 const IID& iid = riid; 00288 00289 *ppCP = impl::connection_point_finder<ITF_LST>::find_connection_point(this, iid); 00290 00291 if ( *ppCP !=NULL) 00292 { 00293 (*ppCP)->AddRef(); 00294 return S_OK; 00295 } 00296 return CONNECT_E_NOCONNECTION; 00297 } 00299 }; 00300 00301 00306 template<typename Itf> class ATL_NO_VTABLE connection_point_impl : public embedded_object< IUnknown, IConnectionPoint > 00307 { 00308 public: 00309 bool is_connected() const 00310 { return !connections_.empty(); } 00311 protected: 00312 connection_point_impl(::IUnknown* pUnk) : next_cookie_(1), embedded_object< IUnknown, IConnectionPoint >(pUnk) {} 00313 00315 00316 STDMETHOD(GetConnectionInterface)(IID* pIID) 00317 { 00318 *pIID = uuidof<Itf>(); 00319 return S_OK; 00320 } 00321 00322 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC) { 00323 com_ptr<IConnectionPointContainer> p; 00324 p = try_cast(com_ptr< ::IUnknown >(get_parent())); 00325 *ppCPC = com_ptr<IConnectionPointContainer>::detach( p ); 00326 return S_OK; 00327 } 00328 00329 STDMETHOD(Advise)(::IUnknown* pUnkSink, DWORD* pdwCookie) 00330 { 00331 try { 00332 connections_[next_cookie_] = try_cast( com_ptr< ::IUnknown >(pUnkSink) ); 00333 } 00334 catch (...) { 00335 return CONNECT_E_CANNOTCONNECT; 00336 } 00337 *pdwCookie = next_cookie_++; 00338 return S_OK; 00339 } 00340 STDMETHOD(Unadvise)(DWORD dwCookie) 00341 { 00342 CONNECTIONS::iterator it = connections_.find(dwCookie); 00343 if (it == connections_.end()) return CONNECT_E_NOCONNECTION; 00344 connections_.erase(it); 00345 return S_OK; 00346 } 00347 00348 STDMETHOD(EnumConnections)(IEnumConnections** ppEnum) 00349 { 00350 try { 00351 *ppEnum = com_ptr<IEnumConnections>::detach( stl_enumeration<IEnumConnections>::create(connections_, get_unknown()) ); 00352 } catch (...) { 00353 return E_FAIL; 00354 } 00355 return S_OK; 00356 } 00358 00359 typedef std::map<DWORD, com_ptr<Itf> > CONNECTIONS; 00360 CONNECTIONS connections_; 00361 private: 00362 UINT next_cookie_; 00363 }; 00364 00369 template<typename Itf> class ATL_NO_VTABLE sink_impl : public static_object<Itf> 00370 { 00371 public: 00374 void advise(const com_ptr<::IUnknown>& t) 00375 { 00376 if (ptr_) throw std::runtime_error("Cannot double advise."); 00377 com_ptr<IConnectionPointContainer> cpc( try_cast(t) ); 00378 IConnectionPoint* cp; 00379 cpc->FindConnectionPoint( uuidof<Itf>(), &cp) | raise_exception; 00380 00381 HRESULT hr = cp->Advise(static_cast< ::IUnknown* >(static_cast<Itf*>(this)), &cookie_); 00382 00383 cp->Release(); 00384 00385 hr | raise_exception; 00386 00387 ptr_ = t; 00388 } 00389 00392 void unadvise() 00393 { 00394 if (ptr_) { 00395 com_ptr<IConnectionPointContainer> cpc( try_cast(ptr_) ); 00396 IConnectionPoint* cp; 00397 cpc->FindConnectionPoint( uuidof<Itf>(), &cp) | raise_exception; 00398 00399 HRESULT hr = cp->Unadvise(cookie_); 00400 cookie_ = 0; 00401 ptr_ = 0; 00402 00403 cp->Release(); 00404 00405 hr | raise_exception; 00406 } 00407 } 00408 00411 com_ptr<::IUnknown> object() 00412 { 00413 return ptr_; 00414 } 00415 00418 bool is_advised() 00419 { 00420 return !ptr_.is_null(); 00421 } 00422 00423 protected: 00424 sink_impl() : cookie_(0) {} 00425 ~sink_impl() { unadvise(); } 00426 private: 00427 DWORD cookie_; 00428 com_ptr<::IUnknown> ptr_; 00429 }; 00431 00432 } 00433 00434 #pragma warning( pop ) 00435 00436 #endif