DLLs contain executable code

advertisement
Dynamic Link Libraries (DLLs)
DLLs contain executable code
Code in Windows can be contained in executable (.exe) files or in dynamic link
libraries (.dll files). A .dll file is similar in format to a .exe file except that it cannot
be started directly from the operating system. The code in it must be called from
another DLL or from a .exe file. (Note: normally a DLL is given the .dll file name
extension, but we have seen that ActiveX controls get the .ocx extension, even
though they are really DLLs.)
They permit programs to share code
Several programs running at the same time can use the code in a single DLL. On
the MacIntosh, the corresponding concept is called a "shared library", which
emphasizes this aspect.
Windows itself is contained in DLLS
The code for Windows itself is stored in several DLLs, for example GDI.DLL
contains all the graphics code. There are also kernel.dll and user.dll. This way, one
copy of these DLLs is in memory, serving all the Windows applications that are
running. Also, the MFC code is contained in DLLs. When you begin App Wizard,
you are given a choice whether you want to link to MFC statically or dynamically.
Now you know what it means: if you choose dynamic linking, then your program
will use the code from MFC in the form of DLLs. If you choose static linking, the
MFC code will be added to your .exe file instead.
DLLs as a tool for managing program development and maintenance
DLLs are very useful for breaking large programs into manageable pieces. Let's
list some (about half) of the DLL's in MathXpert:
parser.dll
parses user input into "term" structures representing math
symsout.dll
displays mathematical formulas on the screen or printer
algebra.dll, trig.dll, calc.dll, polyval.dll
functions to implement mathematical operations
automode.dll
code to decide what to do next in generating automode solutions
prover.dll
code to use logic to verify side conditions for operations
cgraph.dll
code to draw (several different kinds of) graphs
var.dll
code to manage variables
Review of static libraries
A library, or static library, is usually given the .lib file name extension. It consists
of several object files, one after the other, preceded by a kind of table of contents
telling what functions are defined and what their (relative) addresses are. If you
learned C, you are familiar with the C Runtime Library, which contains such
functions as strcpy, strcat, atoi, etc. Perhaps you learned the C++ Standard
Template Library instead. These are examples of static libraries, or at least as you
first used them, they were static libraries. You must explicitly link to a static
library in order to call functions defined in it. If you don’t link the correct .lib file,
you will get an "unresolved external" message.
You do NOT link to a .dll file in the same way.
Import Libraries
Then, why don’t you get an unresolved external message from the functions you
call that are not defined in your .exe, but instead in a DLL? Answer: you link
instead to an "import library". Let’s say you have a DLL that exports a function f.
When your DLL project builds, it will produce two files: MyLibrary.dll and
MyLibrary.lib. The .lib file is an "import library". It is a small file that you link
with your .exe as if it were a normal static library. It contains a function named f
which will satisfy the linker, so you don’t get an unresolved external by calling f.
In Visual C++, you link your .exe to the import library by adding MyLibrary.lib to
the list of libraries on the Link property page under Settings.
Declaring functions in a DLL
In addition to linking to the import library, you have to declare your function
correctly. Here is an annoyance: different compiler vendors require a different
syntax for this! Visual C+|+ requires that when a function is exported from a DLL
it must be declared like this (in the example of a function that takes an int and
returns an int):
__declspec(dllexport) int f(int n)
In the header file that contains a prototype of f, the same magic incantation must
appear.
But, in the .exe or .dll from which f is called, it is not an exported function, but an
imported function. Therefore it must be declared as
__declspec(dllimport) int f(int n);
This requirement makes it difficult to include the same header file in the files
where f is called as in the files where f is defined. However, it is important to do
just that, since that’s what prototypes are for: to ensure type consistency between
the definition and the calls of a function.
This problem can be solved, for example, this way: In the source files of
MyLibrary, put #define MYLIBRARY_DLL, and then instead of
__declspec(edllxport) or __declspec(dllimport), put MEXPORT_MYLIBRARY
Then in the header file where the prototype of f is, put
#ifdef MYLIBRARY_DLL
#define MEXPORT_MYLIBRARY __declspec(dllexport)
#else
#define MEXPORT_MYLIBRARY __declscpec(dllimport)
#endif
extern "C" MEXPORT_MYLIBRARY int f(int);
Data in DLLs
If the DLL has static data, this data is NOT shared between different applications
that may use the DLL. Each application that calls the DLL will get its own copy of
the data. (This was not always the case in early versions of Windows.)
A DLL can export a global variable, as well as a function, but this is NOT
ADVISED. Instead, use functions to Get and Set the variable in question. Better
yet, make all variables members of some class and never use global variables.
Linking with a DLL
Using an import library is called "implicit linking". There is another method, called
"explicit linking", in which you do not use an import library. This method must be
used when you do not know at link time what DLLs might be supplied later on.
You then use the LoadLibrary function to make your DLL's functions accessible,
but the syntax for calling them is more complex, since the linker has to avoid
unresolved externals. We won't go into this.
Should a DLL link to MFC statically or dynamically? Answer: if it’s going to be
distributed as part of an application using MFC, then dynamically, as the MFC
DLLs will have to be present anyway. But if it’s going to be sold or distributed on
its own, as a component of other people’s programs, then perhaps statically, since
that will guarantee that it will run. The eventual user may not have the MFC
libraries, or may not have the same version of the MFC libraries that you have.
Can I put a C++ class in a DLL?
A "regular DLL" exports C functions. Therefore, its declaration should begin with
extern "C". This comes before the MEXPORT_MYLIBRARY int f(int n) in the
header file. If you omit this, the exported function will not be f but the "decorated"
or "mangled" name produced by the C++ compiler, which contains some class
information. Every compiler does this mangling differently. Note, you can use
C++ in the DLL code, but you just export the function using C syntax. You don't
export a class.
If you use an "Extension DLL" then you can export an entire C++ class, complete
with member functions. In this case you must dynamically link to MFC. The
disadvantage of extension DLLs is that they can only be used by C++ programs. If
your DLL needs to be usable from Visual Basic, for example, use a regular DLL.
Can I put resources in a DLL?
Yes, you can put resources (bitmaps, menus, dialogs, etc.) in a DLL.
When you want to load a bitmap, menu, dialog, or other resource from a DLL, you
usually need an HINSTANCE parameter. This should be the instance handle of the
DLL itself. You get this with GetModuleHandle("MyLibrary.dll");
It is perfectly sensible to make a DLL that contains ONLY resources. This is
essentially what the ActiveX wizard does when you create an ActiveX control.
Post-build step
Say your workspace contains two projects, a DLL and an .exe that is going to use
the DLL. When the DLL is built, the .dll file is placed in its own directory,
something like MyLibrary/Debug. You want to have it copied to the MyApp/Debug
directory where your .exe file lives. You do this by going to Settings and choosing
the Post-Build tab, and entering a command to copy the file. Otherwise, you will be
testing Myapp.exe using an old version of MyLibrary.dll.
Initializations in a DLL
DllMain is the main entry point of a DLL. In simple cases, you don’t write it,
because a default will be provided. But if you need to perform some initializations
when the DLL is loaded, this is the place. This function is also called when the
DLL is detached from the calling process and when individual threads in the DLL
are started or terminated.
Using Visual Studio to make DLLs
So far, each of your workspaces has contained exactly one project. But a
workspace can contain several projects. For example, it might contain one project
to make the .exe file and several other projects, each of which makes a DLL which
your program uses. You might break a large program into DLLs just to help with
maintenance. This might be especially useful if a team is working on the
program--then perhaps one team member can be responsible for each DLL. If you
put the DLLs all in one project, then the debugger can jump seamlessly from exe to
dll and back, which is very convenient (Turbo C didn't do that!)
You can, of course, make a different project for the .exe and for each .dll, but there
is no reason to do that, and it prevents seamless debugging.
Download