4

I feel like there's a much, much better way than just having hundreds of signatures in typedefs, and then loading pointers by GetProcAddress. As far as I know, it is the easiest -- but dirty -- when it comes to loading DLL functions.

Is there a less messy way to load DLL functions? Specifically, a large amount of Winapi and Tool Help library functions? I know you can just "include a .lib," but I feel like that would cause unnecessary bloat; nor do I have access to the source code (although Jason C mentioned it is possible to go from a .dll to a .lib).

I was looking to code a library for this. I feel like the major roadblock is dealing with functions that have varying signatures; or is this precisely the reason why everyone uses typedefs instead of "some fanciful loop" to load their DLL functions?

9
  • 3
    The only reason to use GetProcAddress is if you need to make runtime decisions about what library to load (i.e. if you have multiple choices, plugins, or if the library isn't guaranteed to exist). Otherwise, you should use a .lib and let the system take care of library loading and linking. Commented Aug 3, 2013 at 4:24
  • 1
    @Saustin what makes you say import library would cause unnecessary bloat? All it is is a stub to help the linker fix up export symbols to dlls. And the linker won't pull in unnecessary symbols if none of the object files reference them. Commented Aug 3, 2013 at 4:29
  • 2
    So you're loading Windows API functions? Why not just link them with a .lib like every other person does? The function signatures are already in Windows.h! Commented Aug 3, 2013 at 4:32
  • 1
    That's odd. I mean, there are certainly a fair share of Windows API functions that you do need to explicity load, but every reference to CreateTool32Snapshot that I can find suggests that it is defined in kernel32.lib and declared in tlhelp32.h and supported from XP through 8. I've never used CreateTool32Snapshot so I'm not sure, but in my experience Microsoft is generally accurate when it comes to describing special considerations like that. Commented Aug 3, 2013 at 5:20
  • 2
    I should add that CreateTool32Snapshot doesn't exist.. it was a typo that I seriously overlooked. CreateToolhelp32Snapshot is the correct API. Additionally, TlHelp32.h must be declared after Windows.h. Note to self: go to sleep next time. Commented Aug 3, 2013 at 6:04

6 Answers 6

3

Your functions have to be declared somehow, so you need the function signatures. But, if you feel you are duplicating the function signatures, you can use decltype(&func_name) to eliminate that duplication (given a function func_name with the same target signature). You can wrap that in a macro to make it more palatable.

Another common approach is to shove all the function pointers into one big struct (or a bunch of task-specific structs), and load a pointer to the struct instead (e.g. by loading a function that returns a pointer to the struct). This looks like the following:

Common header

struct func_table { void (*f1)(int); int (*f2)(void); }; 

DLL

static struct func_table table = { &f1_Implementation, &f2_Implementation, }; DLLEXPORT struct func_table *getFuncTable(void) { return &table; } 

Program using the DLL

static struct func_table *funcs; void loadFuncTable() { struct func_table (*getFuncTable)(void) = GetProcAddress(..., "getFuncTable"); funcs = getFuncTable(); } /* call funcs->f1(n) and funcs->f2() */ 
Sign up to request clarification or add additional context in comments.

9 Comments

Either I am clearly overlooking something, or the use of a function table would require me to have access to the source code of the DLL! There is no way to implement that in a compatible fashion for me.
I should have made that clear, I have updated my question. Sorry.
It is unfortunate that the poster did not specify that he didn't have the source, because the function table struct is a good approach. You still need signatures somewhere, but it will save you GetProcAddress calls.
One issue worth pointing out, though, with the function table, is that if you add/remove functions in the DLL but want to maintain binary compatibility, you must add new functions to the end of the table, and if you remove functions you must replace them with a placeholder in the table of equal size (e.g. just leave them and set them to NULL). An import library is immune to changes in the DLLs export list, but a function table must be carefully maintained through that. A further measure of protection, which Win API uses frequently, is to specify the size of the struct to the DLL.
It's a general failsafe when passing structs to/from DLLs. Microsoft does it frequently in API calls although I can't think of any examples off the top of my head. Using the above example, if getFuncTable() took the size of the struct as a parameter, or if the struct had a member that you set to the size before calling, the DLL can then determine if your application was designed for a different version of the DLL by verifying the struct size is equal to what is expected, and taking appropriate actions otherwise (e.g. if struct shrunk in future version, only copy the first X bytes).
|
2

The "bloat" of linking to a .lib file (by "bloat" I'm presuming you mean a few extra kB on the executable, which, ya know...) isn't "unnecessary" if you're using it for the convenience of avoiding dealing with hundreds of GetProcAddress calls. :)

Not quite sure what you mean by "some fanciful loop"; the typedefs used in this context serve a similar purpose to declarations in a header -- they provide the compiler and the human reader information about the signature of the function that is being called. One way or another, you have to provide this.

There are tools out there to generate a .lib from a .dll; but you'll still have to have a header declaring the functions you are calling so that the compiler knows what you're doing. Essentially, a .lib generated for a .dll is just a "stub" that loads the DLL and gets the function addresses for you. Different API, but essentially the same.

The only way around it is to design your DLL interface differently so that you don't have as many functions to deal with. However, in most cases I would not say that avoiding typedefs/declarations for functions is sufficient motivation to do something like this. E.g. you could expose exactly one function like (for example):

void PerformAction (LPCSTR action, DWORD parameter); 

And have your implementation of PerformAction do something different depending on "action". That is certainly reasonable in certain situations that are unrelated to your post, but it is not really an appropriate "workaround" for the "problem" you are describing.

You pretty much just have to deal with it. Either create a header with declarations and generate a stub .lib, or create a header with typedefs and use LoadLibrary/GetProcAddress. The former will save you some typing. The latter lets you handle cases where the DLL is not present, or load DLLs that are unknown at design time (e.g. plugins as mentioned in another answer).

7 Comments

Interesting, I knew .libs contained code but I had no idea there were tools to derive them from DLLs -- nor did I know they were a cheap stub. As for your explanation with PerformAction, I do feel like that would be a better way to load specifics, rather than dropping all GetProcAddress calls at once.
With MSVC there is an intermediate step of creating a .def file, but you can do it straightforwardly by using dumpbin.exe to list the symbols. Then you can use lib.exe to generate the import library from the .def file (you don't actually need the DLL at all to do this, only the .def). Under MinGW you can use dlltool instead of lib.exe.
I had no idea there was a MSVC tool like lib.exe, I will try this right away.
It's traditionally used for exactly this purpose - creating import libraries for DLLs. If you are writing a DLL and you wanted to generate the stub LIB as well when you compiled it, you would create a .def file listing the functions it exports, and tell the linker to create the import library for you. There are other things you can put in that file: msdn.microsoft.com/en-us/library/28d6s79h%28v=vs.80%29.aspx . As an alternative you can use __declspec(dllexport) (an MSVC extension) on your functions instead: msdn.microsoft.com/en-us/library/a90k134d%28v=vs.80%29.aspx
Thank you for your help, you have cleared up a large number of (common?) misconceptions I had with this subject. A "few extra kB" on my executable doesn't sound that bad anymore.. but as with TlHelp32.h, sometimes you may have to "just deal with it."
|
2

Visual C++ has an option to delay load a DLL. Your code you links in the DLL's lib file, includes its headers, and call the functions as normal. The Visual C++ linker and runtime take care of calling LoadLibrary() and GetProcAddress() the first time a function is called.

However this will cause a runtime exception if the DLL cannot be loaded for any reason, rather than causing your application to fail to load as with a normally linked DLL.

If this DLL is always loaded and required by your application to run, then you should like to the DLL normally (using the .lib file). In that case you are gaining nothing by delay loading the DLL in that case.

7 Comments

Interesting.. so would this mean the only way to have to have the DLL load would be inside of the path? It seems to me this is done on a call to WinMain/main -- meaning there would be no way to say "Hey, load THIS dll from this file -- not that one!" That is, unless you coded some wrapper executable which placed the DLLs for you.
@Saustin if the DLL is not in the DLL search path then you can still handle it by calling LoadLibary() yourself in the dliStartProcessing notification and returning the HMODULE. msdn.microsoft.com/en-us/library/z9h1h6ty.aspx
This feels like the right path, but I feel rather confused -- am I using a notification hook to update the processes' address table, or is this done for me on load? I may have to tinker with this one a bit.
@Saustin - all you need to do is call LoadLibary with the correct path to manually load the DLL. After than the runtime will handle loading the DLL's functions for you.
I see -- so the main advantage with this method is the ability to control which DLL is loaded when? I am aware this still requires linking the .lib but I am rethinking using static library links as well.
|
2

There are several different ways of loading Windows libraries, but each way serves a different purpose.

Using LoadLibrary() and GetProcAddress() manually is intended to allow runtime decisions about several different dynamic linking situations. These calls are simply system calls which do not affect any aspect of the resulting PE file whatsoever, and the addresses returned by GetProcAddress() are not special in any manner with regards to code generation. This means that the caller is responsible for properly use these symbols at the very syntactical level (for example, using the proper calling convention and the correct number, size and alignment of the arguments, if any, for a function call).

Linking against a .lib file associated with a .dll is different. The client code refers to the runtime content using external identifiers, as if they were statically linked symbols. During the build process, the linker will resolve these identifiers with the symbols found in the .lib file. While, in principle, these symbols could point to anything at all (as any other symbol could), an automatically generated .lib file will simply provide symbols which act as tiny proxies to the memory content that will be filled at load time by the PE loader.

The manner in which these proxies are implemented is dependent on the type of memory access expected. For example, a symbol which refers to a function in the .dll will be implemented as a single indirect jmp instruction, in such a way that the original call instruction from the client code will hit the jmp instruction from the .lib content and will be forwarded to an address resolved by the PE loader at load time. At this address reside the dynamically loaded function's code.

Many more details aside, all of this is used to instruct the PE loader to do the same job as the client code would do by itself: call LoadLibrary() to map a PE into memory and dig through the export tables with GetProcAddress() to find and calculate the proper address to every needed symbol. The PE loader does this automatically at load time from the information found in the import table of the client executable.

In other words, load-time dynamic linking is slower and fatter than run-time dynamic linking by the tiniest amount, if any, but it is intended to provide a much simpler programming interface to the ordinary developer, specially because many libraries are always required and always available. Attempting to provide any additional logic through manual loading is not useful in these circumstances.

Summarizing, do not bother to use LoadLibrary() and GetProcAddress() just because they seem to provide more performance or robustness. Link against .lib files whenever possible.

Going further on the topic, it is even possible to create PE images which don't contain any import tables at all (and can still access system calls and other exported routines). This approach is used by malware to hide suspicious API usage (such as Winsock calls) by stripping any load-time information.

Comments

0

Creating a class as a wrapper of dll, where the public member function of the class are nothing but pointer to that of functions in dll obtained by get proc address would be one fine way to load functions from dll.

It would be better to use RAII ability of c++ to free libraries loaded by freeing libraries in destructors of the class.

This:

typedef int(WINAPI *ShellAboutProc)(HWND, LPCSTR, LPCSTR, HICON); int main() { HMODULE hModule = LoadLibrary(TEXT("Shell32.dll")); ShellAboutProc shellAbout = (ShellAboutProc)GetProcAddress(hModule, "ShellAboutA"); shellAbout(NULL, "hello", "world", NULL); FreeLibrary(hModule); } 

Can be achieved like this:

class ShellApi { DllHelper _dll{"Shell32.dll"}; public: decltype(ShellAboutA) *shellAbout = _dll["ShellAboutA"]; }; int main() { ShellApi shellApi; shellApi.shellAbout(NULL, "hello", "world", NULL); } 

Where the class DllHelper is:

class ProcPtr { public: explicit ProcPtr(FARPROC ptr) : _ptr(ptr) {} template <typename T, typename = std::enable_if_t<std::is_function_v<T>>> operator T *() const { return reinterpret_cast<T *>(_ptr); } private: FARPROC _ptr; }; class DllHelper { public: explicit DllHelper(LPCTSTR filename) : _module(LoadLibrary(filename)) {} ~DllHelper() { FreeLibrary(_module); } ProcPtr operator[](LPCSTR proc_name) const { return ProcPtr(GetProcAddress(_module, proc_name)); } static HMODULE _parent_module; private: HMODULE _module; }; 

All credits to Benoit

I can't find a more elegant way than this.

Comments

-1

There should be a function provided to load a dll manually given it's file name. In the windows API it's LoadLibrary(). It's generally not used unless you're developing a "plugin" style application or you need to manually control loading and unloading.

You should consider how your code will be used to determine if a static library or a dynamically loaded dll is the best solution for your requirements.

1 Comment

LoadLibrary loads the DLL into memory; GetProcAddress is still required to find the address of the function in question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.