Programs That Support Plugins

From WxWiki
Jump to: navigation, search

If the 'host' program uses wxWidgets

Example: http://atol.sf.net/old/plugin_test.zip (This link no longer works either, the sample file might be available from http://prdownloads.sourceforge.net/atol/atol_plugins-0.5.9_src.zip?download )

The following example, contributed by Frank, is based on wxMinimal example, comes with all sources and compiles under Linux as well as under Windows it should be easy to extend the example of individual needs. Sources can be found under: http://gaos.org/~schleif/portable_plugin_example.tar.gz

Example: http://bzzt.net/~wxwidgets/PluginExample.zip (Thanks Noel!)

This example, written by Raphael Juchli, is a *very* minimal example, but demonstrates bi-directionality for a plugin, built against 2.5.1 on Linux and Windows, and 2.4.2 under Windows (not tested with this version under Linux), it demonstrates a way for the plugin and main app to communicate with each other.

Both of the last mentioned examples are great stuff except one exception: They don't take care of proper memory managment. They both don't unload the plugin libs after usage, which causes memory leaks. So keep in mind you need to unload all dynamic libs, if you don't need them any more. ( @ autors of plugin examples : maybe you could fix this ).

In new versions of wx, problem with crashing application during creating wx object by our dynamically loaded library can be resolved by using wxWidgets compiled as a DLL. Compiled DLL version of wx can be found at http://wxpack.sourceforge.net/ (Problem occurs surely in libraries and programs compiled with wxDev-C++, when both host and DLL use wx)

Very simple, yet working example ;)

added by toudi < mikolajczyk dot mateusz at gmail > @ 15.03.2010 This sample was originaly developed by someone called UpCase. By the time i layed my hands on it, it wasn't functional. So i tweaked it a little and it was ready once again. I also added CMake script in order to help building it.

If You don't want to copy & paste, grab the source from here => http://dreakmore.info/wxWidgets/wxPlugin.zip Here it goes.

iPlugin.h:

#ifndef IPLUGIN_H
#define IPLUGIN_H

#include <wx/wx.h>
#if defined(__WIN32__)
	#define IMPLEMENT_PLUGIN(name) extern "C" __declspec(dllexport) Plugin* CreatePlugin() { return new name();};
#else
	#define IMPLEMENT_PLUGIN(name) extern "C" Plugin* CreatePlugin() { return new name();};
#endif

//the plugin interface (a.k.a. abstract class)
//our plugin will contain GUI in itself - therefore we need to make it extend wxEvtHandler (or wxDialog for that matter)
class Plugin : public wxEvtHandler
{
public:
	virtual void PerformTasks()=0;
	virtual wxWindow* GetGUI(wxWindow* parent)=0;	
};

//define a function pointer type for convenience
#ifndef __PLUGIN_FUNCTION
#define __PLUGIN_FUNCTION
typedef Plugin* ( *CreatePlugin_function)();
#endif //__PLUGIN_FUNCTION

#endif

samplePlugin.h NOTE: If you are creating your sample plugin as a seperate project esure you set Properties -> General -> Configuration Type to Dynamic Libary (.dll) for visual studio, steps may vary for other IDE's

#include "iPlugin.h"

//this will be our actual plugin.
class samplePlugin : public Plugin
{
public:
	virtual void PerformTasks();
	virtual wxWindow* GetGUI(wxWindow* parent);

	void OnButton(wxCommandEvent& e);
};

samplePlugin.cc

#include "samplePlugin.h"
//this macro was defined in iPlugin.h file - it's used to export c++ constructor of the class.
IMPLEMENT_PLUGIN(samplePlugin)

void samplePlugin::PerformTasks()
{
	wxMessageBox(_("I would if I could..."));
}

wxWindow* samplePlugin::GetGUI(wxWindow* parent)
{
	wxWindow *dlg = new wxWindow(parent, wxID_ANY);

	wxBoxSizer* box = new wxBoxSizer(wxHORIZONTAL);
	wxButton* b = new wxButton(dlg,wxID_ANY,_("Some action in the plugin"));
	//Use connect in this case as static event tables won't work
	//As Plugin is derived from wxEvtHandler you can catch events in this Plugin
	b->Connect( wxID_ANY,
    wxEVT_COMMAND_BUTTON_CLICKED,
    wxCommandEventHandler(samplePlugin::OnButton),NULL,this
	);

	box->Add(b, 0, wxALIGN_CENTER|wxALL, 5 );
	dlg->SetSizer(box);
	dlg->Layout();
	return dlg;
}

void samplePlugin::OnButton(wxCommandEvent& e)
{
	wxMessageBox(_("Doing some action"));
}

HostFrame.h

#pragma once
#include <wx/wx.h>
#include <wx/notebook.h>
#include "iPlugin.h"
class HostFrame : public wxFrame
{
	wxNotebook* m_notebook;
	wxBoxSizer* box;
public:
	HostFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
	virtual ~HostFrame();
private:
	DECLARE_CLASS(HostFrame)
	wxPanel* dummy;
	void OnDoit(wxCommandEvent& e);
	DECLARE_EVENT_TABLE()
};

HostFrame.cpp

#include "HostApp.h"
#include "HostFrame.h"
#include <wx/dynlib.h>
//include the plugin definition
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
enum
{
    ID_DOIT = 1
};
IMPLEMENT_CLASS(HostFrame, wxFrame)

BEGIN_EVENT_TABLE(HostFrame, wxFrame)
	EVT_BUTTON(ID_DOIT, HostFrame::OnDoit)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

HostFrame::HostFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
        box = new wxBoxSizer(wxVERTICAL);
	wxButton* b = new wxButton(this,ID_DOIT,_("Doit"));
	dummy = new wxPanel(this,wxID_ANY, wxDefaultPosition, wxDefaultSize);
	box->Add(b,0,wxEXPAND,0);
	box->Add(dummy,1,wxEXPAND,5);
	SetSizer(box);
	Layout();
}
HostFrame::~HostFrame() {}

void HostFrame::OnDoit(wxCommandEvent& e)
{
	//Load the plugin
	wxDynamicLibrary dll;
	dll.Load(wxGetCwd()+_("/")+wxDynamicLibrary::CanonicalizeName(_("samplePlugin")));
	if(dll.IsLoaded())
	{
		//Create a valid function pointer using the function pointer type in plugin.h
		wxDYNLIB_FUNCTION(CreatePlugin_function,CreatePlugin,dll);
		//check if the function is found
		if(pfnCreatePlugin)
		{
			//Important: Use Detach(), otherwise the DLL will be unloaded once the wxDynamibLibrary object
			//goes out of scope
			dll.Detach();
			//Create the plugin
			Plugin* plugin = pfnCreatePlugin();
			//call some method in it
			plugin->PerformTasks();
			//we will append the gui from the plugin into the panel's sizer
			wxBoxSizer* s = new wxBoxSizer(wxVERTICAL);
			wxWindow* w = plugin->GetGUI(this->dummy);
			s->Add( w, 0, wxALL|wxALIGN_CENTER, 5 );
			dummy->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
			dummy->SetSizer( s );
			dummy->Layout();
		}
	}
}

HostApp.h

#pragma once
#include <wx/wx.h>
class HostApp : public wxApp
{
public:
    HostApp();
    virtual ~HostApp();
    virtual bool OnInit();
};
DECLARE_APP(HostApp)

HostApp.cpp

#include "HostApp.h"
#include "HostFrame.h"
IMPLEMENT_APP(HostApp)
// ============================================================================
// implementation
// ============================================================================
HostApp::HostApp() {}
HostApp::~HostApp() {}

bool HostApp::OnInit()
{
	HostFrame *frame = new HostFrame(_("wxWidgets"),
	wxPoint(50, 50), wxSize(400, 300));
	frame->Show(TRUE);
	SetTopWindow(frame);
	return TRUE;
}

and - last but not least - CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(wxWidgetsPluginExample)

set(wxWidgets_USE_DEBUG, FALSE)
set(wxWidgets_USE_UNICODE, TRUE)
find_package(wxWidgets REQUIRED core base)

include(${wxWidgets_USE_FILE})

#include_directories(${wxWidgets_INCLUDE_DIRS})
#add_definitions(${wxWidgets_DEFINITIONS})
 
set(SRCS 
	iPlugin.h
	HostApp.h
	HostApp.cpp
	HostFrame.h
	HostFrame.cpp
)

set(plugin_SRCS
	samplePlugin.h
	samplePlugin.cc
)

set(BINDIR ${CMAKE_BINARY_DIR}/../bin/)
#compile the plugin:
add_library (samplePlugin SHARED ${plugin_SRCS})
target_link_libraries(samplePlugin ${wxWidgets_LIBRARIES})
install (TARGETS samplePlugin DESTINATION ${BINDIR})

#win32 is added so that the console window would dissapear under windows.
add_executable(hostApp WIN32 ${SRCS})
target_link_libraries(hostApp ${wxWidgets_LIBRARIES})
install (TARGETS hostApp RUNTIME DESTINATION ${BINDIR})

How to compile it?

First of all, cmake is required (if You don't want to compile all of the files by hand). assuming, that You have all of the files in one directory and You are in it, it's very simple:

mkdir build
cd build
cmake ../
make install [or nmake on windows, using msvc]

You should see the directory bin and two files in it. Enjoy ;)

If the 'host' program doesn't use wxWidgets

But has its own message pump etc.

See also: