DLL Tutorial For Beginners

I was trying to learn DLLs and nothing was really explaining anything; it was just code for you to look at and wonder what was going on. For this article, I assume you know how to use the features of your compiler, such as setting directory paths and such.

To set up the project, select Win32 Console Application, and on the advanced tab, select DLL and empty project options. DLLs are not as hard as you might think they are. First, make your header file; call this DLLTutorial.h. This file is like any other header file in that it has function prototypes.

#ifndef _DLL_TUTORIAL_H_
#define _DLL_TUTORIAL_H_
#include <iostream>

#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

extern "C"
{
   DECLDIR int Add( int a, int b );
   DECLDIR void Function( void );
}

#endif

The first two lines instruct the compiler to include this file only once. The extern "C" tells the compiler that it is okay to use this in C or C++.

There are two ways of exporting functions in VC++:

  1. Use __declspec, a Microsoft-specific keyword.
  2. Create a Module-Definition File (.DEF). The first way is a tad bit easier to do than the second, but both work just fine.

__declspec(dllexport) exports the function symbols to a storage class in your DLL. I defined DECLDIR to do this function when the line

#define DLL_EXPORT

is defined, but also import the functions if the line

#define DLL_EXPORT

is not present in the source file(s). In this case, you will export the functions Add(int a, int b) and Function().

Now, you need to make a source file that you'll call DLLTutorial.cpp.

#include <iostream>
#include "DLL_Tutorial.h"

#define DLL_EXPORT

extern "C"
{
   DECLDIR int Add( int a, int b )
   {
      return( a + b );
   }

   DECLDIR void Function( void )
   {
      std::cout << "DLL Called!" << std::endl;
   }
}

This is where you define all of your functions. Int Add(int a, int b) simply adds two numbers and void Function(void) just informs you that your DLL was called.

Before I show you how to use the DLL, I want to tell you about the Module-Definition File (.def).

Module-Definition File (.def)

A module definition file is a text file with a .def extension. It is used to export the functions of a DLL, much like __declspec(dllexport), but the .def file is not Microsoft specific. There are only two required sections in a .def file: LIBRARY and EXPORTS. Take a look at a basic .def file and then I'll explain.

LIBRARY dll_tutorial
DESCRIPTION "our simple DLL"
EXPORTS
   Add @1
   Function @2

The first line, 'LIBRARY', is one of the required sections. This tells the linker what to name your DLL. The next section labeled 'DESCRIPTION' is not required, but I like to put it in. It writes the string into the .rdata [from MSDN] and it tells people who might use the DLL what it does or what it's for. The next section labeled 'EXPORTS' is the other required section; this section makes the functions available to other applications and it creates an import library. When you build the project, not only is a .dll file produced, but an export library is produced with the extension .lib. In addition to the previous sections, there also are four other sections labeled NAME, STACKSIZE, SECTIONS, and VERSION. I will not cover these in this tutorial. but if you search the Internet, I think you'll find something. One more thing: A semicolon (;) starts a comment, as '//' does in C++.

Now that you have created your DLL, you need to learn how to use it in an application. When the DLL was built, it created a .dll file and a .lib file; you will need both.

Implicit Linking

There are two ways to load a DLL; one way is the easy route and the other is more complicated. The easy route is just linking to your .lib file and putting the .dll file in your new projects path. So, create a new Empty Win32 Console project and add a source file. Put the DLL you made in the same directory as your new project.

#include <iostream>
#include <DLLTutorial.h>

int main()
{
   Function();
   std::cout << Add(32, 58) << "\n";
   return(1);
}

You must link to the DLLTutorial.lib file. I did it in Project Settings, but you could use

#pragma comment(lib, "DLLTutorial.lib")

instead. Please note that I set the compiler to look into my DLL folder for the .lib file and set it to look in the directory for the DLL header. If you don't want to do this, you can always put them in the directory with your new project and use "" (quotes) instead of <>. That's how you load a DLL the easy way.

Explicit Linking

The harder way to load a DLL is a little bit more complicated. You will need function pointers and some Windows functions. But, by loading DLLs this way, you do not need the .lib or the header file for the DLL, only the DLL. I'll list some code and then explain it.

#include <iostream>
#include <windows.h>

typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();

int main()
{
   AddFunc _AddFunc;
   FunctionFunc _FunctionFunc;
   HINSTANCE hInstLibrary = LoadLibrary("DLL_Tutorial.dll");

   if (hInstLibrary)
   {
      _AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");
      _FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary,
         "Function");

      if (_AddFunc)
      {
         std::cout << "23 = 43 = " << _AddFunc(23, 43) << std::endl;
      }
      if (_FunctionFunc)
      {
         _FunctionFunc();
      }

      FreeLibrary(hInstLibrary);
   }
   else
   {
      std::cout << "DLL Failed To Load!" << std::endl;
   }

   std::cin.get();

   return 0;
}

The first thing you'll notice is that you included the file "windows.h" and removed "DLL_Tutorial.h". The reason is simply because Windows.h contains many Windows functions and you will need only a few right now. It also contains some Windows-specific variables that you will use. You can remove the DLL's header file (DLL_Tutorial.h) because, as I've stated before, you don't need it when you load DLLs this way.

The next thing you'll notice is an odd-looking piece of code in the form of:

typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();

Those are function pointers. Because this is a tutorial about DLLs, an in-depth look at function pointers is out of the scope of this tutorial; so, for now just think of them as aliases for the functions the DLL contains. I like to name them with the word "Func" attached on the end. The (int,int) part is the parameters that the function takes; for example, the Add function takes in two ints; therefore, you need those as the parameters for the function pointer. The Function function takes no parameters, so you can leave that blank. The first two lines in main() are the function pointers being declared so that you can set them equal to the functions inside the DLL. I just like to define them beforehand.

An HINSTANCE is a Windows dat type that is a handle to an instance; in this case, that instance will be the DLL. You get the instance of the DLL by using the LoadLibrary() function; it takes in a name as the parameter. After the call to LoadLibrary, you must check to see whether the function succeeded. You can do so by checking whether the HINSTANCE is equal to NULL (defined as 0 in Windows.h or one of the headers Windows.h includes). If it is equal to NULL, the handle is not valid, and you must free the library. In other words, you must free up the memory that the DLL was taking up. If the function succeeded, your HINSTANCE contains the handle to the DLL.

Once you have the handle to the DLL, you now can retrieve the functions from the DLL. To do that, you must use the GetProcAddress() function, which takes in as parameters the handle to the DLL (you can use the HINSTANCE) and the name of the function. You set the function pointers to contain the value returned by GetProcAddress() and you must cast GetProcAddress() to the function pointer that you defined for that function. For example, for the Add() function, you must cast GetProcAddress() to AddFunc; this is so that it knows the parameters and return type. Now, it would be wise to make sure that the function pointers are not equal to NULL and that they hold the functions of the DLL. That is just a simple if statement; if one of them does equal NULL, you must free the library as mentioned above.

Now that the function pointers hold the functions of the DLL, you can use them, but there is one catch: You cannot use the actual function name; you must use the function pointer to call them. After that, all you need to do is free the library and that's it.

Now you know the basics of DLLs. You know how to create them, and you know how to link them with two different methods. There is still more to learn about this, but I'll leave that to you to look for and for better writers to write.



About the Author

Joe P.

I love to play guitar, and I love to program. Thats it, my life is boring. :)

Downloads