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