]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/dynload.cpp
fix memory leak in wxScreenDC, fixes #13249
[wxWidgets.git] / src / common / dynload.cpp
... / ...
CommitLineData
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
47wxDLImports* wxPluginLibrary::ms_classes = NULL;
48
49class wxPluginLibraryModule : public wxModule
50{
51public:
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
68private:
69 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule )
70};
71
72IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule)
73
74
75wxPluginLibrary::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
95wxPluginLibrary::~wxPluginLibrary()
96{
97 if( m_handle != 0 )
98 {
99 UnregisterModules();
100 RestoreClasses();
101 }
102}
103
104wxPluginLibrary *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
113bool 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
131void 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
144void 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
156void 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
214void 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
233wxDLManifest* wxPluginManager::ms_manifest = NULL;
234
235// ------------------------
236// Static accessors
237// ------------------------
238
239wxPluginLibrary *
240wxPluginManager::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
296bool 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
334bool wxPluginManager::Load(const wxString &libname, int flags)
335{
336 m_entry = wxPluginManager::LoadLibrary(libname, flags);
337
338 return IsLoaded();
339}
340
341void 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