]> git.saurik.com Git - wxWidgets.git/blame - src/common/dynload.cpp
Don't use "Cancel" button in the about dialog of the listctrl sample.
[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{
7ed9cd28 79 const wxClassInfo* const oldFirst = wxClassInfo::GetFirst();
4f89dbc4 80 Load( libname, flags );
7ed9cd28 81
7cc3d0e0
VZ
82 // It is simple to know what is the first object in the linked list of
83 // wxClassInfo that we registered (it's also the last one chronologically),
84 // it's just the new head of the wxClassInfo list:
85 m_ourFirst = wxClassInfo::GetFirst();
7ed9cd28
VZ
86
87 // But to find the first wxClassInfo created by this library we need to
88 // iterate until we get to the previous head as we don't have the links in
89 // the backwards direction:
7cc3d0e0 90 if ( m_ourFirst != oldFirst )
7ed9cd28 91 {
7cc3d0e0 92 for ( const wxClassInfo* info = m_ourFirst; ; info = info->GetNext() )
7ed9cd28
VZ
93 {
94 if ( info->GetNext() == oldFirst )
95 {
7cc3d0e0 96 m_ourLast = info;
7ed9cd28
VZ
97 break;
98 }
99 }
100 }
101 else // We didn't register any classes at all.
102 {
103 m_ourFirst =
104 m_ourLast = NULL;
105 }
4f89dbc4 106
0b9ab0bd
RL
107 if( m_handle != 0 )
108 {
2d4957f2 109 UpdateClasses();
0b9ab0bd
RL
110 RegisterModules();
111 }
112 else
d0fcccc4
VZ
113 {
114 // Flag us for deletion
115 --m_linkcount;
116 }
0b9ab0bd
RL
117}
118
4f89dbc4 119wxPluginLibrary::~wxPluginLibrary()
0b9ab0bd 120{
01610529
RL
121 if( m_handle != 0 )
122 {
123 UnregisterModules();
2d4957f2 124 RestoreClasses();
01610529 125 }
0b9ab0bd
RL
126}
127
d0fcccc4
VZ
128wxPluginLibrary *wxPluginLibrary::RefLib()
129{
130 wxCHECK_MSG( m_linkcount > 0, NULL,
9a83f860 131 wxT("Library had been already deleted!") );
d0fcccc4
VZ
132
133 ++m_linkcount;
134 return this;
135}
136
4f89dbc4 137bool wxPluginLibrary::UnrefLib()
7c1e2b44 138{
d0fcccc4 139 wxASSERT_MSG( m_objcount == 0,
9a83f860 140 wxT("Library unloaded before all objects were destroyed") );
d0fcccc4 141
ebf0caa1 142 if ( m_linkcount == 0 || --m_linkcount == 0 )
7c1e2b44
RL
143 {
144 delete this;
68379eaf 145 return true;
7c1e2b44 146 }
d0fcccc4 147
68379eaf 148 return false;
7c1e2b44 149}
0b9ab0bd
RL
150
151// ------------------------
152// Private methods
153// ------------------------
154
2d4957f2
VS
155void wxPluginLibrary::UpdateClasses()
156{
7ed9cd28
VZ
157 if ( !m_ourFirst )
158 return;
159
160 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
2d4957f2 161 {
b77a9389 162 if( info->GetClassName() )
2d4957f2
VS
163 {
164 // Hash all the class names into a local table too so
165 // we can quickly find the entry they correspond to.
b77a9389 166 (*ms_classes)[info->GetClassName()] = this;
2d4957f2 167 }
7ed9cd28
VZ
168
169 if ( info == m_ourLast )
170 break;
2d4957f2
VS
171 }
172}
173
174void wxPluginLibrary::RestoreClasses()
175{
ebf0caa1
VS
176 // Check if there is a need to restore classes.
177 if (!ms_classes)
178 return;
179
7ed9cd28
VZ
180 if ( !m_ourFirst )
181 return;
182
183 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
2d4957f2 184 {
b77a9389 185 ms_classes->erase(ms_classes->find(info->GetClassName()));
7ed9cd28
VZ
186
187 if ( info == m_ourLast )
188 break;
2d4957f2
VS
189 }
190}
191
4f89dbc4 192void wxPluginLibrary::RegisterModules()
0b9ab0bd
RL
193{
194 // Plugin libraries might have wxModules, Register and initialise them if
195 // they do.
196 //
197 // Note that these classes are NOT included in the reference counting since
198 // it's implicit that they will be unloaded if and when the last handle to
199 // the library is. We do have to keep a copy of the module's pointer
200 // though, as there is currently no way to Unregister it without it.
201
7c1e2b44 202 wxASSERT_MSG( m_linkcount == 1,
9a83f860 203 wxT("RegisterModules should only be called for the first load") );
0b9ab0bd 204
7ed9cd28 205 if ( m_ourFirst )
0b9ab0bd 206 {
7ed9cd28 207 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
0b9ab0bd 208 {
80a46597 209 if( info->IsKindOf(wxCLASSINFO(wxModule)) )
7ed9cd28
VZ
210 {
211 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
212
213 wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
0b9ab0bd 214
7ed9cd28
VZ
215 m_wxmodules.push_back(m);
216 wxModule::RegisterModule(m);
217 }
0b9ab0bd 218
7ed9cd28
VZ
219 if ( info == m_ourLast )
220 break;
0b9ab0bd
RL
221 }
222 }
223
224 // FIXME: Likewise this is (well was) very similar to InitializeModules()
225
df5168c4
MB
226 for ( wxModuleList::iterator it = m_wxmodules.begin();
227 it != m_wxmodules.end();
228 ++it)
0b9ab0bd 229 {
df5168c4 230 if( !(*it)->Init() )
0b9ab0bd 231 {
9a83f860 232 wxLogDebug(wxT("wxModule::Init() failed for wxPluginLibrary"));
0b9ab0bd
RL
233
234 // XXX: Watch this, a different hash implementation might break it,
235 // a good hash implementation would let us fix it though.
236
237 // The name of the game is to remove any uninitialised modules and
238 // let the dtor Exit the rest on shutdown, (which we'll initiate
239 // shortly).
240
df5168c4 241 wxModuleList::iterator oldNode = m_wxmodules.end();
0b9ab0bd 242 do {
df5168c4
MB
243 ++it;
244 if( oldNode != m_wxmodules.end() )
245 m_wxmodules.erase(oldNode);
246 wxModule::UnregisterModule( *it );
247 oldNode = it;
248 } while( it != m_wxmodules.end() );
0b9ab0bd 249
7c1e2b44 250 --m_linkcount; // Flag us for deletion
0b9ab0bd
RL
251 break;
252 }
253 }
254}
255
4f89dbc4 256void wxPluginLibrary::UnregisterModules()
0b9ab0bd 257{
df5168c4 258 wxModuleList::iterator it;
0b9ab0bd 259
df5168c4
MB
260 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
261 (*it)->Exit();
0b9ab0bd 262
df5168c4
MB
263 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
264 wxModule::UnregisterModule( *it );
0b9ab0bd 265
5385fa5b
VS
266 // NB: content of the list was deleted by UnregisterModule calls above:
267 m_wxmodules.clear();
0b9ab0bd
RL
268}
269
270
271// ---------------------------------------------------------------------------
d0fcccc4 272// wxPluginManager
0b9ab0bd
RL
273// ---------------------------------------------------------------------------
274
dabd1377 275wxDLManifest* wxPluginManager::ms_manifest = NULL;
0b9ab0bd
RL
276
277// ------------------------
278// Static accessors
279// ------------------------
280
d0fcccc4
VZ
281wxPluginLibrary *
282wxPluginManager::LoadLibrary(const wxString &libname, int flags)
0b9ab0bd 283{
4f89dbc4 284 wxString realname(libname);
0b9ab0bd 285
4f89dbc4
RL
286 if( !(flags & wxDL_VERBATIM) )
287 realname += wxDynamicLibrary::GetDllExt();
288
d0fcccc4
VZ
289 wxPluginLibrary *entry;
290
291 if ( flags & wxDL_NOSHARE )
292 {
293 entry = NULL;
294 }
295 else
296 {
2b5f62a0 297 entry = FindByName(realname);
d0fcccc4 298 }
4f89dbc4 299
d0fcccc4 300 if ( entry )
0b9ab0bd 301 {
9a83f860
VZ
302 wxLogTrace(wxT("dll"),
303 wxT("LoadLibrary(%s): already loaded."), realname.c_str());
d0fcccc4 304
7c1e2b44 305 entry->RefLib();
0b9ab0bd
RL
306 }
307 else
308 {
4f89dbc4 309 entry = new wxPluginLibrary( libname, flags );
0b9ab0bd 310
d0fcccc4 311 if ( entry->IsLoaded() )
0b9ab0bd 312 {
2b5f62a0 313 (*ms_manifest)[realname] = entry;
d0fcccc4 314
9a83f860
VZ
315 wxLogTrace(wxT("dll"),
316 wxT("LoadLibrary(%s): loaded ok."), realname.c_str());
d0fcccc4 317
0b9ab0bd
RL
318 }
319 else
320 {
9a83f860
VZ
321 wxLogTrace(wxT("dll"),
322 wxT("LoadLibrary(%s): failed to load."), realname.c_str());
d0fcccc4
VZ
323
324 // we have created entry just above
325 if ( !entry->UnrefLib() )
326 {
327 // ... so UnrefLib() is supposed to delete it
9a83f860 328 wxFAIL_MSG( wxT("Currently linked library is not loaded?") );
d0fcccc4
VZ
329 }
330
331 entry = NULL;
0b9ab0bd
RL
332 }
333 }
d0fcccc4 334
0b9ab0bd
RL
335 return entry;
336}
337
d0fcccc4 338bool wxPluginManager::UnloadLibrary(const wxString& libname)
0b9ab0bd 339{
d0fcccc4 340 wxString realname = libname;
4f89dbc4 341
2b5f62a0 342 wxPluginLibrary *entry = FindByName(realname);
0b9ab0bd 343
d0fcccc4
VZ
344 if ( !entry )
345 {
346 realname += wxDynamicLibrary::GetDllExt();
0b9ab0bd 347
2b5f62a0 348 entry = FindByName(realname);
d0fcccc4
VZ
349 }
350
351 if ( !entry )
352 {
9a83f860 353 wxLogDebug(wxT("Attempt to unload library '%s' which is not loaded."),
d0fcccc4
VZ
354 libname.c_str());
355
68379eaf 356 return false;
d0fcccc4
VZ
357 }
358
9a83f860 359 wxLogTrace(wxT("dll"), wxT("UnloadLibrary(%s)"), realname.c_str());
d0fcccc4
VZ
360
361 if ( !entry->UnrefLib() )
362 {
363 // not really unloaded yet
68379eaf 364 return false;
d0fcccc4
VZ
365 }
366
2b5f62a0 367 ms_manifest->erase(ms_manifest->find(realname));
d0fcccc4 368
68379eaf 369 return true;
4f89dbc4
RL
370}
371
0b9ab0bd
RL
372// ------------------------
373// Class implementation
374// ------------------------
375
23213f18 376bool wxPluginManager::Load(const wxString &libname, int flags)
0b9ab0bd 377{
4f89dbc4 378 m_entry = wxPluginManager::LoadLibrary(libname, flags);
2b5f62a0 379
4f89dbc4 380 return IsLoaded();
0b9ab0bd
RL
381}
382
4f89dbc4 383void wxPluginManager::Unload()
0b9ab0bd 384{
9a83f860 385 wxCHECK_RET( m_entry, wxT("unloading an invalid wxPluginManager?") );
0b9ab0bd 386
2b5f62a0
VZ
387 for ( wxDLManifest::iterator i = ms_manifest->begin();
388 i != ms_manifest->end();
389 ++i )
4f89dbc4 390 {
2b5f62a0
VZ
391 if ( i->second == m_entry )
392 {
393 ms_manifest->erase(i);
46113053 394 break;
2b5f62a0 395 }
4f89dbc4 396 }
2b5f62a0
VZ
397
398 m_entry->UnrefLib();
399
400 m_entry = NULL;
0b9ab0bd
RL
401}
402
0b9ab0bd 403#endif // wxUSE_DYNAMIC_LOADER