C++ C++;将任意函数从DLL动态加载到std::function

C++ C++;将任意函数从DLL动态加载到std::function,c++,dll,c++11,dllexport,std-function,C++,Dll,C++11,Dllexport,Std Function,如何使用单个函数将任意动态链接库(dll)函数加载到std::function对象中 例如,我想将两个函数编译成一个dll: // test.dll int plusFive(int value) { return value + 5; } void printHello() { std::cout << "Hello!" << std::endl; } //test.dll 整数加五(整数值){ 返回值+5; } void printHello()

如何使用单个函数将任意动态链接库(dll)函数加载到
std::function
对象中

例如,我想将两个函数编译成一个dll:

// test.dll

int plusFive(int value) {
    return value + 5;
}

void printHello() {
    std::cout << "Hello!" << std::endl;
}
//test.dll
整数加五(整数值){
返回值+5;
}
void printHello(){
std::cout使用
windows.h
中提供的WinAPI函数(描述取自)

  • LoadLibrary
    -将指定模块加载到调用进程的地址空间。返回模块的句柄
  • GetProcAddress
    -从指定的动态链接库(DLL)检索导出函数或变量的地址。返回导出函数或变量的地址
使用此函数加载特定函数并返回
std::function
对象:

// main.cc

#include <iostream>
#include <string>
#include <functional>
#include <windows.h>

template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
    // Load DLL.
    HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());

    // Check if DLL is loaded.
    if (hGetProcIDDLL == NULL) {
        std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    // Locate function in DLL.
    FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());

    // Check if function was located.
    if (!lpfnGetProcessID) {
        std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    // Create function object from function pointer.
    std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));

    return func;
}
输出:

Result of func1: 6
Hello!
作为旁注,DLL可以使用GCC(4.7.2)编译,如下所示:

// main.cc

#include <functional>

int main() {
    std::function<int(int)> func1(loadDllFunc("test.dll", "plusFive"));
    std::function<void()> func2(loadDllFunc("test.dll", "printHello"));
}
// test.cc (test.dll)
#include <iostream>

// Declare function prototypes with "extern C" to prevent name mangling.
// Declare functions using __declspec(dllexport) to signify the intent to export.
extern "C" {
    __declspec(dllexport) int __stdcall plusFive(int);
    __declspec(dllexport) void __stdcall printHello();
}

int plusFive(int value) {
    return value + 5;
}

void printHello() {
    std::cout << "Hello!" << std::endl;
}
// main.cc

int main() {
    auto func1 = loadDllFunc<int(int)>("test.dll", "plusFive");
    auto func2 = loadDllFunc<void()>("test.dll", "printHello");

    std::cout << "Result of func1: " << func1(1) << std::endl;
    func2();
}
g++ -shared -o test.dll test.cc -std=c++11
编辑: 我不确定强制转换
loadDllFunc
是否提供了正确的类型:

std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));

当您使用完函数指针时,您忘记了
freellibrary
。@beerboy事实上,一开始我在
loadDllFunc
的末尾包含了对
freellibrary
的调用,就在返回
std::function
之前。这起到了作用,返回的函数即使DLL已卸载,也是有效的。我不知道为什么要这样做虽然不起作用,但我确实删除了对
FreeLibrary
的调用。此外,根据本文中的帖子,可能没有必要调用
FreeLibrary
,因为DLL应该在退出时自动卸载。此外,DLL中函数的调用约定被定义为
\uu stdcall
,但它们不是在main.cc.Edit中导入时定义为这样:很抱歉,u stdcall错误不在main.cc中,实际上无法在那里修复-问题是loadDllFunc中的reinterpret_cast:
reinterpret_cast(lpfngetprocesid);
FARPROC
投射到函数指针
R(*)(..)
而不是
R(u stdcall*)(..)
@beerboy没有看到这一点。我编辑了
重新解释演员阵容
以包含正确的呼叫约定。我认为这解决了问题。谢谢!
template <typename T>
struct TypeParser {};

template <typename Ret, typename... Args>
struct TypeParser<Ret(Args...)> {
    static std::function<Ret(Args...)> createFunction(const FARPROC lpfnGetProcessID) {
        return std::function<Ret(Args...)>(reinterpret_cast<Ret (__stdcall *)(Args...)>(lpfnGetProcessID));
    }
};

template <typename T>
std::function<T> loadDllFunc(const std::string& dllName, const std::string& funcName) {
    // Load DLL.
    HINSTANCE hGetProcIDDLL = LoadLibrary(dllName.c_str());

    // Check if DLL is loaded.
    if (hGetProcIDDLL == NULL) {
        std::cerr << "Could not load DLL \"" << dllName << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    // Locate function in DLL.
    FARPROC lpfnGetProcessID = GetProcAddress(hGetProcIDDLL, funcName.c_str());

    // Check if function was located.
    if (!lpfnGetProcessID) {
        std::cerr << "Could not locate the function \"" << funcName << "\" in DLL\"" << dllName << "\"" << std::endl;
        exit(EXIT_FAILURE);
    }

    // Create function object from function pointer.
    return TypeParser<T>::createFunction(lpfnGetProcessID);
}