Use wxDELETE() and wxDELETEA() when possible.
[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 m_before = wxClassInfo::GetFirst();
80 Load( libname, flags );
81 m_after = wxClassInfo::GetFirst();
82
83 if( m_handle != 0 )
84 {
85 UpdateClasses();
86 RegisterModules();
87 }
88 else
89 {
90 // Flag us for deletion
91 --m_linkcount;
92 }
93 }
94
95 wxPluginLibrary::~wxPluginLibrary()
96 {
97 if( m_handle != 0 )
98 {
99 UnregisterModules();
100 RestoreClasses();
101 }
102 }
103
104 wxPluginLibrary *wxPluginLibrary::RefLib()
105 {
106 wxCHECK_MSG( m_linkcount > 0, NULL,
107 wxT("Library had been already deleted!") );
108
109 ++m_linkcount;
110 return this;
111 }
112
113 bool wxPluginLibrary::UnrefLib()
114 {
115 wxASSERT_MSG( m_objcount == 0,
116 wxT("Library unloaded before all objects were destroyed") );
117
118 if ( m_linkcount == 0 || --m_linkcount == 0 )
119 {
120 delete this;
121 return true;
122 }
123
124 return false;
125 }
126
127 // ------------------------
128 // Private methods
129 // ------------------------
130
131 void wxPluginLibrary::UpdateClasses()
132 {
133 for (const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
134 {
135 if( info->GetClassName() )
136 {
137 // Hash all the class names into a local table too so
138 // we can quickly find the entry they correspond to.
139 (*ms_classes)[info->GetClassName()] = this;
140 }
141 }
142 }
143
144 void wxPluginLibrary::RestoreClasses()
145 {
146 // Check if there is a need to restore classes.
147 if (!ms_classes)
148 return;
149
150 for(const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
151 {
152 ms_classes->erase(ms_classes->find(info->GetClassName()));
153 }
154 }
155
156 void wxPluginLibrary::RegisterModules()
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
166 wxASSERT_MSG( m_linkcount == 1,
167 wxT("RegisterModules should only be called for the first load") );
168
169 for ( const wxClassInfo *info = m_after; info != m_before; info = info->GetNext())
170 {
171 if( info->IsKindOf(CLASSINFO(wxModule)) )
172 {
173 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
174
175 wxASSERT_MSG( m, wxT("wxDynamicCast of wxModule failed") );
176
177 m_wxmodules.push_back(m);
178 wxModule::RegisterModule(m);
179 }
180 }
181
182 // FIXME: Likewise this is (well was) very similar to InitializeModules()
183
184 for ( wxModuleList::iterator it = m_wxmodules.begin();
185 it != m_wxmodules.end();
186 ++it)
187 {
188 if( !(*it)->Init() )
189 {
190 wxLogDebug(wxT("wxModule::Init() failed for wxPluginLibrary"));
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
199 wxModuleList::iterator oldNode = m_wxmodules.end();
200 do {
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() );
207
208 --m_linkcount; // Flag us for deletion
209 break;
210 }
211 }
212 }
213
214 void wxPluginLibrary::UnregisterModules()
215 {
216 wxModuleList::iterator it;
217
218 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
219 (*it)->Exit();
220
221 for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it )
222 wxModule::UnregisterModule( *it );
223
224 // NB: content of the list was deleted by UnregisterModule calls above:
225 m_wxmodules.clear();
226 }
227
228
229 // ---------------------------------------------------------------------------
230 // wxPluginManager
231 // ---------------------------------------------------------------------------
232
233 wxDLManifest* wxPluginManager::ms_manifest = NULL;
234
235 // ------------------------
236 // Static accessors
237 // ------------------------
238
239 wxPluginLibrary *
240 wxPluginManager::LoadLibrary(const wxString &libname, int flags)
241 {
242 wxString realname(libname);
243
244 if( !(flags & wxDL_VERBATIM) )
245 realname += wxDynamicLibrary::GetDllExt();
246
247 wxPluginLibrary *entry;
248
249 if ( flags & wxDL_NOSHARE )
250 {
251 entry = NULL;
252 }
253 else
254 {
255 entry = FindByName(realname);
256 }
257
258 if ( entry )
259 {
260 wxLogTrace(wxT("dll"),
261 wxT("LoadLibrary(%s): already loaded."), realname.c_str());
262
263 entry->RefLib();
264 }
265 else
266 {
267 entry = new wxPluginLibrary( libname, flags );
268
269 if ( entry->IsLoaded() )
270 {
271 (*ms_manifest)[realname] = entry;
272
273 wxLogTrace(wxT("dll"),
274 wxT("LoadLibrary(%s): loaded ok."), realname.c_str());
275
276 }
277 else
278 {
279 wxLogTrace(wxT("dll"),
280 wxT("LoadLibrary(%s): failed to load."), realname.c_str());
281
282 // we have created entry just above
283 if ( !entry->UnrefLib() )
284 {
285 // ... so UnrefLib() is supposed to delete it
286 wxFAIL_MSG( wxT("Currently linked library is not loaded?") );
287 }
288
289 entry = NULL;
290 }
291 }
292
293 return entry;
294 }
295
296 bool wxPluginManager::UnloadLibrary(const wxString& libname)
297 {
298 wxString realname = libname;
299
300 wxPluginLibrary *entry = FindByName(realname);
301
302 if ( !entry )
303 {
304 realname += wxDynamicLibrary::GetDllExt();
305
306 entry = FindByName(realname);
307 }
308
309 if ( !entry )
310 {
311 wxLogDebug(wxT("Attempt to unload library '%s' which is not loaded."),
312 libname.c_str());
313
314 return false;
315 }
316
317 wxLogTrace(wxT("dll"), wxT("UnloadLibrary(%s)"), realname.c_str());
318
319 if ( !entry->UnrefLib() )
320 {
321 // not really unloaded yet
322 return false;
323 }
324
325 ms_manifest->erase(ms_manifest->find(realname));
326
327 return true;
328 }
329
330 // ------------------------
331 // Class implementation
332 // ------------------------
333
334 bool wxPluginManager::Load(const wxString &libname, int flags)
335 {
336 m_entry = wxPluginManager::LoadLibrary(libname, flags);
337
338 return IsLoaded();
339 }
340
341 void wxPluginManager::Unload()
342 {
343 wxCHECK_RET( m_entry, wxT("unloading an invalid wxPluginManager?") );
344
345 for ( wxDLManifest::iterator i = ms_manifest->begin();
346 i != ms_manifest->end();
347 ++i )
348 {
349 if ( i->second == m_entry )
350 {
351 ms_manifest->erase(i);
352 break;
353 }
354 }
355
356 m_entry->UnrefLib();
357
358 m_entry = NULL;
359 }
360
361 #endif // wxUSE_DYNAMIC_LOADER