C ++ Динамически загружать произвольную функцию из DLL в std :: function

Как я могу загрузить произвольный библиотека динамических ссылок (DLL) функция в std::function объект, использующий одну функцию?

Например, я хотел бы скомпилировать две функции в DLL:

// test.dll

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

void printHello() {
std::cout << "Hello!" << std::endl;
}

И загрузите их оба во время выполнения, используя одну функцию, подобную этой:

// main.cc

#include <functional>

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

6

Решение

Использовать WinAPI функции, предусмотренные в windows.h (описания взяты из MSDN Dev Center).

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

Исходный код DLL должен быть написан так:

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

А потом использовать loadDllFunc как это:

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

Выход:

Result of func1: 6
Hello!

В качестве идентификатора DLL может быть скомпилирована с использованием GCC (4.7.2) следующим образом:

g++ -shared -o test.dll test.cc -std=c++11

Редактировать:

Я не уверен, что актеры в loadDllFunc дает правильный тип:

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

Кажется, это __stdcall int (*)(int) когда это должно быть int (__stdcall *)(int),

Вот еще один способ реализации loadDllFunc используя вспомогательный класс анализатора. Это решение будет правильно приводить указатель на функцию int (__stdcall *)(int),

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

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]