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++项目吧。