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