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