How can I load an arbitrary dynamic-link library (dll) function into a std::function
object using a single function?
For example I would like to compile two functions into a dll:
// test.dll
int plusFive(int value) {
return value + 5;
}
void printHello() {
std::cout << "Hello!" << std::endl;
}
And load them both at runtime using a single function like this:
// main.cc
#include <functional>
int main() {
std::function<int(int)> func1(loadDllFunc("test.dll", "plusFive"));
std::function<void()> func2(loadDllFunc("test.dll", "printHello"));
}
GetProcAddress verifies that the specified ordinal is in the range 1 through the highest ordinal value exported in the . def file. The function then uses the ordinal as an index to read the function's address from a function table.
LoadLibrary can be used to load a library module into the address space of the process and return a handle that can be used in GetProcAddress to get the address of a DLL function. LoadLibrary can also be used to load other executable modules.
Use the WinAPI functions provided in windows.h
(descriptions taken from MSDN Dev Center).
LoadLibrary
- Loads the specified module into the address space of the calling process. Returns a handle to the module.GetProcAddress
- Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL). Returns the address of the exported function or variable.Use this function to load a specific function and return a std::function
object:
// 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;
}
The DLL source should be written like this:
// 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;
}
And then use loadDllFunc
like this:
// 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();
}
Output:
Result of func1: 6
Hello!
As a sidenote the DLL can be compiled using GCC (4.7.2) like this:
g++ -shared -o test.dll test.cc -std=c++11
I'm not sure that the cast in loadDllFunc
gives the correct type:
std::function<T> func(reinterpret_cast<__stdcall T*>(lpfnGetProcessID));
It seems to cast it to __stdcall int (*)(int)
when it should be int (__stdcall *)(int)
.
Here is another way to implement loadDllFunc
using an auxiliary parser class. This solution will correctly cast the function pointer to 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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With