VC++ write a project that demonstrates how to write plugin plug-ins for applications

If plugin is not needed, DLL is usually compiled directly into the project with lib. In this case, it is no different from ordinary function library calls.

But if you consider that in your own application, you want to allow anyone in the customer to add a plugin, then the situation is different.

Here (reference address: http://www.cplusplus.com/articles/48TbqMoL/ ) gives an example compiled with MINGW, but this example does not work on VC. I made a slight modification and made a note to make a VCC demo project. There are 3 cases in main.hpp,

(1) C program format of extern "C" __declspec(dllimport/dllexport)

(2) __declspec(dllimport/dllexport), which can call the program format of C++ class

(3) The form defined by *.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__

The main definition change is here, and the other content will not be explained. It is basically the same as the original post. It is actually very simple. For example, main.cpp only adds a test getValue function.

// 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;
}

If you don't want to find it, just go to the link below to download the VC++ project.

Download link: A project written in VC++ that demonstrates how to write a plugin plug-in for the application

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

Guess you like

Origin blog.csdn.net/tanmx219/article/details/107909758