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