A Simple C++ Plugin System -- Interface Between Plugin and Main Application

原创 2016年10月10日 23:54:04


前人已有A Simple C++ Plugin System Summary,本文将处理,如何实现插件与主程序之间的接口


1. 主程序中访问,修改插件参数,参见下面的指针类接口。
2. 插件访问,修改主程序参数,需要在插件的初始化函数中提供主程序引用参数,实测可行。
3. 插件A访问,修改插件B,插件C……中的参数(对插件A的开发者要求很高,插件B,插件C要提供接口供插件A调用,如插件A直接调用插件B,C,但这有时不太现实,如果插件B,C只能有一个实例。这样的话,要求主程序提供一套插件回调机制,插件A通过主程序回调其它插件)。

Related Work


The method we’ve been using recently is actually quite simple. The plugin implements a onCommand method which accepts arbitrary commands from the application. The advantage of using this type of interface is that you’re able to implement almost any kind of functionality without having to add new methods and break the API each time you roll out a new feature. Obviously it doesn’t have it be this simple, but you get the idea!

Command nodes (see code below) are namespaced using a REST style interface like so resource:action, and the data buffer contains either a JSON encoded message which for representing and converting to an STL container such a std::vector or std::map to pass to the internal API, or it may just be a raw data buffer that can be used directly.

bool onCommand(const char* node, const char* data, unsigned int size)
    try {
        // Handle a JSON encoded options hash
        if (strcmp(node, "options:set") == 0) {   
            json::Value root;
            json::Reader reader;
            if (!reader.parse(data, size, root))          
                throw std::runtime_error("Invalid JSON format: " + reader.getFormatedErrorMessages());

            // Do something with JSON data here...

        // Handle raw file data
        else if (strcmp(node, "file:write") == 0) {
            std::string path("test.bin");
            std::ofstream ofs(path, std::ios::out|std::ios::binary);
            if (!ofs.is_open())
                throw std::runtime_error("Cannot write to output file: " + path);
            ofs.write(data, size);

        // Handle unknown commands
        else throw std::runtime_error("Unknown command");
    catch (std::exception& exc) {
        // Catch exceptions here and return false.
        // You could set a lastError string here which is exposed to
        // the application that returns the error message as a char*.
        // See the full example for details.
        std::cerr << "Command error: " << exc.what() << std::endl;
        return false;
    return true;


通过指针返回符号(函数或者成员变量),注意typedef void* gpointer; 这样,通过void * 可以返回任意数据类型,无论是函数还是成员变量。

/* the function signature for 'say_hello' */
typedef void (* SayHelloFunc) (const char *message);

just_say_hello (const char *filename, GError **error)
  SayHelloFunc  say_hello;
  GModule      *module;

  module = g_module_open (filename, G_MODULE_BIND_LAZY);
  if (!module)
      g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
                   "%s", g_module_error ());
      return FALSE;

  if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello))
      g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
                   "%s: %s", filename, g_module_error ());
      if (!g_module_close (module))
        g_warning ("%s: %s", filename, g_module_error ());
      return FALSE;

  if (say_hello == NULL)
      g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
                   "symbol say_hello is NULL");
      if (!g_module_close (module))
        g_warning ("%s: %s", filename, g_module_error ());
      return FALSE;

  /* call our function in the module */
  say_hello ("Hello world!");

  if (!g_module_close (module))
    g_warning ("%s: %s", filename, g_module_error ());
  return TRUE;




所有插件仅处理一种类型的数据,如矩阵。参见orange 实现机制 不过这是python,但原则上c++也可以这么做。但势必会麻烦一些,毕竟python是脚本语言。






#include "DataDriveFunctions.h"
#include "DataDriveMain.h"
#include "yzbx_config.h"
#include <dlfcn.h>

