Creating And Using DLLs by (09 January 1999) | Return to The Archives

Introduction

So you're interested in making an oh-so-fashionable DLL? Well look no further. Creating a DLL is a lot easier than you probably think. DLLs (Dynamic Link Libraries) are very useful when you're writing windows programs. A good example use would be if you create a number of programs that all use common functions. In such a case, you can create a library that they all call functions from. Another interesting use would be to create plug-ins for your application. For example, a particular program I was working on in the past had plug-in renderers that were compiled as DLLs and loaded when the actual program ran. This document will attempt to show you how to create a basic DLL and how to use it (with import library linking and without). This document will not get into things such as sharing data, thread precautions, or resource libraries. We're just sticking to basic dll uses -- the rest you can experiment with on your own. Again, MSVC6 and the ide. Hopefully you shouldn't have too many problems w/conversions. Let's roll.

Creating The DLL

Creating a dll is nothing too far out. Basically, you write your functions then compile them almost like you would any other library. If you're using MSVC, create a new project and set the target as a Win32 Dynamic-Link Library. That way when you compile your code, it should produce a dll, an import library (.lib), and an export library (.exp). Here's some sample code that shows how the sample DLL included with this tutorial is put together:
Header File (dlltest.h):

     #ifndef _DLLTEST_H_
     #define _DLLTEST_H_

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

     extern "C" __declspec(dllexport) void NumberList();
     extern "C" __declspec(dllexport) void LetterList();

     #endif

Source File (dlltest.cpp):

     #include "dlltest.h"

     #define MAXMODULE 50

     char module[MAXMODULE];

     extern "C" __declspec(dllexport)

     void NumberList() {

           GetModuleFileName(NULL, (LPTSTR)module, MAXMODULE);

           cout << "\n\nThis function was called from "
                << module
                << endl << endl;

           cout << "NumberList(): ";

           for(int i=0;  i<10; i++) {

                cout << i << " ";
           }

           cout << endl << endl;
     }

     extern "C" __declspec(dllexport)

     void LetterList() {

           GetModuleFileName(NULL, (LPTSTR)module, MAXMODULE);

           cout << "\n\nThis function was called from "
                << module
                << endl << endl;

           cout << "LetterList(): ";

           for(int i=0;  i<26; i++) {

                cout << char(97 + i) << " ";
           }

           cout << endl << endl;
     }

Basically, there's nothing too special about the code above. The sample application is a console app, so I just wrote up two simple functions that display some text and tell you where they're being called from. The extern "C" __declspec(dllexport) means that we want to allow these functions to be used by our actual program. When you compile this thing, it should create the libraries. Now lets see how we actually use them.

Using the DLL (With an Import Library)

First lets look at how to use our DLL using the import library (dlltest.lib) that was one of the resulting files from compiling the DLL above. This method is the easiest because all you really have to do is include the header file, then include the import library when you're linking your objects. That's it. Here's an example:
DLL Test Source File (dllrun01.cpp) - Win32 Console Application:

     #include <conio.h>
     #include <dlltest.h>

     void main() {

           NumberList();
           LetterList();

           getch();
     }

The code above will work fine if you have your dlltest.h header file in your compiler's header path, and the dlltest.lib import library in the lib path. You also need to link your import library with your other modules when linking. Be warned though, when you run the resulting executable, the DLL must be in the path or in the same directory as the executable otherwise it will have an error. That's the whole point. But if you had 10 programs that use the same DLL, you can put one copy of the DLL in a common directory.
dllrun01.exe Output:

     This function was called from C:\DLLTEST\DLLRUN01.EXE

     NumberList(): 0 1 2 3 4 5 6 7 8 9

     This function was called from C:\DLLTEST\DLLRUN01.EXE

     LetterList(): a b c d e f g h i j k l m n o p q r s t u v w x y z

Using the DLL (Without an Import Library)

Now we'll look at how to load the DLL on the fly. This is useful for things such as if you don't know what the dll is called before-hand (for example the plug-in system I mentioned earlier). Here's the example code: DLL Test Source File (dllrun02.cpp) - Win32 Console Application:

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

     #define MAXMODULE 50

     typedef void (WINAPI*cfunc)();

     cfunc NumberList;
     cfunc LetterList;

     void main() {

           HINSTANCE hLib=LoadLibrary("DLLTEST.DLL");

           if(hLib==NULL) {

                cout << "Unable to load library!" << endl;
                getch();
                return;
           }

           char mod[MAXMODULE];

           GetModuleFileName((HMODULE)hLib, (LPTSTR)mod, MAXMODULE);
           cout << "Library loaded: " << mod << endl;

           NumberList=(cfunc)GetProcAddress((HMODULE)hLib, "NumberList");
           LetterList=(cfunc)GetProcAddress((HMODULE)hLib, "LetterList");

           if((NumberList==NULL) || (LetterList==NULL)) {

                cout << "Unable to load function(s)." << endl;
                FreeLibrary((HMODULE)hLib);
                return;
           }

           NumberList();
           LetterList();

           FreeLibrary((HMODULE)hLib);

           getch();
     }

The code should load our library (assuming its in the path), then get the addresses of the two functions that we want to call. I'd recommend that you be careful when calling functions from dlls without import libraries. There's a lot more code to write (loading each function/library), and a lot more room for errors if your dll isn't correct. So if you don't need to do it this way, I wouldn't. That's up to you.
dllrun02.exe Output:

     Library loaded: C:\DLLTEST\DLLTEST.DLL

     This function was called from C:\DLLTEST\DLLRUN02.EXE

     NumberList(): 0 1 2 3 4 5 6 7 8 9

     This function was called from C:\DLLTEST\DLLRUN02.EXE

     LetterList(): a b c d e f g h i j k l m n o p q r s t u v w x y z

Closing

Hopefully you learned how to get started on working with dynamic-link libraries. Please let me know what you think of this document. There are many other uses and many more advanced topics in DLL management that you can explore on your own. Also, although the sample program is a Win32 console application, it works just the same for 'normal' Windows programs.

Downloads

- Download the Sample Application (48k)
- Download the Sample Application + Source Code (50k)

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.