1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/dynload.cpp 3// Purpose: Dynamic loading framework 4// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's 5// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux) 6// Modified by: 7// Created: 03/12/01 8// RCS-ID: $Id: dynload.cpp 40943 2006-08-31 19:31:43Z ABX $ 9// Copyright: (c) 2001 Ron Lee <ron@debian.org> 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13// ---------------------------------------------------------------------------- 14// headers 15// ---------------------------------------------------------------------------- 16 17#include "wx/wxprec.h" 18 19#ifdef __BORLANDC__ 20 #pragma hdrstop 21#endif 22 23#if wxUSE_DYNAMIC_LOADER 24 25#ifdef __WINDOWS__ 26 #include "wx/msw/private.h" 27#endif 28 29#ifndef WX_PRECOMP 30 #include "wx/log.h" 31 #include "wx/intl.h" 32 #include "wx/hash.h" 33 #include "wx/utils.h" 34 #include "wx/module.h" 35#endif 36 37#include "wx/strconv.h" 38 39#include "wx/dynload.h" 40 41 42// --------------------------------------------------------------------------- 43// wxPluginLibrary 44// --------------------------------------------------------------------------- 45 46 47wxDLImports* wxPluginLibrary::ms_classes = NULL; 48 49class wxPluginLibraryModule : public wxModule 50{ 51public: 52 wxPluginLibraryModule() { } 53 54 // TODO: create ms_classes on demand, why always preallocate it? 55 virtual bool OnInit() 56 { 57 wxPluginLibrary::ms_classes = new wxDLImports; 58 wxPluginManager::CreateManifest(); 59 return true; 60 } 61 62 virtual void OnExit() 63 { 64 delete wxPluginLibrary::ms_classes; 65 wxPluginLibrary::ms_classes = NULL; 66 wxPluginManager::ClearManifest(); 67 } 68 69private: 70 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule ) 71}; 72 73IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule) 74 75 76wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags) 77 : m_linkcount(1) 78 , m_objcount(0) 79{ 80 m_before = wxClassInfo::sm_first; 81 Load( libname, flags ); 82 m_after = wxClassInfo::sm_first; 83 84 if( m_handle != 0 ) 85 { 86 UpdateClasses(); 87 RegisterModules(); 88 } 89 else 90 { 91 // Flag us for deletion 92 --m_linkcount; 93 } 94} 95 96wxPluginLibrary::~wxPluginLibrary() 97{ 98 if( m_handle != 0 ) 99 { 100 UnregisterModules(); 101 RestoreClasses(); 102 } 103} 104 105wxPluginLibrary *wxPluginLibrary::RefLib() 106{ 107 wxCHECK_MSG( m_linkcount > 0, NULL, 108 _T("Library had been already deleted!") ); 109 110 ++m_linkcount; 111 return this; 112} 113 114bool wxPluginLibrary::UnrefLib() 115{ 116 wxASSERT_MSG( m_objcount == 0, 117 _T("Library unloaded before all objects were destroyed") ); 118 119 if ( m_linkcount == 0 || --m_linkcount == 0 ) 120 { 121 delete this; 122 return true; 123 } 124 125 return false; 126} 127 128// ------------------------ 129// Private methods 130// ------------------------ 131 132void wxPluginLibrary::UpdateClasses() 133{ 134 for (wxClassInfo *info = m_after; info != m_before; info = info->m_next) 135 { 136 if( info->GetClassName() ) 137 { 138 // Hash all the class names into a local table too so 139 // we can quickly find the entry they correspond to. 140 (*ms_classes)[info->GetClassName()] = this; 141 } 142 } 143} 144 145void wxPluginLibrary::RestoreClasses() 146{ 147 // Check if there is a need to restore classes. 148 if (!ms_classes) 149 return; 150 151 for(wxClassInfo *info = m_after; info != m_before; info = info->m_next) 152 { 153 ms_classes->erase(ms_classes->find(info->GetClassName())); 154 } 155} 156 157void wxPluginLibrary::RegisterModules() 158{ 159 // Plugin libraries might have wxModules, Register and initialise them if 160 // they do. 161 // 162 // Note that these classes are NOT included in the reference counting since 163 // it's implicit that they will be unloaded if and when the last handle to 164 // the library is. We do have to keep a copy of the module's pointer 165 // though, as there is currently no way to Unregister it without it. 166 167 wxASSERT_MSG( m_linkcount == 1, 168 _T("RegisterModules should only be called for the first load") ); 169 170 for ( wxClassInfo *info = m_after; info != m_before; info = info->m_next) 171 { 172 if( info->IsKindOf(CLASSINFO(wxModule)) ) 173 { 174 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule); 175 176 wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") ); 177 178 m_wxmodules.push_back(m); 179 wxModule::RegisterModule(m); 180 } 181 } 182 183 // FIXME: Likewise this is (well was) very similar to InitializeModules() 184 185 for ( wxModuleList::iterator it = m_wxmodules.begin(); 186 it != m_wxmodules.end(); 187 ++it) 188 { 189 if( !(*it)->Init() ) 190 { 191 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary")); 192 193 // XXX: Watch this, a different hash implementation might break it, 194 // a good hash implementation would let us fix it though. 195 196 // The name of the game is to remove any uninitialised modules and 197 // let the dtor Exit the rest on shutdown, (which we'll initiate 198 // shortly). 199 200 wxModuleList::iterator oldNode = m_wxmodules.end(); 201 do { 202 ++it; 203 if( oldNode != m_wxmodules.end() ) 204 m_wxmodules.erase(oldNode); 205 wxModule::UnregisterModule( *it ); 206 oldNode = it; 207 } while( it != m_wxmodules.end() ); 208 209 --m_linkcount; // Flag us for deletion 210 break; 211 } 212 } 213} 214 215void wxPluginLibrary::UnregisterModules() 216{ 217 wxModuleList::iterator it; 218 219 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) 220 (*it)->Exit(); 221 222 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) 223 wxModule::UnregisterModule( *it ); 224 225 // NB: content of the list was deleted by UnregisterModule calls above: 226 m_wxmodules.clear(); 227} 228 229 230// --------------------------------------------------------------------------- 231// wxPluginManager 232// --------------------------------------------------------------------------- 233 234wxDLManifest* wxPluginManager::ms_manifest = NULL; 235 236// ------------------------ 237// Static accessors 238// ------------------------ 239 240wxPluginLibrary * 241wxPluginManager::LoadLibrary(const wxString &libname, int flags) 242{ 243 wxString realname(libname); 244 245 if( !(flags & wxDL_VERBATIM) ) 246 realname += wxDynamicLibrary::GetDllExt(); 247 248 wxPluginLibrary *entry; 249 250 if ( flags & wxDL_NOSHARE ) 251 { 252 entry = NULL; 253 } 254 else 255 { 256 entry = FindByName(realname); 257 } 258 259 if ( entry ) 260 { 261 wxLogTrace(_T("dll"), 262 _T("LoadLibrary(%s): already loaded."), realname.c_str()); 263 264 entry->RefLib(); 265 } 266 else 267 { 268 entry = new wxPluginLibrary( libname, flags ); 269 270 if ( entry->IsLoaded() ) 271 { 272 (*ms_manifest)[realname] = entry; 273 274 wxLogTrace(_T("dll"), 275 _T("LoadLibrary(%s): loaded ok."), realname.c_str()); 276 277 } 278 else 279 { 280 wxLogTrace(_T("dll"), 281 _T("LoadLibrary(%s): failed to load."), realname.c_str()); 282 283 // we have created entry just above 284 if ( !entry->UnrefLib() ) 285 { 286 // ... so UnrefLib() is supposed to delete it 287 wxFAIL_MSG( _T("Currently linked library is not loaded?") ); 288 } 289 290 entry = NULL; 291 } 292 } 293 294 return entry; 295} 296 297bool wxPluginManager::UnloadLibrary(const wxString& libname) 298{ 299 wxString realname = libname; 300 301 wxPluginLibrary *entry = FindByName(realname); 302 303 if ( !entry ) 304 { 305 realname += wxDynamicLibrary::GetDllExt(); 306 307 entry = FindByName(realname); 308 } 309 310 if ( !entry ) 311 { 312 wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."), 313 libname.c_str()); 314 315 return false; 316 } 317 318 wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname.c_str()); 319 320 if ( !entry->UnrefLib() ) 321 { 322 // not really unloaded yet 323 return false; 324 } 325 326 ms_manifest->erase(ms_manifest->find(realname)); 327 328 return true; 329} 330 331// ------------------------ 332// Class implementation 333// ------------------------ 334 335bool wxPluginManager::Load(const wxString &libname, int flags) 336{ 337 m_entry = wxPluginManager::LoadLibrary(libname, flags); 338 339 return IsLoaded(); 340} 341 342void wxPluginManager::Unload() 343{ 344 wxCHECK_RET( m_entry, _T("unloading an invalid wxPluginManager?") ); 345 346 for ( wxDLManifest::iterator i = ms_manifest->begin(); 347 i != ms_manifest->end(); 348 ++i ) 349 { 350 if ( i->second == m_entry ) 351 { 352 ms_manifest->erase(i); 353 break; 354 } 355 } 356 357 m_entry->UnrefLib(); 358 359 m_entry = NULL; 360} 361 362#endif // wxUSE_DYNAMIC_LOADER 363