using namespace DataDrive ;
typedef Base* create_t(std::shared_ptr<DataDriveMain> data);
typedef void destroy_t(Base*);
int main(){
  using std::cout;
    using std::cerr;

    // load the dll library
    void* dll = dlopen("./test4.so", RTLD_LAZY);
    if (!dll) {
        cerr << "Cannot load library: " << dlerror() << '\n';
        return 1;

    // reset errors

    // load the symbols
    create_t* create_dll = (create_t*) dlsym(dll, "create");
    const char* dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol create: " << dlsym_error << '\n';
        return 1;

    destroy_t* destroy_dll = (destroy_t*) dlsym(dll, "destroy");
    dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
        return 1;

    // create an instance of the class
    std::shared_ptr<DataDriveMain> data=std::make_shared<DataDriveMain>(DataDriveMain("/home/yzbx/config/surveillance-video-system.ini"));
    Base* base = create_dll(data);

    // use the class
        cout << "The frameNum is: " << data->frameNum << '\n';
    cout << "The frameNum is: " << data->frameNum << '\n';
    // destroy the class

    // unload the dll library


#include "DataDriveFunctions.h"
#include "DataDriveMain.h"
#include "yzbx_config.h"
using namespace DataDrive ;

 class DllTest:public Base{
    DllTest(std::shared_ptr<DataDriveMain> data):Base(data){}
    bool run();

bool DllTest::run(){
  return true;

extern "C" Base * create(std::shared_ptr<DataDriveMain> data){
  return new DllTest(data);

extern "C" void destroy(Base * p){
  delete p;


g++ -std=c++14 -fPIC -I/home/yzbx/git/surveillance-video-system/objectTracking/src/objectTracking/yzbxLib `pkg-config --cflags Qt5Core` test4_dll.cpp -shared -o test4.so  `pkg-config --libs Qt5Core` -L/home/yzbx/build/build-objectTracking-Desktop_Qt_5_6_0_GCC_64bit-Debug/yzbxLib -lyzbxLib

g++ -std=c++14 -fPIC -I/home/yzbx/git/surveillance-video-system/objectTracking/src/objectTracking/yzbxLib `pkg-config --cflags Qt5Core` test4_main.cpp -o test4  -L/home/yzbx/build/build-objectTracking-Desktop_Qt_5_6_0_GCC_64bit-Debug/yzbxLib -lyzbxLib `pkg-config --libs Qt5Core` `pkg-config --libs bgslibrary` `pkg-config --libs opencv` -lboost_filesystem -lboost_program_options -lboost_system -ldl


(env2) $: cd -
(env2) $: ls
a.out      hello.so     test1-libm-so    test3_triangle.cpp  triangle.so
bin        Jamroot      test2_hello.cpp  test4
build.sh   polygon.hpp  test2_main.cpp   test4_dll.cpp
config     test1        test3_main       test4_main.cpp
error.log  test1.c      test3_main.cpp   test4.so
(env2) $: ./test4
The frameNum is: 0
The frameNum is: 1
(env2) $: 

Application binary interface(应用二进制接口)

In computer software, an application binary interfaceABI ) describes the low-level interface betw...
  • simtwo
  • simtwo
  • 2010年11月11日 21:42
  • 2026

SH Application Binary Interface for GCC

转自:http://www.kpitgnutools.com/manuals/SH-ABI-Specification.html SH Application Binary Interface fo...
  • talking12391239
  • talking12391239
  • 2013年03月12日 14:53
  • 787

A Simple C++ Plugin System Summary

Abstract一个简单的C++插件系统介绍,主要介绍linux平台下的原理及代码Keywordsplugin framework c++ plugin system plugin architect...
  • u010598445
  • u010598445
  • 2016年10月10日 18:04
  • 304

experiment: C++ Plugin Framework

找到一个CPF http://www.codeproject.com/KB/DLL/PluginSystem.aspx google keywords "c++ plugin fr...
  • LostSpeed
  • LostSpeed
  • 2011年11月01日 01:32
  • 2503

blocked the main thread for 71ms. Plugin should use CordovaInterface.getThreadPool()

在自己的cordova项目中经常出现一个警告:THREAD WARNING: exec() call to xxxxx.xxxxx blocked the main thread for 71ms...
  • qq_29157683
  • qq_29157683
  • 2016年09月12日 18:51
  • 1057

Making a Plugin System

Making a Plugin System Score: 3.7/5 (44 votes) Now, lets say that you are making a program...
  • ffyanwei
  • ffyanwei
  • 2014年04月28日 10:48
  • 179

Gradle 1.12用户指南翻译——第四十五章. 应用程序插件

Gradle 应用程序插件扩展了语言插件的一些常见应用程序相关的任务。它允许为 jvm 运行和捆绑应用程序。 45.1. 用法 要使用这个应用程序插件,请在构建脚本中包含以下语句: 示例 45.1...
  • maosidiaoxian
  • maosidiaoxian
  • 2016年01月11日 09:11
  • 2609

关于Plugin with id 'com.github.dcendents.android-maven' not found.问题解决

  • sinat_28884723
  • sinat_28884723
  • 2017年05月20日 11:53
  • 1640

There is a circular dependency between XMPPFramework/Core and XMPPFramework/Authentication

执行"pod install" 或者 "pod update" , xmppframework 会出现循环依赖问题。 There is a circular dependency betwe...
  • CB1234CB
  • CB1234CB
  • 2015年06月29日 09:41
  • 893

Plugin 'InnoDB' registration as a STORAGE ENGINE failed.

Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
  • nightelve
  • nightelve
  • 2014年04月30日 00:09
  • 6327
您举报文章:A Simple C++ Plugin System -- Interface Between Plugin and Main Application