Audacity  3.2.0
ModuleManager.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ModuleManager.cpp
6 
7  Dominic Mazzoni
8  James Crook
9 
10 
11 *******************************************************************//*******************************************************************/
20 
21 #include "ModuleManager.h"
22 #include "ModuleInterface.h"
23 
24 #include "BasicUI.h"
25 
26 #include <wx/dynlib.h>
27 #include <wx/log.h>
28 #include <wx/string.h>
29 #include <wx/filename.h>
30 
31 #include "FileNames.h"
32 #include "MemoryX.h"
33 
34 #include "PluginInterface.h"
35 
36 #ifdef EXPERIMENTAL_MODULE_PREFS
37 #include "Prefs.h"
38 #include "ModuleSettings.h"
39 #endif
40 
41 #define initFnName "ExtensionModuleInit"
42 #define versionFnName "GetVersionString"
43 
44 //typedef wxString (*tVersionFn)();
45 typedef wxChar * (*tVersionFn)();
46 
48  : mName{ name }
49 {
50  mLib = std::make_unique<wxDynamicLibrary>();
51  mDispatch = NULL;
52 }
53 
55 {
56 }
57 
59 {
60  using namespace BasicUI;
61  return ShowMessageBox(msg,
62  MessageBoxOptions{}.Caption(XO("Module Unsuitable")));
63 }
64 
65 void Module::ShowLoadFailureError(const wxString &Error)
66 {
67  auto ShortName = wxFileName(mName).GetName();
69  XO("Unable to load the \"%s\" module.\n\nError: %s")
70  .Format(ShortName, Error));
71  wxLogMessage(wxT("Unable to load the module \"%s\". Error: %s"), mName, Error);
72 }
73 
74 bool Module::Load(wxString &deferredErrorMessage)
75 {
76  deferredErrorMessage.clear();
77  // Will this ever happen???
78  if (mLib->IsLoaded()) {
79  if (mDispatch) {
80  return true;
81  }
82 
83  // Any messages should have already been generated the first time it was loaded.
84  return false;
85  }
86 
87  auto ShortName = wxFileName(mName).GetName();
88 
89  if (!mLib->Load(mName, wxDL_NOW | wxDL_QUIET | wxDL_GLOBAL)) {
90  // For this failure path, only, there is a possiblity of retrial
91  // after some other dependency of this module is loaded. So the
92  // error is not immediately reported.
93  deferredErrorMessage = wxString(wxSysErrorMsg());
94  return false;
95  }
96 
97  // Check version string matches. (For now, they must match exactly)
98  tVersionFn versionFn = (tVersionFn)(mLib->GetSymbol(wxT(versionFnName)));
99  if (versionFn == NULL){
100  DoMessageBox(
101  XO("The module \"%s\" does not provide a version string.\n\nIt will not be loaded.")
102  .Format( ShortName));
103  wxLogMessage(wxT("The module \"%s\" does not provide a version string. It will not be loaded."), mName);
104  mLib->Unload();
105  return false;
106  }
107 
108  wxString moduleVersion = versionFn();
109  if( moduleVersion != AUDACITY_VERSION_STRING) {
110  DoMessageBox(
111  XO("The module \"%s\" is matched with Audacity version \"%s\".\n\nIt will not be loaded.")
112  .Format(ShortName, moduleVersion));
113  wxLogMessage(wxT("The module \"%s\" is matched with Audacity version \"%s\". It will not be loaded."), mName, moduleVersion);
114  mLib->Unload();
115  return false;
116  }
117 
118  mDispatch = (fnModuleDispatch) mLib->GetSymbol(wxT(ModuleDispatchName));
119  if (!mDispatch) {
120  // Module does not provide a dispatch function.
121  return true;
122  }
123 
124  // However if we do have it and it does not work,
125  // then the module is bad.
126  bool res = ((mDispatch(ModuleInitialize))!=0);
127  if (res) {
128  return true;
129  }
130 
131  mDispatch = NULL;
132 
133  DoMessageBox(
134  XO("The module \"%s\" failed to initialize.\n\nIt will not be loaded.")
135  .Format(ShortName));
136  wxLogMessage(wxT("The module \"%s\" failed to initialize.\nIt will not be loaded."), mName);
137  mLib->Unload();
138 
139  return false;
140 }
141 
142 // This isn't yet used?
144 {
145  if (mLib->IsLoaded()) {
146  if (mDispatch)
148  }
149 
150  mLib->Unload();
151 }
152 
154 {
155  if (mLib->IsLoaded())
156  if( mDispatch != NULL )
157  return mDispatch(type);
158 
159  return 0;
160 }
161 
162 void * Module::GetSymbol(const wxString &name)
163 {
164  return mLib->GetSymbol(name);
165 }
166 
167 // ============================================================================
168 //
169 // ModuleManager
170 //
171 // ============================================================================
172 
173 // The one and only ModuleManager
174 std::unique_ptr<ModuleManager> ModuleManager::mInstance{};
175 
176 // Provide builtin modules a means to identify themselves
177 using BuiltinModuleList = std::vector<ModuleMain>;
178 namespace {
180  {
181  static BuiltinModuleList theList;
182  return theList;
183  }
184 }
185 
186 void RegisterProvider(ModuleMain moduleMain)
187 {
188  auto &list = builtinModuleList();
189  if ( moduleMain )
190  list.push_back(moduleMain);
191 
192  return;
193 }
194 
196 {
197  auto &list = builtinModuleList();
198  auto end = list.end(), iter = std::find(list.begin(), end, moduleMain);
199  if (iter != end)
200  list.erase(iter);
201 }
202 
203 // ----------------------------------------------------------------------------
204 // Creation/Destruction
205 // ----------------------------------------------------------------------------
206 
208 {
209 }
210 
212 {
213  mDynModules.clear();
214  builtinModuleList().clear();
215 }
216 
217 // static
219 {
220  const auto &audacityPathList = FileNames::AudacityPathList();
221  FilePaths pathList;
222  wxString pathVar;
223 
224  // Code from LoadLadspa that might be useful in load modules.
225  pathVar = wxGetenv(wxT("AUDACITY_MODULES_PATH"));
226  if (!pathVar.empty())
227  FileNames::AddMultiPathsToPathList(pathVar, pathList);
228 
229  for (const auto &path : audacityPathList) {
230  wxString prefix = path + wxFILE_SEP_PATH;
231  FileNames::AddUniquePathToPathList(prefix + wxT("modules"),
232  pathList);
233  if (files.size()) {
234  break;
235  }
236  }
237 
238  #if defined(__WXMSW__)
239  FileNames::FindFilesInPathList(wxT("*.dll"), pathList, files);
240  #else
241  FileNames::FindFilesInPathList(wxT("*.so"), pathList, files);
242  #endif
243 }
244 
246  const FilePaths &files, FilePaths &decided, DelayedErrors &errors)
247 {
248  FilePaths checked;
249  wxString saveOldCWD = ::wxGetCwd();
250  auto cleanup = finally([&]{ ::wxSetWorkingDirectory(saveOldCWD); });
251  for (const auto &file : files) {
252  // As a courtesy to some modules that might be bridges to
253  // open other modules, we set the current working
254  // directory to be the module's directory.
255  auto prefix = ::wxPathOnly(file);
256  ::wxSetWorkingDirectory(prefix);
257 
258  // Only process the first module encountered in the
259  // defined search sequence.
260  wxString ShortName = wxFileName( file ).GetName();
261  if( checked.Index( ShortName, false ) != wxNOT_FOUND )
262  continue;
263  checked.Add( ShortName );
264 
265  // Skip if a previous pass through this function decided it already
266  if( decided.Index( ShortName, false ) != wxNOT_FOUND )
267  continue;
268 
269 #ifdef EXPERIMENTAL_MODULE_PREFS
270  int iModuleStatus = ModuleSettings::GetModuleStatus( file );
271  if( iModuleStatus == kModuleDisabled )
272  continue;
273  if( iModuleStatus == kModuleFailed )
274  continue;
275  // New module? You have to go and explicitly enable it.
276  if( iModuleStatus == kModuleNew ){
277  // To ensure it is noted in config file and so
278  // appears on modules page.
280  continue;
281  }
282 
283  if( iModuleStatus == kModuleAsk )
284 #endif
285  // JKC: I don't like prompting for the plug-ins individually
286  // I think it would be better to show the module prefs page,
287  // and let the user decide for each one.
288  {
289  auto msg = XO("Module \"%s\" found.").Format( ShortName );
290  msg += XO("\n\nOnly use modules from trusted sources");
291  const TranslatableStrings buttons{
292  XO("Yes"), XO("No"),
293  }; // could add a button here for 'yes and remember that', and put it into the cfg file. Needs more thought.
294  int action = BasicUI::ShowMultiDialog(msg,
295  XO("Audacity Module Loader"),
296  buttons,
297  "",
298  XO("Try and load this module?"),
299  false);
300 #ifdef EXPERIMENTAL_MODULE_PREFS
301  // If we're not prompting always, accept the answer permanently
302  if( iModuleStatus == kModuleNew ){
303  iModuleStatus = (action==1)?kModuleDisabled : kModuleEnabled;
304  ModuleSettings::SetModuleStatus( file, iModuleStatus );
305  }
306 #endif
307  if(action == 1){ // "No"
308  decided.Add( ShortName );
309  continue;
310  }
311  }
312 #ifdef EXPERIMENTAL_MODULE_PREFS
313  // Before attempting to load, we set the state to bad.
314  // That way, if we crash, we won't try again.
316 #endif
317 
318  wxString Error;
319  auto umodule = std::make_unique<Module>(file);
320  if (umodule->Load(Error)) // it will get rejected if there are version problems
321  {
322  decided.Add( ShortName );
323  auto module = umodule.get();
324 
325  if (!module->HasDispatch())
326  {
327  auto ShortName = wxFileName(file).GetName();
328  DoMessageBox(
329  XO("The module \"%s\" does not provide any of the required functions.\n\nIt will not be loaded.")
330  .Format(ShortName));
331  wxLogMessage(wxT("The module \"%s\" does not provide any of the required functions. It will not be loaded."), file);
332  module->Unload();
333  }
334  else
335  {
336  Get().mModules.push_back(std::move(umodule));
337 
338 #ifdef EXPERIMENTAL_MODULE_PREFS
339  // Loaded successfully, restore the status.
340  ModuleSettings::SetModuleStatus(file, iModuleStatus);
341 #endif
342  }
343  }
344  else if (!Error.empty()) {
345  // Module is not yet decided in this pass.
346  // Maybe it depends on another which has not yet been loaded.
347  // But don't take the kModuleAsk path again in a later pass.
349  errors.emplace_back( std::move( umodule ), Error );
350  }
351  }
352 }
353 
354 // static
356 {
357  FilePaths files;
358  FindModules(files);
359 
360  FilePaths decided;
361  DelayedErrors errors;
362  size_t numDecided = 0;
363 
364  // Multiple passes give modules multiple chances to load in case they
365  // depend on some other module not yet loaded
366  do {
367  numDecided = decided.size();
368  errors.clear();
369  TryLoadModules(files, decided, errors);
370  }
371  while ( errors.size() && numDecided < decided.size() );
372 
373  // Only now show accumulated errors of modules that failed to load
374  for ( const auto &pair : errors ) {
375  auto &pModule = pair.first;
376  pModule->ShowLoadFailureError(pair.second);
377  ModuleSettings::SetModuleStatus( pModule->GetName(), kModuleFailed );
378  }
379 }
380 
381 // static
383 {
384  for (const auto &module: mModules) {
385  module->Dispatch(type);
386  }
387  return 0;
388 }
389 
390 // ============================================================================
391 //
392 // Return reference to singleton
393 //
394 // (Thread-safe...no active threading during construction or after destruction)
395 // ============================================================================
397 {
398  if (!mInstance)
399  {
401  }
402 
403  return *mInstance;
404 }
405 
407 {
408  return L"Module";
409 }
410 
412 {
413  return wxString::Format(wxT("%s_%s_%s_%s_%s"),
415  wxEmptyString,
416  module->GetVendor().Internal(),
417  module->GetSymbol().Internal(),
418  module->GetPath());
419 }
420 
422 {
424 
425 // The commented out code loads modules whether or not they are enabled.
426 // none of our modules is a 'provider' of effects, so this code commented out.
427 #if 0
428  FilePaths provList;
429  FilePaths pathList;
430 
431  // Code from LoadLadspa that might be useful in load modules.
432  wxString pathVar = wxString::FromUTF8(getenv("AUDACITY_MODULES_PATH"));
433 
434  if (!pathVar.empty())
435  {
436  FileNames::AddMultiPathsToPathList(pathVar, pathList);
437  }
438  else
439  {
441  }
442 
443 #if defined(__WXMSW__)
444  FileNames::FindFilesInPathList(wxT("*.dll"), pathList, provList);
445 #elif defined(__WXMAC__)
446  FileNames::FindFilesInPathList(wxT("*.dylib"), pathList, provList);
447 #else
448  FileNames::FindFilesInPathList(wxT("*.so"), pathList, provList);
449 #endif
450 
451  for ( const auto &path : provList )
452  LoadModule(path);
453 #endif
454 
455  return true;
456 }
457 
459 {
460  for (auto moduleMain : builtinModuleList())
461  {
462  ModuleInterfaceHandle module {
463  moduleMain(), ModuleInterfaceDeleter{}
464  };
465 
466  if (module && module->Initialize())
467  {
468  // Register the provider
469  ModuleInterface *pInterface = module.get();
470  auto id = GetID(pInterface);
471 
472  // Need to remember it
473  mDynModules[id] = std::move(module);
474  }
475  else
476  {
477  // Don't leak! Destructor of module does that.
478  }
479  }
480 }
481 
483 {
484  if (pInterface)
485  {
486  pInterface->Terminate();
487  std::unique_ptr < ModuleInterface > { pInterface }; // DELETE it
488  }
489 }
490 
491 bool ModuleManager::RegisterEffectPlugin(const PluginID & providerID, const PluginPath & path, TranslatableString &errMsg)
492 {
493  errMsg = {};
494  if (mDynModules.find(providerID) == mDynModules.end())
495  {
496  return false;
497  }
498 
499  auto nFound = mDynModules[providerID]->DiscoverPluginsAtPath(path, errMsg, PluginManagerInterface::DefaultRegistrationCallback);
500 
501  return nFound > 0;
502 }
503 
505  const PluginPath & path)
506 {
507  if (path.empty() && mDynModules.find(providerID) != mDynModules.end())
508  {
509  return mDynModules[providerID].get();
510  }
511 
512  return nullptr;
513 }
514 
515 std::unique_ptr<ComponentInterface> ModuleManager::CreateInstance(
516  const PluginID & providerID, const PluginPath & path)
517 {
518  if (auto iter = mDynModules.find(providerID);
519  iter == mDynModules.end())
520  return nullptr;
521  else
522  return iter->second->CreateInstance(path);
523 }
524 
525 bool ModuleManager::IsProviderValid(const PluginID & WXUNUSED(providerID),
526  const PluginPath & path)
527 {
528  // Builtin modules do not have a path
529  if (path.empty())
530  {
531  return true;
532  }
533 
534  wxFileName lib(path);
535  if (lib.FileExists() || lib.DirExists())
536  {
537  return true;
538  }
539 
540  return false;
541 }
542 
543 bool ModuleManager::IsPluginValid(const PluginID & providerID,
544  const PluginPath & path,
545  bool bFast)
546 {
547  if (mDynModules.find(providerID) == mDynModules.end())
548  {
549  return false;
550  }
551 
552  return mDynModules[providerID]->IsPluginValid(path, bFast);
553 }
ModuleManager::TryLoadModules
static void TryLoadModules(const FilePaths &files, FilePaths &decided, DelayedErrors &errors)
Definition: ModuleManager.cpp:245
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
ModuleManager::mDynModules
ModuleMap mDynModules
Definition: ModuleManager.h:135
ModuleManager::~ModuleManager
~ModuleManager()
Definition: ModuleManager.cpp:211
BasicUI::MessageBoxOptions
Definition: BasicUI.h:91
fnModuleDispatch
int(* fnModuleDispatch)(ModuleDispatchTypes type)
Definition: ModuleManager.h:39
Module::mName
const FilePath mName
Definition: ModuleManager.h:56
ModuleSettings::GetModuleStatus
MODULE_MANAGER_API int GetModuleStatus(const FilePath &fname)
Definition: ModuleSettings.cpp:28
ModuleManager::mModules
std::vector< std::unique_ptr< Module > > mModules
Definition: ModuleManager.h:139
ComponentInterface::GetSymbol
virtual ComponentInterfaceSymbol GetSymbol()=0
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: TranslatableString.h:295
Module::GetSymbol
void * GetSymbol(const wxString &name)
Definition: ModuleManager.cpp:162
BasicUI::ShowMessageBox
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:256
DoMessageBox
static BasicUI::MessageBoxResult DoMessageBox(const TranslatableString &msg)
Definition: ModuleManager.cpp:58
kModuleEnabled
@ kModuleEnabled
Definition: ModuleSettings.h:18
ModuleManager.h
ModuleManager::GetID
static PluginID GetID(ModuleInterface *module)
Definition: ModuleManager.cpp:411
ModuleSettings.h
PluginPath
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
Module::~Module
virtual ~Module()
Definition: ModuleManager.cpp:54
kModuleFailed
@ kModuleFailed
Definition: ModuleSettings.h:20
Format
Abstract base class used in importing a file.
ModuleManager::InitializeBuiltins
void InitializeBuiltins()
Definition: ModuleManager.cpp:458
Module::mDispatch
fnModuleDispatch mDispatch
Definition: ModuleManager.h:58
Module::ShowLoadFailureError
void ShowLoadFailureError(const wxString &Error)
Definition: ModuleManager.cpp:65
anonymous_namespace{ModuleManager.cpp}::builtinModuleList
BuiltinModuleList & builtinModuleList()
Definition: ModuleManager.cpp:179
BasicUI::ShowMultiDialog
int ShowMultiDialog(const TranslatableString &message, const TranslatableString &title, const TranslatableStrings &buttons, const ManualPageID &helpPage, const TranslatableString &boxMsg, bool log)
Display a dialog with radio buttons.
Definition: BasicUI.h:309
ModuleInterface.h
ModuleManager::ModuleManager
ModuleManager()
Definition: ModuleManager.cpp:207
XO
#define XO(s)
Definition: Internat.h:31
ModuleManager::RegisterEffectPlugin
bool RegisterEffectPlugin(const PluginID &provider, const PluginPath &path, TranslatableString &errMsg)
Definition: ModuleManager.cpp:491
ModuleManager::CreateInstance
std::unique_ptr< ComponentInterface > CreateInstance(const PluginID &provider, const PluginPath &path)
Definition: ModuleManager.cpp:515
ModuleManager::IsPluginValid
bool IsPluginValid(const PluginID &provider, const PluginPath &path, bool bFast)
Definition: ModuleManager.cpp:543
BasicUI::MessageBoxResult
MessageBoxResult
Definition: BasicUI.h:129
RegisterProvider
void RegisterProvider(ModuleMain moduleMain)
Definition: ModuleManager.cpp:186
wxArrayStringEx
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Definition: wxArrayStringEx.h:18
ModuleManager::DiscoverProviders
bool DiscoverProviders()
Definition: ModuleManager.cpp:421
tVersionFn
wxChar *(* tVersionFn)()
Definition: ModuleManager.cpp:45
FileNames::AddUniquePathToPathList
FILES_API void AddUniquePathToPathList(const FilePath &path, FilePaths &pathList)
ComponentInterface::GetVendor
virtual VendorSymbol GetVendor()=0
ModuleInterface
Definition: ModuleInterface.h:75
ModuleManager::GetPluginTypeString
static wxString GetPluginTypeString()
Definition: ModuleManager.cpp:406
ModuleManager::DelayedErrors
std::vector< std::pair< std::unique_ptr< Module >, wxString > > DelayedErrors
Definition: ModuleManager.h:91
ModuleManager::Dispatch
int Dispatch(ModuleDispatchTypes type)
Definition: ModuleManager.cpp:382
ModuleManager::IsProviderValid
bool IsProviderValid(const PluginID &provider, const PluginPath &path)
Definition: ModuleManager.cpp:525
ModuleManager
Definition: ModuleManager.h:73
FilePath
wxString FilePath
Definition: Project.h:20
ComponentInterface::GetPath
virtual PluginPath GetPath()=0
Module::Unload
void Unload()
Definition: ModuleManager.cpp:143
PluginID
wxString PluginID
Definition: EffectManager.h:31
ModuleManager::Get
static ModuleManager & Get()
Definition: ModuleManager.cpp:396
name
const TranslatableString name
Definition: Distortion.cpp:98
BuiltinModuleList
std::vector< ModuleMain > BuiltinModuleList
Definition: ModuleManager.cpp:177
Module::Module
Module(const FilePath &name)
Definition: ModuleManager.cpp:47
kModuleNew
@ kModuleNew
Definition: ModuleSettings.h:21
FileNames::ModulesDir
FILES_API FilePath ModulesDir()
FileNames::FindFilesInPathList
FILES_API void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &results, int flags=wxDIR_FILES)
BasicUI.h
Toolkit-neutral facade for basic user interface services.
ModuleDispatchTypes
ModuleDispatchTypes
Definition: ModuleConstants.h:27
FileNames::AddMultiPathsToPathList
FILES_API void AddMultiPathsToPathList(const wxString &multiPathString, FilePaths &pathList)
UnregisterProvider
void UnregisterProvider(ModuleMain moduleMain)
Definition: ModuleManager.cpp:195
id
int id
Definition: WaveTrackControls.cpp:577
Module::mLib
std::unique_ptr< wxDynamicLibrary > mLib
Definition: ModuleManager.h:57
PluginManagerInterface::DefaultRegistrationCallback
static const PluginID & DefaultRegistrationCallback(ModuleInterface *provider, ComponentInterface *ident)
Definition: PluginManager.cpp:328
ModuleTerminate
@ ModuleTerminate
Definition: ModuleConstants.h:29
ModuleMain
ModuleInterface *(*)() ModuleMain
Definition: ModuleManager.h:145
BasicUI
Definition: Effect.h:47
BasicUI::MessageBoxOptions::Caption
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:98
FileNames::AudacityPathList
FILES_API const FilePaths & AudacityPathList()
A list of directories that should be searched for Audacity files (plug-ins, help files,...
ModuleManager::FindModules
static void FindModules(FilePaths &files)
Definition: ModuleManager.cpp:218
ModuleSettings::SetModuleStatus
MODULE_MANAGER_API void SetModuleStatus(const FilePath &fname, int iStatus)
Definition: ModuleSettings.cpp:75
MemoryX.h
ModuleManager::mInstance
static std::unique_ptr< ModuleManager > mInstance
Definition: ModuleManager.h:130
versionFnName
#define versionFnName
Definition: ModuleManager.cpp:42
ModuleManager::Initialize
void Initialize()
Definition: ModuleManager.cpp:355
ModuleInterfaceDeleter::operator()
void operator()(ModuleInterface *pInterface) const
Definition: ModuleManager.cpp:482
FileNames.h
Module::Dispatch
int Dispatch(ModuleDispatchTypes type)
Definition: ModuleManager.cpp:153
ModuleInterfaceHandle
std::unique_ptr< ModuleInterface, ModuleInterfaceDeleter > ModuleInterfaceHandle
Definition: ModuleManager.h:67
ComponentInterfaceSymbol::Internal
const wxString & Internal() const
Definition: ComponentInterfaceSymbol.h:55
kModuleDisabled
@ kModuleDisabled
Definition: ModuleSettings.h:17
PluginInterface.h
Prefs.h
ModuleDispatchName
#define ModuleDispatchName
Definition: ModuleConstants.h:16
BasicUI::Icon::Error
@ Error
ModuleManager::CreateProviderInstance
ModuleInterface * CreateProviderInstance(const PluginID &provider, const PluginPath &path)
Definition: ModuleManager.cpp:504
safenew
#define safenew
Definition: MemoryX.h:10
ModuleInterfaceDeleter
Definition: ModuleManager.h:61
ModuleInterface::Terminate
virtual void Terminate()=0
kModuleAsk
@ kModuleAsk
Definition: ModuleSettings.h:19
Module::Load
bool Load(wxString &deferredErrorMessage)
Definition: ModuleManager.cpp:74
ModuleInitialize
@ ModuleInitialize
Definition: ModuleConstants.h:28