DLL Debug
configuration DLL Debug
and DLL Release
instead of Debug
and Release
. In addition, it is imperative that in the settings of all projects included in the wxWidgets distribution kit, the Multi-Threaded Debug DLL Multi-Threaded DLL
values ​​are specified in the C/C++ -> Code Generation -> Runtime Library
parameter. It is with “DLL” at the end. In this case, we will have wxWidgets compiled in the form of dynamic libraries and with dynamic CRT.DLL Debug
configurations, DLL Debug
and DLL Release
can be such that not all libraries will be assembled the first time. All this because of problems with specifying dependencies. If not assembled, run the assembly again. Usually 2-3 iterations are enough to get a complete set of dynamic libraries.%WXWIN%
(for Windows), which points to the folder with the wxWidgets source codes. For Linux and OS X, just configure && make && make install
.configure --enable-shared --disable-static --enable-unicode --disable-compat28 --disable-final --enable-debug
configure --enable-shared --disable-static --enable-unicode --disable-compat28 --enable-final --disable-debug
cmake_minimum_required(VERSION 2.6.0) # We will generate both Debug and Release project files at the same time # for Windows and OS X if(WIN32 OR APPLE) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) set(LIB_SUFFIX "") endif(WIN32 OR APPLE) # For Linux we will need to execute CMake twice in order to generate # Debug and Release versions of Makefiles if(UNIX AND NOT APPLE) set(LINUX ON) set(LIB_SUFFIX /${CMAKE_BUILD_TYPE}) endif(UNIX AND NOT APPLE) set(PROJECT_NAME wxModularHost) project(${PROJECT_NAME}) # If there are any additional CMake modules (eg module which searches # for OpenCV or for DirectShow libs), then CMake should start searching # for them in current folder set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) if(APPLE) set(OS_BASE_NAME Mac) set(CMAKE_OSX_SYSROOT "macosx10.6") endif(APPLE) if(LINUX) set(OS_BASE_NAME Linux) endif(LINUX) if(WIN32) set(OS_BASE_NAME Win) endif(WIN32) # Here we specify the list of wxWidgets libs which we will use in our project set(wxWidgets_USE_LIBS base core adv aui net gl xml propgrid html) # Here we specify that we need DLL version of wxWidgets libs and dynamic CRT # This is a MUST for applications with plugins. Both app and DLL plugin MUST # use the same instance of wxWidgets and the same event loop. set(BUILD_SHARED_LIBS 1) # Find wxWidgets library on current PC # You should have %WXWIN% environment variable which should point to the # directory where wxWidgets source code is placed. # wxWidgets libs MUST be compiled for both Debug and Release versions find_package(wxWidgets REQUIRED) # For some reason CMake generates wrong list of definitions. # Each item should start with /D but it does not. # We need to fix that manually set(wxWidgets_DEFINITIONS_TEMP) foreach(DEFINITION ${wxWidgets_DEFINITIONS}) if(NOT ${DEFINITION} MATCHES "/D.*") set(DEFINITION "/D${DEFINITION}") endif() set(wxWidgets_DEFINITIONS_TEMP ${wxWidgets_DEFINITIONS_TEMP} ${DEFINITION}) endforeach(${DEFINITION}) set(wxWidgets_DEFINITIONS ${wxWidgets_DEFINITIONS_TEMP}) # Here we add some definitions which prevent Visual Studio from # generating tons of warnings about unsecure function calls. # See http://msdn.microsoft.com/en-us/library/ttcz0bys.aspx if(WIN32) set(wxWidgets_DEFINITIONS ${wxWidgets_DEFINITIONS}; /D_CRT_SECURE_NO_DEPRECATE; /D_CRT_NONSTDC_NO_DEPRECATE; /D_UNICODE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4996") endif(WIN32) # Since we are going to use wxWidgets in all subrojects, # it's OK to create the variable which will contain # common preprocessor definitions. This variable will be # used in subprojects. set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS}; ${wxWidgets_DEFINITIONS}) # Variable which points to root folder of our source code set(PROJECT_ROOT_DIR ${PROJECT_SOURCE_DIR}/..) # If any ThirdParty libraries are going to be # used in our project then it would be better to put # them into separate subfolder. We will create # the variable which points to this subfolder. set(THIRD_PARTY_DIR ${PROJECT_ROOT_DIR}/ThirdParty) set(BASE_INCLUDE_DIRECTORIES ${PROJECT_ROOT_DIR}/include) # Add wxWidgets include paths to the list of # include directories for all projects. include_directories(${wxWidgets_INCLUDE_DIRS}) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D__WXDEBUG__=1" ) # Now we can include all our subprojects. # CMake will generate project files for them add_subdirectory (../wxModularHost ../../wxModularHost/${OS_BASE_NAME}${LIB_SUFFIX})
rem @echo off IF "%1" == "" GOTO NO_PARAMS IF "%1" == "x86" GOTO CMAKE_86 IF "%1" == "86" GOTO CMAKE_86 IF "%1" == "x64" GOTO CMAKE_64 IF "%1" == "64" GOTO CMAKE_64 ECHO %1 ECHO "Nothing to do" GOTO End :CMAKE_86 ECHO "Configuring for x86" cm86.bat GOTO End :CMAKE_64 ECHO "Configuring for x64" cm64.bat GOTO End :NO_PARAMS ECHO "No parameters specified" IF EXIST "%ProgramW6432%" GOTO CMAKE_64 GOTO CMAKE_86 :End
rmdir /S /Q Win mkdir Win cd Win cmake ../ -G "Visual Studio 11" cd ..
rmdir /S /Q Win mkdir Win cd Win cmake ../ -G "Visual Studio 11 Win64" cd ..
#!/bin/bash echo OS Type: $OSTYPE # ---------------------------------- # build Debug configuration makefile # ---------------------------------- echo building Debug configuration makefile echo directory "LinuxDebug" rm -dr "LinuxDebug" mkdir "LinuxDebug" cd "LinuxDebug" cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE:STRING=Debug ../ cd .. # ---------------------------------- # build Release configuration makefile # ---------------------------------- echo building Release configuration makefile echo directory "LinuxRelease" rm -dr "LinuxRelease" mkdir "LinuxRelease" cd "LinuxRelease" cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE:STRING=Release ../ cd ..
%WXWIN%\samples\minimal
folder set(SRCS MainFrame.cpp wxModularHostApp.cpp) set(HEADERS MainFrame.h wxModularHostApp.h) set(INCLUDE_DIRECTORIES ${BASE_INCLUDE_DIRECTORIES}) if(WIN32) set(SRCS ${SRCS} wxModularHost.rc) set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS}; /D_USRDLL; /DwxUSE_NO_MANIFEST=1; /D__STDC_CONSTANT_MACROS) endif(WIN32) set(LIBS ${wxWidgets_LIBRARIES}) set(EXECUTABLE_NAME wxModularHost) add_definitions(${PREPROCESSOR_DEFINITIONS}) include_directories(${INCLUDE_DIRECTORIES}) if(WIN32) set(EXECUTABLE_TYPE WIN32) endif(WIN32) if(APPLE) set(MACOSX_BUNDLE YES) set(EXECUTABLE_TYPE MACOSX_BUNDLE) endif(APPLE) if(LINUX) set(EXECUTABLE_TYPE "") endif(LINUX) set(PROJECT_FILES ${SRCS} ${HFILES}) add_executable(${EXECUTABLE_NAME} ${EXECUTABLE_TYPE} ${PROJECT_FILES}) set(EXE_DIR bin) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${EXE_DIR}${LIB_SUFFIX}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TARGET_LOCATION}) target_link_libraries(${EXECUTABLE_NAME} ${LIBS})
#ifndef _STDWX_H_ #define _STDWX_H_ #if defined(WIN32) || defined(WINDOWS) #include <windows.h> #include <winnt.h> #define PLUGIN_EXPORTED_API WXEXPORT #else #define PLUGIN_EXPORTED_API extern "C" #endif // SYSTEM INCLUDES // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "wx/wx.h" #include <wx/cmdline.h> #include <wx/config.h> #include <wx/defs.h> #include <wx/dir.h> #include <wx/display.h> #include <wx/dynlib.h> #include <wx/dynload.h> #include <wx/fileconf.h> #include <wx/filename.h> #include <wx/frame.h> #include <wx/glcanvas.h> #include <wx/hashmap.h> #include <wx/image.h> #include <wx/imaglist.h> #include <wx/intl.h> #include <wx/list.h> #include <wx/notebook.h> #include <wx/stdpaths.h> #include <wx/sstream.h> #include <wx/thread.h> #include <wx/treebook.h> #include <wx/wfstream.h> #include <wx/wupdlock.h> #include <wx/textfile.h> #include <wx/socket.h> #include <wx/mimetype.h> #include <wx/ipc.h> #endif
#include "stdwx.h"
cmake_minimum_required(VERSION 2.6.0) include(PCHSupport.cmake) ...
#include "stdwx.h"
#ifndef _DECLARATIONS_H #define _DECLARATIONS_H #if defined(__WXMSW__) #ifdef DEMO_PLUGIN_EXPORTS #define DEMO_API __declspec(dllexport) #else #define DEMO_API __declspec(dllimport) #endif #else #define DEMO_API #endif #endif // _DECLARATIONS_H
#pragma once #include "Declarations.h" class DEMO_API wxNonGuiPluginBase : public wxObject { DECLARE_ABSTRACT_CLASS(wxNonGuiPluginBase) public: wxNonGuiPluginBase(); virtual ~wxNonGuiPluginBase(); virtual int Work() = 0; }; typedef wxNonGuiPluginBase * (*CreatePlugin_function)(); typedef void (*DeletePlugin_function)(wxNonGuiPluginBase * plugin);
DEMO_API
macro, which indicates wxNonGuiPluginBase
class exported from us or imported. This is done with the help of dllexport/dllimport
(see http://msdn.microsoft.com/en-us/library/3y1sfaz2(v=vs.90).aspx) depending on the presence of the preprocessor directive DEMO_PLUGIN_EXPORTS
. When building the wxNonGuiPluginBase library, we specify DEMO_PLUGIN_EXPORTS
in the list of preprocessor directives, and when building plug-ins that depend on the wxNonGuiPluginBase library and when building the main application, we do not specify. Thus, for the wxNonGuiPluginBase project, the DEMO_API value will contain the dllexport
attribute, and for all other projects, the dllimport
value. #include "stdwx.h" #include "wxNonGuiPluginBase.h" IMPLEMENT_ABSTRACT_CLASS(wxNonGuiPluginBase, wxObject) wxNonGuiPluginBase::wxNonGuiPluginBase() { } wxNonGuiPluginBase::~wxNonGuiPluginBase() { }
set (SRCS wxNonGuiPluginBase.cpp) set (HEADERS Declarations.h wxNonGuiPluginBase.h) set(LIBRARY_NAME wxNonGuiPluginBase) if(WIN32) # Only for Windows: # we add additional preprocessor definitons set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS}; /D_USRDLL;/DDEMO_PLUGIN_EXPORTS;/D__STDC_CONSTANT_MACROS) endif(WIN32) # Add 2 files for precompiled headers set(SRCS ${SRCS} ${HEADERS} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp) # Set preprocessor definitions add_definitions(${PREPROCESSOR_DEFINITIONS}) # Set include directories include_directories(${INCLUDE_DIRECTORIES} ${BASE_INCLUDE_DIRECTORIES}) # Set library search paths link_directories(${LINK_DIRECTORIES}) # Setup the project name and assign the source files for this project add_library(${LIBRARY_NAME} SHARED ${SRCS}) #Setup the output folder set(DLL_DIR bin) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${DLL_DIR}${LIB_SUFFIX}) set_target_properties(${LIBRARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TARGET_LOCATION}) # Set additional dependencies target_link_libraries(${LIBRARY_NAME} ${wxWidgets_LIBRARIES}) # Setup precompiled headers set_precompiled_header(${LIBRARY_NAME} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp)
PREPROCESSOR_DEFINITIONS
contains the declaration of the macro DEMO_PLUGIN_EXPORTS
, which is used in the file Definitions.hwxNonGuiPluginBase
, implement the working functionality in it, and also make exported functions to create an instance of the class and to delete it. These functions will be called by the main application. #pragma once #include <wxNonGuiPluginBase.h> class SampleNonGuiPlugin : public wxNonGuiPluginBase { DECLARE_DYNAMIC_CLASS(SampleNonGuiPlugin) public: SampleNonGuiPlugin(); virtual ~SampleNonGuiPlugin(); virtual int Work(); };
#include "stdwx.h" #include "SampleNonGuiPlugin.h" IMPLEMENT_DYNAMIC_CLASS(SampleNonGuiPlugin, wxObject) SampleNonGuiPlugin::SampleNonGuiPlugin() { } SampleNonGuiPlugin::~SampleNonGuiPlugin() { } int SampleNonGuiPlugin::Work() { return 10; }
LIBRARY "SampleNonGuiPlugin" EXPORTS CreatePlugin=CreatePlugin DeletePlugin=DeletePlugin
#include "stdwx.h" #include <wxNonGuiPluginBase.h> #include "SampleNonGuiPlugin.h" PLUGIN_EXPORTED_API wxNonGuiPluginBase * CreatePlugin() { return new SampleNonGuiPlugin; } PLUGIN_EXPORTED_API void DeletePlugin(wxNonGuiPluginBase * plugin) { wxDELETE(plugin); }
set (SRCS SampleNonGuiPlugin.cpp SampleNonGuiPluginExports.cpp) set (HEADERS SampleNonGuiPlugin.h) set(LIBRARY_NAME SampleNonGuiPlugin) if(WIN32) set(SRCS ${SRCS} ${LIBRARY_NAME}.def) set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS};/D_USRDLL;/D__STDC_CONSTANT_MACROS) set(LINK_DIRECTORIES ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase/${OS_BASE_NAME}${LIB_SUFFIX}/$(ConfigurationName)) set(DEMO_LIBS wxNonGuiPluginBase.lib) endif(WIN32) set(SRCS ${SRCS} ${HEADERS} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp) add_definitions(${PREPROCESSOR_DEFINITIONS}) include_directories(${INCLUDE_DIRECTORIES} ${BASE_INCLUDE_DIRECTORIES} ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase) link_directories(${LINK_DIRECTORIES}) add_library(${LIBRARY_NAME} SHARED ${SRCS}) set(DLL_DIR bin) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${DLL_DIR}/${CMAKE_CFG_INTDIR}/plugins) set_target_properties(${LIBRARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TARGET_LOCATION}) target_link_libraries(${LIBRARY_NAME} ${DEMO_LIBS} ${wxWidgets_LIBRARIES}) add_dependencies(${LIBRARY_NAME} wxNonGuiPluginBase) set_precompiled_header(${LIBRARY_NAME} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp)
CreatePlugin()
and DeletePlugin()
CreatePlugin()
wxNonGuiPluginBase
public interface, which the application also knows about.CreatePlugin()
function.DeletePlugin()
function) and unload the library from memory. #pragma once #include <wxNonGuiPluginBase.h> // We need to know which DLL produced the specific plugin object. WX_DECLARE_HASH_MAP(wxNonGuiPluginBase*, wxDynamicLibrary*, wxPointerHash, wxPointerEqual, wxNonGuiPluginToDllDictionary); // We also need to keep the list of loaded DLLs WX_DECLARE_LIST(wxDynamicLibrary, wxDynamicLibraryList); // And separate list of loaded plugins for faster access. WX_DECLARE_LIST(wxNonGuiPluginBase, wxNonGuiPluginBaseList); class wxModularCoreSettings; class wxModularCore { public: wxModularCore(); virtual ~wxModularCore(); virtual wxString GetPluginsPath(bool forceProgramPath) const; virtual wxString GetPluginExt(); bool LoadPlugins(bool forceProgramPath); bool UnloadPlugins(); const wxNonGuiPluginBaseList & GetNonGuiPlugins() const; void Clear(); private: bool LoadNonGuiPlugins(const wxString & pluginsDirectory); bool UnloadNonGuiPlugins(); bool RegisterNonGuiPlugin(wxNonGuiPluginBase * plugin); bool UnRegisterNonGuiPlugin(wxNonGuiPluginBase * plugin); wxDynamicLibraryList m_DllList; wxNonGuiPluginToDllDictionary m_MapNonGuiPluginsDll; wxNonGuiPluginBaseList m_NonGuiPlugins; wxModularCoreSettings * m_Settings; };
wxDynamicLibraryList
), - ( wxNonGuiPluginBaseList
), -, ( wxNonGuiPluginToDllDictionary
)m_Settings
. , (, , , , , , , ). . #include "stdwx.h" #include "wxModularCore.h" #include "wxModularCoreSettings.h" #include <wx/listimpl.cpp> WX_DEFINE_LIST(wxDynamicLibraryList); WX_DEFINE_LIST(wxNonGuiPluginBaseList); wxModularCore::wxModularCore() :m_Settings(new wxModularCoreSettings) { // This will allow to delete all objects from this list automatically m_DllList.DeleteContents(true); } wxModularCore::~wxModularCore() { Clear(); wxDELETE(m_Settings); } void wxModularCore::Clear() { UnloadPlugins(); // TODO: Add the code which resets the object to initial state } bool wxModularCore::LoadPlugins(bool forceProgramPath) { wxString pluginsRootDir = GetPluginsPath(forceProgramPath); wxFileName fn; fn.AssignDir(pluginsRootDir); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); fn.AppendDir(wxT("plugins")); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); if (!fn.DirExists()) return false; return LoadNonGuiPlugins(fn.GetFullPath()); } bool wxModularCore::UnloadPlugins() { return UnloadNonGuiPlugins(); } bool wxModularCore::LoadNonGuiPlugins(const wxString & pluginsDirectory) { wxFileName fn; fn.AssignDir(pluginsDirectory); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); fn.AppendDir(wxT("nongui")); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); if (!fn.DirExists()) return false; if(!wxDirExists(fn.GetFullPath())) return false; wxString wildcard = wxString::Format(wxT("*.%s"), GetPluginExt().GetData()); wxArrayString pluginPaths; wxDir::GetAllFiles(fn.GetFullPath(), &pluginPaths, wildcard); for(size_t i = 0; i < pluginPaths.GetCount(); ++i) { wxString fileName = pluginPaths[i]; wxDynamicLibrary * dll = new wxDynamicLibrary(fileName); if (dll->IsLoaded()) { wxDYNLIB_FUNCTION(CreatePlugin_function, CreatePlugin, *dll); if (pfnCreatePlugin) { wxNonGuiPluginBase* plugin = pfnCreatePlugin(); RegisterNonGuiPlugin(plugin); m_DllList.Append(dll); m_MapNonGuiPluginsDll[plugin] = dll; } else wxDELETE(dll); } } return true; } bool wxModularCore::UnloadNonGuiPlugins() { bool result = true; wxNonGuiPluginBase * plugin = NULL; while (m_NonGuiPlugins.GetFirst() && (plugin = m_NonGuiPlugins.GetFirst()->GetData())) { result &= UnRegisterNonGuiPlugin(plugin); } return result; } wxString wxModularCore::GetPluginsPath(bool forceProgramPath) const { wxString path; if (m_Settings->GetStoreInAppData() && !forceProgramPath) path = wxStandardPaths::Get().GetConfigDir(); else path = wxPathOnly(wxStandardPaths::Get().GetExecutablePath()); return path; } wxString wxModularCore::GetPluginExt() { return #if defined(__WXMSW__) wxT("dll"); #else wxT("so"); #endif } bool wxModularCore::RegisterNonGuiPlugin(wxNonGuiPluginBase * plugin) { m_NonGuiPlugins.Append(plugin); return true; } bool wxModularCore::UnRegisterNonGuiPlugin(wxNonGuiPluginBase * plugin) { wxNonGuiPluginBaseList::compatibility_iterator it = m_NonGuiPlugins.Find(plugin); if (it == NULL) return false; do { wxDynamicLibrary * dll = m_MapNonGuiPluginsDll[plugin]; if (!dll) // Probably plugin was not loaded from dll break; wxDYNLIB_FUNCTION(DeletePlugin_function, DeletePlugin, *dll); if (pfnDeletePlugin) { pfnDeletePlugin(plugin); m_NonGuiPlugins.Erase(it); m_MapNonGuiPluginsDll.erase(plugin); return true; } } while (false); // If plugin is not loaded from DLL (eg embedded into executable) wxDELETE(plugin); m_NonGuiPlugins.Erase(it); return true; } const wxNonGuiPluginBaseList & wxModularCore::GetNonGuiPlugins() const { return m_NonGuiPlugins; }
LoadNonGuiPlugins()
, wxDYNLIB_FUNCTION
CreatePlugin()
. CreatePlugin_function
wxNonGuiPluginBase.h.UnRegisterNonGuiPlugin()
, , DeletePlugin()
. (, ), . #pragma once class wxModularCoreSettings { public: wxModularCoreSettings(); wxModularCoreSettings(const wxModularCoreSettings & settings); wxModularCoreSettings & operator = (const wxModularCoreSettings & settings); virtual ~wxModularCoreSettings(); void SetStoreInAppData(const bool & val); bool GetStoreInAppData() const; protected: virtual void CopyFrom(const wxModularCoreSettings & settings); private: bool m_bStoreInAppData; // Should we store data in Application Data folder or in .exe folder };
#include "stdwx.h" #include "wxModularCoreSettings.h" wxModularCoreSettings::wxModularCoreSettings() : m_bStoreInAppData(false) { } wxModularCoreSettings::wxModularCoreSettings(const wxModularCoreSettings & settings) { CopyFrom(settings); } wxModularCoreSettings & wxModularCoreSettings::operator = (const wxModularCoreSettings & settings) { if (this != &settings) { CopyFrom(settings); } return *this; } wxModularCoreSettings::~wxModularCoreSettings() { } void wxModularCoreSettings::CopyFrom(const wxModularCoreSettings & settings) { m_bStoreInAppData = settings.m_bStoreInAppData; } void wxModularCoreSettings::SetStoreInAppData(const bool & value) { m_bStoreInAppData = value; } bool wxModularCoreSettings::GetStoreInAppData() const { return m_bStoreInAppData; }
set (SRCS wxModularCore.cpp wxModularCoreSettings.cpp) set (HEADERS wxModularCore.h wxModularCoreSettings.h) set(LIBRARY_NAME wxModularCore) if(WIN32) set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS};/D__STDC_CONSTANT_MACROS) set(LINK_DIRECTORIES ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase/${OS_BASE_NAME}${LIB_SUFFIX}/$(ConfigurationName)) set(DEMO_LIBS wxNonGuiPluginBase.lib) endif(WIN32) set(SRCS ${SRCS} ${HEADERS} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp) add_definitions(${PREPROCESSOR_DEFINITIONS}) include_directories(${INCLUDE_DIRECTORIES} ${BASE_INCLUDE_DIRECTORIES} ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase) link_directories(${LINK_DIRECTORIES}) add_library(${LIBRARY_NAME} STATIC ${SRCS}) set(DLL_DIR bin) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${DLL_DIR}/${CMAKE_CFG_INTDIR}) set_target_properties(${LIBRARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TARGET_LOCATION}) target_link_libraries(${LIBRARY_NAME} ${DEMO_LIBS} ${wxWidgets_LIBRARIES}) add_dependencies(${LIBRARY_NAME} wxNonGuiPluginBase) set_precompiled_header(${LIBRARY_NAME} ${PROJECT_ROOT_DIR}/include/stdwx.h ${PROJECT_ROOT_DIR}/include/stdwx.cpp)
... add_subdirectory (../wxModularCore ../../wxModularCore/${OS_BASE_NAME}${LIB_SUFFIX}) ...
wxModularCore
: ... class wxModularHostApp: public wxApp { void TestNonGuiPlugins(); ... wxModularCore * m_PluginManager; ... };
void wxModularHostApp::Init() { ////@begin wxModularHostApp member initialisation m_PluginManager = new wxModularCore; ////@end wxModularHostApp member initialisation }
bool wxModularHostApp::OnInit() { ... TestNonGuiPlugins(); MainFrame* mainWindow = new MainFrame( NULL ); mainWindow->Show(true); return true; } /* * Cleanup for wxModularHostApp */ int wxModularHostApp::OnExit() { wxDELETE(m_PluginManager); ////@begin wxModularHostApp cleanup return wxApp::OnExit(); ////@end wxModularHostApp cleanup } void wxModularHostApp::TestNonGuiPlugins() { if(m_PluginManager) { if(m_PluginManager->LoadPlugins(true)) { for(wxNonGuiPluginBaseList::Node * node = m_PluginManager->GetNonGuiPlugins().GetFirst(); node; node = node->GetNext()) { wxNonGuiPluginBase * plugin = node->GetData(); if(plugin) { wxLogDebug(wxT("Non-GUI plugin returns %i"), plugin->Work()); } } } } }
TestNonGuiPlugins()
LoadPlugins()
wxModularCore
, , Work()
(, wxNonGuiPluginBase, ). #pragma once #include "Declarations.h" class DEMO_API wxGuiPluginBase : public wxObject { DECLARE_ABSTRACT_CLASS(wxGuiPluginBase) public: wxGuiPluginBase(); virtual ~wxGuiPluginBase(); virtual wxString GetName() const = 0; virtual wxString GetId() const = 0; virtual wxWindow * CreatePanel(wxWindow * parent) = 0; }; typedef wxGuiPluginBase * (*CreateGuiPlugin_function)(); typedef void (*DeleteGuiPlugin_function)(wxGuiPluginBase * plugin);
GetName()
- returns the name of the moduleGetId()
- returns the unique identifier of the module (you can use the GUID for this; in Visual Studio there is a special utility for these purposes. See the menu Tools -> Create GUID
)CreatePanel()
- creates a control (for demonstration, we are satisfied with any control) and returns a pointer to it. #pragma once #include <wxGuiPluginBase.h> class SampleGuiPlugin1 : public wxGuiPluginBase { DECLARE_DYNAMIC_CLASS(SampleGuiPlugin1) public: SampleGuiPlugin1(); virtual ~SampleGuiPlugin1(); virtual wxString GetName() const; virtual wxString GetId() const; virtual wxWindow * CreatePanel(wxWindow * parent); };
#include "stdwx.h" #include "SampleGuiPlugin1.h" IMPLEMENT_DYNAMIC_CLASS(SampleGuiPlugin1, wxObject) SampleGuiPlugin1::SampleGuiPlugin1() { } SampleGuiPlugin1::~SampleGuiPlugin1() { } wxString SampleGuiPlugin1::GetName() const { return _("GUI Plugin 1"); } wxString SampleGuiPlugin1::GetId() const { return wxT("{4E97DF66-5FBB-4719-AF17-76C1C82D3FE1}"); } wxWindow * SampleGuiPlugin1::CreatePanel(wxWindow * parent) { wxWindow * result= new wxPanel(parent, wxID_ANY); result->SetBackgroundColour(*wxRED); return result; }
LoadXXXPlugins()
, UnloadXXXPlugins()
, RegisterXXXPlugin()
, UnRegisterXXXPlugin()
, - - wxModularCore
, , . #pragma once // We need to keep the list of loaded DLLs WX_DECLARE_LIST(wxDynamicLibrary, wxDynamicLibraryList); class wxModularCoreSettings; class wxModularCore { public: wxModularCore(); virtual ~wxModularCore(); virtual wxString GetPluginsPath(bool forceProgramPath) const; virtual wxString GetPluginExt(); virtual bool LoadAllPlugins(bool forceProgramPath) = 0; virtual bool UnloadAllPlugins() = 0; virtual void Clear(); protected: wxDynamicLibraryList m_DllList; wxModularCoreSettings * m_Settings; template<typename PluginType, typename PluginListType> bool RegisterPlugin(PluginType * plugin, PluginListType & list) { list.Append(plugin); return true; } template<typename PluginType, typename PluginListType, typename PluginToDllDictionaryType, typename DeletePluginFunctionType> bool UnRegisterPlugin( PluginType * plugin, PluginListType & container, PluginToDllDictionaryType & pluginMap) { typename PluginListType::compatibility_iterator it = container.Find(plugin); if (it == NULL) return false; do { wxDynamicLibrary * dll = (wxDynamicLibrary *)pluginMap[plugin]; if (!dll) // Probably plugin was not loaded from dll break; wxDYNLIB_FUNCTION(DeletePluginFunctionType, DeletePlugin, *dll); if (pfnDeletePlugin) { pfnDeletePlugin(plugin); container.Erase(it); pluginMap.erase(plugin); return true; } } while (false); // If plugin is not loaded from DLL (eg embedded into executable) wxDELETE(plugin); container.Erase(it); return true; } template<typename PluginType, typename PluginListType, typename PluginToDllDictionaryType, typename DeletePluginFunctionType> bool UnloadPlugins(PluginListType & list, PluginToDllDictionaryType & pluginDictoonary) { bool result = true; PluginType * plugin = NULL; while (list.GetFirst() && (plugin = list.GetFirst()->GetData())) { result &= UnRegisterPlugin<PluginType, PluginListType, PluginToDllDictionaryType, DeletePluginFunctionType>(plugin, list, pluginDictoonary); } return result; } template <typename PluginType, typename PluginListType, typename PluginToDllDictionaryType, typename CreatePluginFunctionType> bool LoadPlugins(const wxString & pluginsDirectory, PluginListType & list, PluginToDllDictionaryType & pluginDictionary, const wxString & subFolder) { wxFileName fn; fn.AssignDir(pluginsDirectory); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); fn.AppendDir(subFolder); wxLogDebug(wxT("%s"), fn.GetFullPath().data()); if (!fn.DirExists()) return false; if(!wxDirExists(fn.GetFullPath())) return false; wxString wildcard = wxString::Format(wxT("*.%s"), GetPluginExt().GetData()); wxArrayString pluginPaths; wxDir::GetAllFiles(fn.GetFullPath(), &pluginPaths, wildcard); for(size_t i = 0; i < pluginPaths.GetCount(); ++i) { wxString fileName = pluginPaths[i]; wxDynamicLibrary * dll = new wxDynamicLibrary(fileName); if (dll->IsLoaded()) { wxDYNLIB_FUNCTION(CreatePluginFunctionType, CreatePlugin, *dll); if (pfnCreatePlugin) { PluginType * plugin = pfnCreatePlugin(); RegisterPlugin(plugin, list); m_DllList.Append(dll); pluginDictionary[plugin] = dll; } else wxDELETE(dll); } } return true; } };
#pragma once #include <wxModularCore.h> #include <wxNonGuiPluginBase.h> #include <wxGuiPluginBase.h> // We need to know which DLL produced the specific plugin object. WX_DECLARE_HASH_MAP(wxNonGuiPluginBase*, wxDynamicLibrary*, wxPointerHash, wxPointerEqual, wxNonGuiPluginToDllDictionary); WX_DECLARE_HASH_MAP(wxGuiPluginBase*, wxDynamicLibrary*, wxPointerHash, wxPointerEqual, wxGuiPluginToDllDictionary); // And separate list of loaded plugins for faster access. WX_DECLARE_LIST(wxNonGuiPluginBase, wxNonGuiPluginBaseList); WX_DECLARE_LIST(wxGuiPluginBase, wxGuiPluginBaseList); class SampleModularCore : public wxModularCore { public: virtual ~SampleModularCore(); virtual bool LoadAllPlugins(bool forceProgramPath); virtual bool UnloadAllPlugins(); const wxNonGuiPluginBaseList & GetNonGuiPlugins() const; const wxGuiPluginBaseList & GetGuiPlugins() const; private: wxNonGuiPluginToDllDictionary m_MapNonGuiPluginsDll; wxNonGuiPluginBaseList m_NonGuiPlugins; wxGuiPluginToDllDictionary m_MapGuiPluginsDll; wxGuiPluginBaseList m_GuiPlugins; };
#include "stdwx.h" #include "SampleModularCore.h" #include <wx/listimpl.cpp> WX_DEFINE_LIST(wxNonGuiPluginBaseList); WX_DEFINE_LIST(wxGuiPluginBaseList); SampleModularCore::~SampleModularCore() { Clear(); } bool SampleModularCore::LoadAllPlugins(bool forceProgramPath) { wxString pluginsRootDir = GetPluginsPath(forceProgramPath); bool result = true; result &= LoadPlugins<wxNonGuiPluginBase, wxNonGuiPluginBaseList, wxNonGuiPluginToDllDictionary, CreatePlugin_function>(pluginsRootDir, m_NonGuiPlugins, m_MapNonGuiPluginsDll, wxT("nongui")); result &= LoadPlugins<wxGuiPluginBase, wxGuiPluginBaseList, wxGuiPluginToDllDictionary, CreateGuiPlugin_function>(pluginsRootDir, m_GuiPlugins, m_MapGuiPluginsDll, wxT("gui")); // You can implement other logic which takes in account // the result of LoadPlugins() calls return true; } bool SampleModularCore::UnloadAllPlugins() { return UnloadPlugins<wxNonGuiPluginBase, wxNonGuiPluginBaseList, wxNonGuiPluginToDllDictionary, DeletePlugin_function>(m_NonGuiPlugins, m_MapNonGuiPluginsDll) && UnloadPlugins<wxGuiPluginBase, wxGuiPluginBaseList, wxGuiPluginToDllDictionary, DeleteGuiPlugin_function>(m_GuiPlugins, m_MapGuiPluginsDll); } const wxNonGuiPluginBaseList & SampleModularCore::GetNonGuiPlugins() const { return m_NonGuiPlugins; } const wxGuiPluginBaseList & SampleModularCore::GetGuiPlugins() const { return m_GuiPlugins; }
void MainFrame::AddPagesFromGuiPlugins() { SampleModularCore * pluginManager = wxGetApp().GetPluginManager(); for(wxGuiPluginBaseList::Node * node = pluginManager->GetGuiPlugins().GetFirst(); node; node = node->GetNext()) { wxGuiPluginBase * plugin = node->GetData(); if(plugin) { wxWindow * page = plugin->CreatePanel(m_Notebook); if(page) { m_Notebook->AddPage(page, plugin->GetName()); } } } }
GetName()
, CreatePanel()
.RUNTIME_OUTPUT_DIRECTORY
. Linux, .. – ( ), LIBRARY_OUTPUT_DIRECTORY
. : bin, . , bin. ( ): ... set(DLL_DIR bin) if(LINUX) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${DLL_DIR}${LIB_SUFFIX}/plugins/nongui) else(LINUX) set(TARGET_LOCATION ${PROJECT_SOURCE_DIR}/${DLL_DIR}/${CMAKE_CFG_INTDIR}/plugins/nongui) get_target_property(RESULT_FULL_PATH ${LIBRARY_NAME} LOCATION) get_filename_component(RESULT_FILE_NAME ${RESULT_FULL_PATH} NAME) endif(LINUX) set_target_properties(${LIBRARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TARGET_LOCATION}) ... if(LINUX) add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_LOCATION} COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${LIBRARY_NAME}> ${TARGET_LOCATION}/${RESULT_FILE_NAME} ) endif(LINUX)
... if(WIN32) set(SRCS ${SRCS} ${LIBRARY_NAME}.def) set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS};/D_USRDLL;/D__STDC_CONSTANT_MACROS) set(LINK_DIRECTORIES ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase/${OS_BASE_NAME}${LIB_SUFFIX}/$(ConfigurationName)) set(DEMO_LIBS wxNonGuiPluginBase.lib) endif(WIN32) if(LINUX) set(DEMO_LIBS wxNonGuiPluginBase) endif(LINUX) ...
ldd libSampleGuiPlugin2.so | grep wxSampleGuiPluginBase
RPATH
, : if(WIN32) set(SRCS ${SRCS} ${LIBRARY_NAME}.def) set(PREPROCESSOR_DEFINITIONS ${PREPROCESSOR_DEFINITIONS};/D_USRDLL;/D__STDC_CONSTANT_MACROS) set(LINK_DIRECTORIES ${PROJECT_ROOT_DIR}/wxNonGuiPluginBase/${OS_BASE_NAME}${LIB_SUFFIX}/$(ConfigurationName)) set(DEMO_LIBS wxNonGuiPluginBase.lib) endif(WIN32) if(LINUX) set(DEMO_LIBS wxNonGuiPluginBase) SET(CMAKE_SKIP_BUILD_RPATH FALSE) SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) SET(CMAKE_INSTALL_RPATH ".:./../../") endif(LINUX)
if(APPLE) FOREACH(DEP_LIB ${DEMO_LIBS}) get_filename_component(ABS_ROOT_DIR ${PROJECT_ROOT_DIR} ABSOLUTE) set(LIBNAME_FULL "${ABS_ROOT_DIR}/${DEP_LIB}/${OS_BASE_NAME}${LIB_SUFFIX}/$(CONFIGURATION)/lib${DEP_LIB}.dylib") add_custom_command(TARGET ${LIBRARY_NAME} POST_BUILD COMMAND install_name_tool -change "${LIBNAME_FULL}" "@executable_path/../Frameworks/lib${DEP_LIB}.dylib" $<TARGET_FILE:${LIBRARY_NAME}>) ENDFOREACH(DEP_LIB) endif(APPLE)
if(APPLE) FOREACH(DEP_LIB ${DEMO_LIBS_SHARED}) get_filename_component(ABS_ROOT_DIR ${PROJECT_ROOT_DIR} ABSOLUTE) set(LIBNAME_FULL "${ABS_ROOT_DIR}/${DEP_LIB}/${OS_BASE_NAME}${LIB_SUFFIX}/$(CONFIGURATION)/lib${DEP_LIB}.dylib") add_custom_command(TARGET ${EXECUTABLE_NAME} POST_BUILD COMMAND install_name_tool -change "${LIBNAME_FULL}" "@executable_path/../Frameworks/lib${DEP_LIB}.dylib" $<TARGET_FILE:${EXECUTABLE_NAME}>) ENDFOREACH(DEP_LIB) endif(APPLE)
Source: https://habr.com/ru/post/203322/
All Articles