• entries
    146
  • comments
    436
  • views
    197730

Dynamic Link Libraries

Sign in to follow this  

304 views

Interfaces vs Classes
You may be wondering why I'm not exporting a class from the DLL, but instead using an interface. The reason is simple: Exporting a class from a DLL is an error prone and less than clean means of providing access to an object contained in a DLL. Furthermore, one of the key concepts of OOP is the use of abstractions to reduce dependencies. By providing an interface in stead we allow the actual implementation of the class to be changed or upgraded, just as long as the interface stays the same. There is also the issue of portability. Most compilers know how to deal with an interface, and those that don't usually have extensions to the calling conventions that you can specify that will enable it to work with interfaces provided by another compiler. COM, for instance, uses interfaces and almost any compiler in existence today (that compiles for the Win32 platform) can use COM. I should note that COM uses the stdcall calling convention by default, while the code presented here is not.

Using the DLL - Static Linkage
Statically linking to a DLL simplifies the job of the programmer somewhat. Basically, when you compile the DLL you will note that a library file is also generated. This library file contains code to load the DLL into memory and also provides a symbol map of the exported functions provided by the DLL. This saves you some work in having to manually import the DLL and getting the addresses of the methods within the DLL.

You just add the library file to the link stage of your application, and make sure that the DLL is available in to the application by placing it in one of the searched paths (which includes the application startup directory). From that point on you can call the functions of the DLL as though they were part of your code. Common examples of this includes making calls to C functions, OpenGL, and DirectX.

#include "../SimpleDLL/Simple.h"

int main() {
IStrange* s = GetStrange();
s->PrintString(s->GetName());
s->Release();
}


Simple eh?

Using the DLL - Dynamic Linkage
Dynamically linking to a DLL requires that you manually load and unload the DLL. It also requires that you manually obtain the addresses of the exported functions that the DLL provides. Of course, there are reasons to use dynamic linkage, but we'll get to those in a bit. As far as overhead goes, there is no difference between static and dynamic linkage.

With dynamic linkage you don't need to add the library file to your build stage. The following code provides a wrapper that nicely cleans up the process of loading and unloading a DLL, along with obtaining the pointers to the exported functions.

#ifndef LIBRARY_15AA5FAF_2162_4fb5_81D8_ECFB57234538
#define LIBRARY_15AA5FAF_2162_4fb5_81D8_ECFB57234538

#define WIN32_LEAN_AND_MEAN
#include

class Library {
public:
explicit Library(std::string const& file) {
dll_ = LoadLibrary(file.c_str());
if(!dll_)
throw std::runtime_error("Unable to load library " + file);
}
~Library() {
if(dll_)
FreeLibrary(dll_);
}

template
T GetFunction(std::string const& name) {
T f = reinterpret_cast(GetProcAddress(dll_, name.c_str()));
if(!f)
throw std::runtime_error("Unable to load function " + name);
return f;
}
private:
HMODULE dll_;
};

#endif


You will note that the code that uses that utility class also uses the typedef that we provided in the header file ('Simple.h'). I've found that it is usually helpful to provide such typedefs, in case the programmer that uses the library does need to dynamically load it.

#include

#include "../SimpleDLL/Simple.h"
#include "Library.h"

int main() {
try {
Library strangeDll("SimpleDLL");
GetStrangeSignature GetStrange = strangeDll.GetFunction("GetStrange");

IStrange* s = GetStrange();
s->PrintString(s->GetName());
s->Release();
} catch(std::runtime_error& error) {
std::cout< }
}



Static vs Dynamic linkage
So why would you want to use Dynamic linkage when it appears to be more work? Well, lets imagine a simple scenario: You have two driver DLLs, one provides OpenGL functionality, while the other provides Direct3D functionality. When the application launches, you read a configuration file which determines the driver you will use. In this case, static linkage would be a poor choice, as you will end up having both libraries in memory, even though you will only use one of them. Dynamic linkage, however, will allow you to load up the library you want when you want it. You can then use that library as you will. If the user should later change which one he wishes to use (by going to options and changing it) you can unload that library and load up the other one.

On the other hand, if you were to provide a library of functionality that wouldn't need to be swapped out for another (such as a physics library), then using static linkage would be beneficial. In that case the added work of loading and managing the library comes at no extra gain, and hence is not worth the effort.
Sign in to follow this  


7 Comments


Recommended Comments

Very nice set of entrys, Washu. I'm still a little sketchy on some of the dynamic linkage code (I'm not used to more advanced C++ code), but I get the general idea.

Share this comment


Link to comment
Quote:
Well, lets imagine a simple scenario: You have two driver DLLs, one provides OpenGL functionality, while the other provides Direct3D functionality. When the application launches, you read a configuration file which determines the driver you will use. In this case, static linkage would be a poor choice, as you will end up having both libraries in memory, even though you will only use one of them. Dynamic linkage, however, will allow you to load up the library you want when you want it. You can then use that library as you will. If the user should later change which one he wishes to use (by going to options and changing it) you can unload that library and load up the other one.

I kind of disagree here - memory usage is hardly an issue. Especially given that the DLLs won't be that large most of the time.

A better scenario, IMO, is when you're loading plugins. You can't know beforehand what plugins will be there, so you can't use static linkage (because the windows loader will bark at you).

Share this comment


Link to comment
Quote:
Original post by that damn mod [grin]
I kind of disagree here - memory usage is hardly an issue. Especially given that the DLLs won't be that large most of the time.

A better scenario, IMO, is when you're loading plugins. You can't know beforehand what plugins will be there, so you can't use static linkage (because the windows loader will bark at you).

Like most examples, it's a contrived one. Examples should never be taken seriously, they are there to demonstrate a concept, not so much to demonstrate proper usage :P

Share this comment


Link to comment
Finally I get to nit-pick something :)


dll_ = LoadLibrary(file.c_str());



Will not compile in VS2005 right out of the box because of the error: cannot convert parameter 1 from 'const char *' to 'LPCWSTR'

Share this comment


Link to comment
This is because VS2005 defaults to having Unicode on. Not such a bad thing, but it does tend to make simple examples like this bork.

Share this comment


Link to comment
LoadLibraryA() will work. LoadLibrary() is actually a macro, which in VS2005 automatically defaults LoadLibraryW() instead. Another reason to use dynamic linkage is portability - Linux provides very similar .so loading functions, but has no support for static linking.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now