In addition to the answer already posted, I thought I should share a convenient trick that I use to load all the DLL functions into the program using function pointers, without creating a separate GetProcAddress call for each function. I would also like to call functions directly, like trying in the OP.
Start by defining a pointer type for a generic function:
typedef int (__stdcall* func_ptr_t)();
Which types that are used are not very important. Now create an array of this type, which corresponds to the number of functions that you have in the DLL:
func_ptr_t func_ptr [DLL_FUNCTIONS_N];
In this array, we can store the actual function pointers pointing to the DLL's memory space.
The next problem is that GetProcAddress expects function names as strings. Therefore, create a similar array consisting of function names in the DLL:
const char* DLL_FUNCTION_NAMES [DLL_FUNCTIONS_N] = { "dll_add", "dll_subtract", "dll_do_stuff", ... };
Now we can easily call GetProcAddress () in a loop and save each function inside this array:
for(int i=0; i<DLL_FUNCTIONS_N; i++) { func_ptr[i] = GetProcAddress(hinst_mydll, DLL_FUNCTION_NAMES[i]); if(func_ptr[i] == NULL) {
If the cycle was successful, the only problem we have now is function calls. The typedef function pointer from earlier does not help, because each function will have its own signature. This can be solved by creating a structure with all types of functions:
typedef struct { int (__stdcall* dll_add_ptr)(int, int); int (__stdcall* dll_subtract_ptr)(int, int); void (__stdcall* dll_do_stuff_ptr)(something); ... } functions_struct;
And finally, to associate them with the array earlier, create a union:
typedef union { functions_struct by_type; func_ptr_t func_ptr [DLL_FUNCTIONS_N]; } functions_union;
Now you can load all functions from the DLL using a convenient loop, but name them through the by_type member.
But of course it's a little burdensome to type something like
functions.by_type.dll_add_ptr(1, 1); whenever you want to call a function.
As it turned out, it was for this reason that I added the "ptr" postfix to the names: I wanted them to be different from the actual function names. Now we can smooth out the icky struct syntax and get the names we need using some macros:
#define dll_add (functions.by_type.dll_add_ptr) #define dll_subtract (functions.by_type.dll_subtract_ptr) #define dll_do_stuff (functions.by_type.dll_do_stuff_ptr)
And now you can use function names with the correct type and parameters, as if they were statically linked to your project:
int result = dll_add(1, 1);
Disclaimer: Strictly speaking, conversions between different function pointers are not defined by the C standard and are unsafe. Formally, what I'm doing here is undefined behavior. However, in the Windows world, function pointers always have the same size regardless of type, and conversions between them are predictable in any version of Windows that I used.
In addition, there could theoretically be an addition added to union / struct, which will cause everything to fail. However, pointers are the same size as the alignment requirement in Windows. A static_assert , to ensure that struct / union is not indented, may still be in order.