And more importantly, why would anybody do it?
This article contains Windows programming code and C++ code of moderate to high complexity.
Why loading dynamically a dll and calling a function from it?
Among other things, because you do not need a header file. You do not need to find it, use it and potentially “fight” with issues some other completely unrelated stuff in the same header, might do to your project.
That is a simple use case. And here is more reasons you will want DLL dynamic loading.
You have written some snazzy C++ and you are very proud of it. Being C++ it might be some deep system “mumbo-jumbo” that you have been amazed about. And every good deep system “mumbo-jumbo” does not require Graphical User Interface (aka GUI). After all, you are a system programmer and your code runs on servers! But it does requires some way of signalling to its human administrator’s servants, and you have decided you want it to release sounds! Like squeaking when not well, that sort of a thing.
OK. Of to yet another masterful dollop of (server side) C++. There is kernel32.dll and yes, there is a WIN32 function called Beep() in there. Nothing easier than using it. Bam! Done!
This is where I stop you, my dear C++ sorcerer.
Think. Your C++ code produces very small and fast and perhaps useful and invisible Windows program. The last thing you want to do it is to start including DLL’s in its build. Why?
Including DLL’s in a build means your program will need to make sure (at startup time) each of these DLL’s is found and then loaded into memory. And each of them, like kernel32.dll, will do the same for itself with a myriad of other DLL’s it depends on. And so on with those other dll’s. This is called “DLL Dependency Tree”
All of a sudden the file size and the memory footprint of your little, beep emanating C++ wonder, has grown. A lot. And you wanted “just” to call the Beep(), and very rarely at that.
This is why a concept of dynamically loading (Windows) dll’s has been invented. This is the sequence of activities it is made of:
- Load a dll
- Ask it (nicely) for a function you need
- Call a function
- Unload the library. (This is a crucial step)
By now I am sure, you might have lost all the patience and are about to leave, and copy paste next C++ code from somewhere. This is why I have made this little DBJDBJ tool, to do the dynamic loading of Windows dll’s.
Basically, there is one function that does it all. For it to be used you need three things
- the dll name
- the function name
- the function signature
// the Beep function signature
typedef BOOL(*BeepFP) (DWORD, DWORD);
// load the dll + get the function
BeepFP fp = dbj::win::funload(
// third argument if true means 'system dll is required'
// just use it
dll will be properly unloaded when it’s holder goes out of scope. For the fancy test unit please look into test.cpp.
To start the dll dynamic loading, one needs to know where is it, and give the full path to the dll location.
For understanding the “finding rules” please read the article here. Note: we are using
LoadLibrary() and not the
LoadLibraryEx(). Why? Primarily because we want to enforce the usage policy: “Keep it simple”.
We obviously could provide more functionality and make everything more complex. I suggest that small percentage of readers needing the extended functionality, take this code and extends it.
You need to declare a proper function pointer to the Beep(). Now. You are a C++ sorcerer (I hope) and you need no lecture on function pointers. OK. You go to MSDN and find the declaration of the Beep (mildly interesting not a dry text) and from there you declare a proper pointer to it:
Parameter dwFreq, specifies the frequency,
in hertz, of the sound.
This parameter must be in the range
37 through 32767 (0x25 through 0x7FFF).
Thus the funciton pointer declaration to the Beep() is:
typedef BOOL ( * BeepFP ) ( DWORD , DWORD ) ;
Thus we have the BeepFP and we can now use it, as one can see in the test code.
The full working code is here. I am sure you know what is testing code and what is a library code in there. Hint: The lib is all in one header. It is made with 2017 Community Edition of Visual Studio. It uses standard C++17.
Any questions, or bugs, fire away and ask.