VC++写一个演示如何为应用程序写plugin插件的项目

如果不需要plugin,DLL一般都是带lib直接编译进项目的居多,这种情况下,和普通的函数库调用没什么区别。

但如果考虑到自己的应用程序中,要允许客户中任何人添加plugin,那情况就有所不同。

这里(参考地址:http://www.cplusplus.com/articles/48TbqMoL/)给出了一个用MINGW编译的例子,但这个例子在VC上是运行不通的。我稍加修改,并作了备注,做成了一个VCC演示工程。main.hpp中例出了3种情况,

(1)extern "C" __declspec(dllimport/dllexport)的C程序格式

(2)__declspec(dllimport/dllexport),可调用C++类的程序格式

(3)*.def定义的形式

#ifndef __MAIN_HPP_INCLUDED__
#define __MAIN_HPP_INCLUDED__

#include <memory>
#include <string>

/*
method (1)Only suitable for C type, NOT c++ classes
    #define DLLAPI extern "C" __declspec(dllexport)

method (2) for compile with test1.lib / test2.lib / test3.lib etc.
    #define DLLAPI __declspec(dllexport)

    NOTE: if your application is not compiled with *.lib, and you need to use loadlibrary, the format may be strange as below

    typedef std::unique_ptr<Base> (__cdecl *ObjProc)(void);
    HINSTANCE mod = LoadLibrary("test1.dll");
    ObjProc objFunc = (ObjProc) GetProcAddress(mod, "?getObj@@YA?AV?$unique_ptr@VBase@@U?$default_delete@VBase@@@std@@@std@@XZ");

    the strange name ""?getObj@@YA?AV?$unique_ptr..." can be obtained from dumpbin tool
    dumpbin /exports test1.dll
    
method (3) plugin mode
    #define DLLAPI

    NOTE: in this case you need to define the source.def file, the contents may be as below,

    LIBRARY TEST1
    EXPORTS
    getObj
    getName
    getValue
*/

#ifdef _WINDLL // BUILD_DLL for MINGW
    //#define DLLAPI extern "C" __declspec(dllexport)
    //#define DLLAPI __declspec(dllexport)
    #define DLLAPI
#else
    //#define DLLAPI extern "C" __declspec(dllimport)
    //#define DLLAPI __declspec(dllimport)
    #define DLLAPI
#endif // BUILD_DLL


class Base {
public:
    virtual ~Base() = default;
    virtual void print(void) = 0;
    virtual double calc(double val) = 0;
};

// DLL export funcs

DLLAPI std::unique_ptr<Base> getObj(void);
DLLAPI std::string getName(void);
DLLAPI int getValue(void);

#endif // __MAIN_HPP_INCLUDED__

主要定义上变化的部分就在这里,其他内容就不再解释了,和原贴基本没什么区别,其实都很简单,例如main.cpp只添加了一个测试getValue函数,

// Program to demonstrate the use of a plugin system.

#include <iostream>
#include <vector>
#include <memory>
#include <stdexcept>
#include <exception>
#include <windows.h>
#include "main.hpp"

// Load the objects from the plugin folder.
//
// Takes as a parameter a reference to a list of modules,
// which will be emptied and then refilled with handles to
// the modules loaded. These should be freed with the
// FreeLibrary() after use.
//
// Returns a list of Base*, contained in a smart pointer
// to ease memory deallocation and help prevent memory
// leaks.
std::vector<std::unique_ptr<Base>> getPlugins(std::vector<HINSTANCE>& modules) {
    // A temporary structure to return.
    std::vector<std::unique_ptr<Base>> ret;
    // empty the modules list passed
    modules.clear();

    // Find the files contained in the 'plugins' folder
    WIN32_FIND_DATA fileData;
    HANDLE fileHandle = FindFirstFile(R"(.\plugins\*.dll)", &fileData);

    if (fileHandle == (void*)ERROR_INVALID_HANDLE ||
        fileHandle == (void*)ERROR_FILE_NOT_FOUND) {
        // If we couldn't find any plugins, quit gracefully,
        // returning an empty structure.
        return std::vector<std::unique_ptr<Base>>();
    }

    // Loop over every plugin in the folder and store in our
    // temporary return list
    do {
        // Define the function types for what we are retrieving
        typedef std::unique_ptr<Base> (__cdecl *ObjProc)(void);
        typedef std::string (__cdecl *NameProc)(void);
        typedef int (__cdecl *valueProc)(void);

        // Load the library
        HINSTANCE mod = LoadLibrary((R"(.\plugins\)" + std::string(fileData.cFileName)).c_str());

        if (!mod) {
            // Couldn't load the library, cleaning module list and quitting.
            for (HINSTANCE hInst : modules)
                FreeLibrary(hInst);
            throw std::runtime_error("Library " + std::string(fileData.cFileName) + " wasn't loaded successfully!");
        }

        // Get the function and the class exported by the DLL.
        // If you aren't using the MinGW compiler, you may need to adjust
        // this to cope with name mangling (I haven't gone into this here,
        // look it up if you want).
        ObjProc objFunc = (ObjProc) GetProcAddress(mod, "getObj");
        int ecode = GetLastError();
        NameProc nameFunc = (NameProc) GetProcAddress(mod, "getName");
        ecode = GetLastError();
        valueProc valueFunc = (valueProc)GetProcAddress(mod, "getValue");
        ecode = GetLastError();


        if (!objFunc || !nameFunc)
            throw std::runtime_error("Invalid Plugin DLL: both 'getObj' and 'getName' must be defined.");

        // push the objects and modules into our vectors
        ret.push_back(objFunc());
        modules.push_back(mod);

        std::clog << nameFunc() << " loaded!\n";
    } while (FindNextFile(fileHandle, &fileData));

    std::clog << std::endl;

    // Close the file when we are done
    FindClose(fileHandle);
    return ret;
}

int main() {
    // Our list of modules. We need this to properly free the module
    // after the program has finished.
    std::vector<HINSTANCE> modules;

    // Enter a block, to prevent the Base objects being
    // deallocated after the modules are freed (which will
    // cause your program to crash)
    {
        // The list of objectects that we will retrieve from the DLL's.
        std::vector<std::unique_ptr<Base>> objs;

        // Load the plugins using our function
        try {
            objs = getPlugins(modules);
        } catch (const std::exception& e) {
            std::cerr << "Exception caught: " << e.what() << std::endl;
            return 1;
        }

        // Call the 'print' function for out classes.
        // This is normally where you would implement
        // the code for using the plugins.
        for (auto& x : objs) {
            x->print();
            std::cout << "\t" << x->calc(10) << std::endl;
        }
    }

    // Program finishing, time to clean up
    for (HINSTANCE hInst : modules)
        FreeLibrary(hInst);

    return 0;
}

不想找的就直接到下面的链接下载VC++项目吧。

下载地址:VC++写的演示如何为应用程序写plugin插件的项目

https://download.csdn.net/download/tanmx219/12701204

posted @ 2020-08-10 13:21  SpaceVision  阅读(38)  评论(0编辑  收藏  举报