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.