Using Dynamic Link Libraries

Using DLLs In Your Programs

In order to use a DLL you must have the appropriate header files and/or prototypes for the functions you want to call, plus the DLL of course, and a special library called an import library. An import library is a lot like a normal library except that instead of normal functions it contains an import table like I described in the introduction, and a short function with the name of the function you really want to call which looks up the correct address in the import table and calls the real DLL function. By linking your program with an import library you gain access to the functions exported by the DLL for which the import library was created.

Using an import library is just like linking with an ordinary library.

I talk about creating import libraries for your own DLLs in the section on creating DLLs. But sometimes you don't have an import library for a DLL that someone else gave you, which is what the next section is about.

Using Other People's DLLs

What if you have a DLL but you don't have an import library for it? At the moment this is the case for a lot of commercial DLL libraries which provide import libraries for Microsoft compatible compilers. At this time gcc does not understand Microsoft .lib files correctly (although that will be fixed in the future). To use the DLL you have to generate an import library that GCC will understand. You do that using dlltool in the same way as you generate import libraries for your own programs. But before you can do that you need a .def file. Fortunately there is a tool for automatically generating .def files called impdef.exe which is discussed in the section for DLL import library tools in the introduction to GNU programming tools.

Note, however, that impdef isn't perfect. Some newer DLLs confuse it so that it may not be possible to automatically generate the .def file, or the file won't work without changes. Also, gcc requires that functions with PASCAL calling convention (also called STDCALL or WINAPI functions) to have @nn added to the end of the function name, where nn is the number of bytes passed on the stack to the function in question (if you didn't understand that don't worry, just think of it as a magic number). Sometimes the functions will be exported with such "mangled" names, in which case things should be fine (as long as you don't use the -k option for dlltool). But in most cases, including almot all of the Win32 API functions, the mangled version is not exported. In this case you have to add the @nn on to each function name manually. You can generally determine the correct number by writing a program that uses the function and trying to link it. gcc will report the correct number in its linker error message (if the prototype is done correctly). You also have to use the -k option when creating the import library with dlltool, which I talk about a bit more in the section on creating DLLs.

There are other tools that will show you the exports for a DLL, including TDUMP from Borland and DUMPBIN (I think) from Microsoft. Also, using Explorer in Windows 95 you can Quick View a DLL, and that will also give you a list of its exports. Unfortunately you can't save it to a file or copy it to the clipboard, so it's very inconvenient for creating import libraries.

Global Variables in DLLs

With Win32 Microsoft introduced the idea that DLLs could contain global variables which you could access the same way you can access a function. The variables are also listed in the import/export tables with the functions, but instead of pointing to a function's code the variable entries point to the actual spot in memory where the variable is stored.

Microsoft made a special keyword for Visual C++ which makes the compiler generate the code to automatically follow the pointer in the import table and get or set the real value of such a variable whenever you manipulate it in your program. EGCS 1.1 and above should allow you to use the __declspec (dllexport) and __declspec (dllimport) syntax to use such variables. You can also access such variables by performing a little magic in your header files, if you are using another version of gcc for example. Say there was a variable foobar exported by a DLL you use. Here's how you could use it in your programs (assuming foobar is an int):

extern int* _imp__foobar;
#define foobar (*_imp__foobar)

Then you can go ahead and use foobar just like it was the same variable all through your program, and the DLL will see the changes you make in the variable as well. But, before you start doing this all over the place a few words of warning:

All things considered, global variables should be avoided in any case, and even more so when you are dealing with dynamic linking. Still, it is possible to work with global variables in a DLL, but just because you can do something doesn't mean you should do it.