]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynload.cpp
simplify code so it always returns the same object
[wxWidgets.git] / src / common / dynload.cpp
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$
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
47 wxDLImports* wxPluginLibrary::ms_classes = NULL;
48
49 class wxPluginLibraryModule : public wxModule
50 {
51 public:
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 wxDELETE(wxPluginLibrary::ms_classes);
65 wxPluginManager::ClearManifest();
66 }
67
68 private:
69 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule )
70 };
71
72 IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule)
73
74
75 wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags)
76 : m_linkcount(1)
77 , m_objcount(0)
78 {
79 const wxClassInfo* const oldFirst = wxClassInfo::GetFirst();
80 Load( libname, flags );
81
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();
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:
90 if ( m_ourFirst != oldFirst )
91 {
92 for ( const wxClassInfo* info = m_ourFirst; ; info = info->GetNext() )
93 {
94 if ( info->GetNext() == oldFirst )
95 {
96 m_ourLast = info;
97 break;
98 }
99 }
100 }
101 else // We didn't register any classes at all.
102 {
103 m_ourFirst =
104 m_ourLast = NULL;
105 }
106
107 if( m_handle != 0 )
108 {
109 UpdateClasses();
110 RegisterModules();
111 }
112 else
113 {
114 // Flag us for deletion
115 --m_linkcount;
116 }
117 }
118
119 wxPluginLibrary::~wxPluginLibrary()
120 {
121 if( m_handle != 0 )
122 {
123 UnregisterModules();
124 RestoreClasses();
125 }
126 }
127
128 wxPluginLibrary *wxPluginLibrary::RefLib()
129 {
130 wxCHECK_MSG( m_linkcount > 0, NULL,
131 wxT("Library had been already deleted!") );
132
133 ++m_linkcount;
134 return this;
135 }
136
137 bool wxPluginLibrary::UnrefLib()
138 {
139 wxASSERT_MSG( m_objcount == 0,
140 wxT("Library unloaded before all objects were destroyed") );
141
142 if ( m_linkcount == 0 || --m_linkcount == 0 )
143 {
144 delete this;
145 return true;
146 }
147
148 return false;
149 }
150
151 // ------------------------
152 // Private methods
153 // ------------------------
154
155 void wxPluginLibrary::UpdateClasses()
156 {
157 if ( !m_ourFirst )
158 return;
159
160 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
161 {
162 if( info->GetClassName() )
163 {
164 // Hash all the class names into a local table too so
165 // we can quickly find the entry they correspond to.
166 (*ms_classes)[info->GetClassName()] = this;
167 }
168
169 if ( info == m_ourLast )
170 break;
171 }
172 }
173
174 void wxPluginLibrary::RestoreClasses()
175 {
176 // Check if there is a need to restore classes.
177 if (!ms_classes)
178 return;
179
180 if ( !m_ourFirst )
181 return;
182
183 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
184 {
185 ms_classes->erase(ms_classes->find(info->GetClassName()));
186
187 if ( info == m_ourLast )
188 break;
189 }
190 }
191
192 void wxPluginLibrary::RegisterModules()
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
202 wxASSERT_MSG( m_linkcount == 1,
203 wxT("RegisterModules should only be called for the first load") );
204
205 if ( m_ourFirst )
206 {
207 for ( const wxClassInfo *info = m_ourFirst; ; info = info->GetNext() )
208 {
209 if( info->IsKindOf(wxCLASSINFO(wxModule)) )
210 {
211 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
212
213 wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
214
215 m_wxmodules.push_back(m);
216 wxModule::RegisterModule(m);
217 }
218
219 if ( info == m_ourLast )
220 break;
221 }
222 }
223
224 // FIXME: Likewise this is (well was) very similar to InitializeModules()
225
226 for ( wxModuleList::iterator it = m_wxmodules.begin();
227 it != m_wxmodules.end();
228 ++it)
229 {
230 if( !(*it)->Init() )
231 {
232 wxLogDebug(wxT("wxModule::Init() failed for wxPluginLibrary"));
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
241 wxModuleList::iterator oldNode = m_wxmodules.end();
242 do {
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() );
249
250 --m_linkcount; // Flag us for deletion
251 break;
252 }
253 }
254 }
255
256 void wxPluginLibrary::UnregisterModules()
257 {
258 wxModuleList::iterator it;
259
260 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
261 (*it)->Exit();
262
263 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
264 wxModule::UnregisterModule( *it );
265
266 // NB: content of the list was deleted by UnregisterModule calls above:
267 m_wxmodules.clear();
268 }
269
270
271 // ---------------------------------------------------------------------------
272 // wxPluginManager
273 // ---------------------------------------------------------------------------
274
275 wxDLManifest* wxPluginManager::ms_manifest = NULL;
276
277 // ------------------------
278 // Static accessors
279 // ------------------------
280
281 wxPluginLibrary *
282 wxPluginManager::LoadLibrary(const wxString &libname, int flags)
283 {
284 wxString realname(libname);
285
286 if( !(flags & wxDL_VERBATIM) )
287 realname += wxDynamicLibrary::GetDllExt();
288
289 wxPluginLibrary *entry;
290
291 if ( flags & wxDL_NOSHARE )
292 {
293 entry = NULL;
294 }
295 else
296 {
297 entry = FindByName(realname);
298 }
299
300 if ( entry )
301 {
302 wxLogTrace(wxT("dll"),
303 wxT("LoadLibrary(%s): already loaded."), realname.c_str());
304
305 entry->RefLib();
306 }
307 else
308 {
309 entry = new wxPluginLibrary( libname, flags );
310
311 if ( entry->IsLoaded() )
312 {
313 (*ms_manifest)[realname] = entry;
314
315 wxLogTrace(wxT("dll"),
316 wxT("LoadLibrary(%s): loaded ok."), realname.c_str());
317
318 }
319 else
320 {
321 wxLogTrace(wxT("dll"),
322 wxT("LoadLibrary(%s): failed to load."), realname.c_str());
323
324 // we have created entry just above
325 if ( !entry->UnrefLib() )
326 {
327 // ... so UnrefLib() is supposed to delete it
328 wxFAIL_MSG( wxT("Currently linked library is not loaded?") );
329 }
330
331 entry = NULL;
332 }
333 }
334
335 return entry;
336 }
337
338 bool wxPluginManager::UnloadLibrary(const wxString& libname)
339 {
340 wxString realname = libname;
341
342 wxPluginLibrary *entry = FindByName(realname);
343
344 if ( !entry )
345 {
346 realname += wxDynamicLibrary::GetDllExt();
347
348 entry = FindByName(realname);
349 }
350
351 if ( !entry )
352 {
353 wxLogDebug(wxT("Attempt to unload library '%s' which is not loaded."),
354 libname.c_str());
355
356 return false;
357 }
358
359 wxLogTrace(wxT("dll"), wxT("UnloadLibrary(%s)"), realname.c_str());
360
361 if ( !entry->UnrefLib() )
362 {
363 // not really unloaded yet
364 return false;
365 }
366
367 ms_manifest->erase(ms_manifest->find(realname));
368
369 return true;
370 }
371
372 // ------------------------
373 // Class implementation
374 // ------------------------
375
376 bool wxPluginManager::Load(const wxString &libname, int flags)
377 {
378 m_entry = wxPluginManager::LoadLibrary(libname, flags);
379
380 return IsLoaded();
381 }
382
383 void wxPluginManager::Unload()
384 {
385 wxCHECK_RET( m_entry, wxT("unloading an invalid wxPluginManager?") );
386
387 for ( wxDLManifest::iterator i = ms_manifest->begin();
388 i != ms_manifest->end();
389 ++i )
390 {
391 if ( i->second == m_entry )
392 {
393 ms_manifest->erase(i);
394 break;
395 }
396 }
397
398 m_entry->UnrefLib();
399
400 m_entry = NULL;
401 }
402
403 #endif // wxUSE_DYNAMIC_LOADER