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

Comments

  • Sr. SE

    Posted by 8Dmax on 03/05/2014 08:30am

    #define DLL_EXPORT should be in front of #include "DLL_Tutorial.h" in DLLTutorial.cpp.

    Reply
  • Confusing tutorial

    Posted by anonymous on 04/25/2013 12:08pm

    Well i find your tutorial really confusing ,, you talked about lot of stuffs and you did not make it easy for C juniors ,

    Reply
  • utility and dll

    Posted by on 01/24/2013 11:26pm

    Hi, i have one utility and have to automatically install the one dll to it. for that it need to ask about the utility compatibility like version and it also ask for the utility is pirate version or original version . if it is original version it need to ask for the identity and have to give the full access to it . otherwise some properties of dll has to be hidden…. then only it has to install on utility. give me some ideas to do it.

    Reply
  • utility and dll

    Posted by on 01/24/2013 11:25pm

    Hi, i have one utility and have to automatically install the one dll to it. for that it need to ask about the utility compatibility like version and it also ask for the utility is pirate version or original version . if it is original version it need to ask for the identity and have to give the full access to it . otherwise some properties of dll has to be hidden…. then only it has to install on utility. pls give me some ideas to do it.

    Reply
  • Re:

    Posted by icon-design on 09/13/2012 09:32pm

    You commit an error. I can prove it. Write to me in PM, we will communicate. P.S. Please review our icons for Windows and windows12icons.

    Reply
  • Implicit Linking Need Header Too?

    Posted by Cole Tran on 09/10/2012 11:22pm

    I thought implicit linking requires the header file as well, you only mentioned .dll and.lib in your explanation though. Is the header file required too?

    Reply
  • A great DLL tut

    Posted by Thanh on 08/23/2012 06:31pm

    I'm a control system student. As you know, in every controller chip, the library functions are in DLL/Lib files. When I try to write use a controller, so I need to know how to call theses functions in the dll files. So, your article teaches me how to do that. Thank you so much. Keep doing what you want!

    Reply
  • DLL examples

    Posted by karthik on 08/03/2012 04:13am

    This DLL tutorial is very simple and easy to understand. The example given in this is good. Thank you very much

    Reply
  • #define not acting like a #define

    Posted by Jason on 06/28/2012 09:57am

    I am using VS2010. The #define in DLLTutorial.cpp does not register in the DLLTutorial.h file. I have to specify the DLL_EXPORT preprocessor definitions in C/C++ - Preprocessor - Preprocessor Definitions. This seems rather strange to me. If you can think of something I am missing, please let me know! Thank you very much for the tutorial!

    • #define DLL_EXPORT

      Posted by Samuel on 10/08/2012 12:16am

      Hi, If you don't want to register the "#define DLL_EXPORT" in prepocessor you also, in this case, can moving it before the "#include "DLL_Tutorial.h" " Define the Export in preprocessor depend of the project. In this example the workspace (in case of VisualC++) has 1 project only, the dll, but in biggest project you can have workspace will several project, with some of them exporting library and other importing library, so using a preprocessor named "DLL_EXPORT" can be dangerous if you use the same preprocessor in each module of your workspace. But no misunderstanding, using the prepocessor definition in the example is perfectly fine. I just want to raise this possibility in case of some beginner are reading the example (because it has be made of them). Thanks!

      Reply
    • A few corrections

      Posted by Umair on 07/17/2012 11:05pm

      This tutorial is quite nice, but there are a few things that need to be updated or added. First of: HINSTANCE hInstLibrary = LoadLibrary("DLL_Tutorial.dll"); should be changed to HINSTANCE hInstLibrary = LoadLibrary(L"DLL_Tutorial.dll"); secondly, about the *.def file You need to create a *.def file, say "AllExports.def" in notepad and then adding it to the project. Put this code in it: LIBRARY dll_tutorial EXPORTS Add @1 Function @2 now you can build the project and get the dll. If you do not do this, then when you try to use _AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add"); you will always get a NULL value.

      • L in LoadLibrary

        Posted by Gitte Bager on 04/26/2013 08:33am

        Hi Joe, Your tutorial is really great and very appreciated. Thank you. Concerning the addition of the L to the LoadLibrary, i.e. HINSTANCE hInstLibrary = LoadLibrary(L"DLL_Tutorial.dll"); - I agree with Umair. I just ran your DLL_Src and DLLTest_Src in Visual Studio Express 2012 (Desktop) - and I needed to add the "L" as well. Guessing that it depends on what compiler is being used. Anyway thanks for posting.

        Reply
      Reply
    Reply
  • DLL LoadLibrary

    Posted by Daniel on 06/13/2012 12:26am

    I have problems to load a .dll I downloaded a .dll called nsMCDLibrary.dll and I created a folder in C:/Neuroshare and I saved it here. I add the folder path to my path environment variable. And I checked dependencies with dependency walker Now, I have a C++/Qt program where I do this: char *libname = "nsMCDLibrary.dll"; HINSTANCE h = LoadLibrary((WCHAR*)libname); Then h = 0 and GetLastError = 126 If I do this WCHAR *libname = L"nsMCDLibrary.dll"; HINSTANCE h = LoadLibrary(libname); Then h = 268435456 and GetLastError = 127 I don´t know where is the problem. Could you help me? Or Could you say me anything that I have to check? Thank you, Daniel.

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds