What is a DLL (dynamic link library)?
A DLL is a library that contains code and data that can be used by multiple programs at the same time. For example, in the Windows operating system, the COMDLG32 DLL performs common functions related to dialog boxes. Therefore, each program can use the functionality contained in the DLL to implement the Open dialog box. This helps facilitate code reuse and efficient use of memory. The purpose of this article is to allow you to understand and master DLLs at once.
Why use DLLs (dynamic link libraries)?
Code reuse is an important way to improve the efficiency of software development. Generally speaking, as long as a part of the code is universal, it can be constructed into a relatively independent functional module and reused in subsequent projects. A more common example is a variety of application frameworks, all of which are published in the form of source code. Because this reuse is the source code level, the source code is completely exposed to the programmer, so called "white box reuse." White box multiplexing has the following three disadvantages:
1. Exposure to source code, multiple copies, resulting in storage waste;
2. Easy naming conflict with programmer's native code;
3. It is difficult to update the module function, which is not conducive to the modular implementation of the problem;
To compensate for these deficiencies, a "binary level" code reuse is proposed. Using the binary level of code reuse to some extent hides the source code, for "black box multiplexing" way not only dll one, static link library, even more advanced COM components are.
Using DLLs mainly has the following advantages:
1. Use fewer resources; When multiple programs use the same function library, DLLs can reduce the amount of duplication of code loaded in disk and physical memory. This can affect not only the programs that run in the foreground, but also the programs that run on the Windows operating system greatly.
2. Promotion of modular architecture;
3. Simplify deployment and installation.
Creating a DLL
Open Visual Studio 2012 to create a project with the following diagram:
Enter the project name and click [OK];
Click Finish to create the project.
Now we can add our code to the project. Join MyCode.h and MyCode.cpp two files; Enter the following code in MyCode.h:
#ifndef _mycode_h_
#define _mycode_h_
#ifdef Dlldemo1_exports
#define Exports_demo _declspec (dllexport)
#else
#define Exports_demo _declspec (dllimport)
#endif
extern "C" Exports_demo int Add (int a, int b);
#endif
Enter the following code in the MyCode.cpp:
#include "stdafx.h"
#include "MyCode.h"
int Add (int a, int b)
{
return (A + B);
}
The DLLDemo1.dll file is generated when the project is compiled. In the code, a lot of details, I will explain in detail later (engineering download).
Using DLLs
When our program needs to use a DLL, we need to load the DLL, there are two ways to load the DLL in the program, the load-time dynamic link and the run-time dynamic link.
1. In load-time dynamic linking, the application displays calls to exported DLL functions as if local functions were called. To use load-time dynamic linking, you need to provide a header file and an import library file (. lib) when you compile and link your application. When this is done, the linker provides the system with the information it needs to load the DLL and resolves the location of the exported DLL function at load time;
2. In the Run-time dynamic link, the application calls the LoadLibrary function or the LoadLibraryEx function to load the DLL at run time. After the DLL is successfully loaded, you can use the GetProcAddress function to obtain the address of the exported DLL function to invoke. When you use run-time dynamic linking, you do not need to use the import library file.
There are two ways to use DLLs when you are actually programming, so which one should you use? In actual development, it is based on the following points:
1. Startup performance If the initial startup performance of your application is important, you should use run-time dynamic linking;
2. Ease of use in load-time dynamic link, the exported DLL function is similar to the local function, we can make the call of these functions conveniently;
3. Application logic in Run-time dynamic linking, the application can branch to load different modules as needed.
Next, I'll call DLL dynamic-link libraries in two different ways.
Load-time dynamic Link:
#include <windows.h>
#include <iostream>
#include ". \\DLLDemo1\\MyCode.h "
using namespace Std;
#pragma comment (lib, "...). \\debug\\DLLDemo1.lib ")
extern "C" _declspec (dllimport) int Add (int a, int b);
int main (int argc, char *argv[])
{
Cout<<add (2, 3) <<endl;
return 0;
}
Run-time dynamic Link:
#include <windows.h>
#include <iostream>
using namespace Std;
typedef int (*ADDFUNC) (int a, int b);
int main (int argc, char *argv[])
{
Hmodule hDLL = LoadLibrary ("DLLDemo1.dll");
if (hDLL!= NULL)
{
Addfunc add = (addfunc) GetProcAddress (hDLL, "add");
if (add!= NULL)
{
Cout<<add (2, 3) <<endl;
}
FreeLibrary (hDLL);
}
}
The above code is in the DLLDEMO1 project. (Project download).
DllMain function
When Windows loads a DLL, it needs a portal function, just as the console program requires a main function. Sometimes the DLL does not provide the DllMain function, and the application can successfully reference the DLL, because Windows will introduce a default DllMain function version from other runtime libraries when DllMain is not found. Does not mean that the DLL can discard the DllMain function.
According to the authoring specification, Windows must find and execute the DllMain function in the DLL as a basis for loading the DLL, which allows the DLL to remain in memory. This function is not part of the exported function, but the internal function of the DLL, which means that the DllMain function cannot be called directly from the client, and the DllMain function is automatically invoked.
The DllMain function is invoked when a DLL is loaded and unloaded, and the DllMain function is invoked when a single thread starts and terminates. Parameter Ul_reason_for_call indicates the reason for calling DllMain, in the following four cases:
Dll_process_attach: When a DLL is first loaded into the process address space, the system calls the DLL's DllMain function, and the passed Ul_reason_for_call parameter value is Dll_process_attach. This situation occurs only when the DLL is first mapped;
Dll_thread_attach: This notification tells all DLLs to perform the initialization of the thread. When a process creates a new thread, the system looks at all the DLL file mappings in the process address space and then uses Dll_thread_attach to invoke the DllMain function in the DLL. Note that the system does not use value Dll_thread_attach for the main thread of the process to invoke the DllMain function in the DLL;
Dll_process_detach: When the DLL is unmapped from the address space of the process, the parameter Ul_reason_for_call parameter value is Dll_process_detach. When a DLL handles Dll_process_detach, the DLL should handle process-related cleanup operations. If a process is terminated because a thread in the system has called terminateprocess to terminate, the system does not use Dll_process_detach to invoke the DllMain function in the DLL to perform cleanup of the process. This will result in data loss;
Dll_thread_detach: The notification tells all the DLLs to perform the thread cleanup work. Note that if the end of the thread is done using TerminateThread, then the system will not use the value Dll_thread_detach to perform thread cleanup, which means that data loss is possible, So don't use TerminateThread to end the thread. All these explanations are embodied in engineering Dllmaindemo (engineering downloads).
Function Export method
During the creation of the DLL, I used the _declspec (dllexport) method to export the function, and there is another way to export the function, which is to use the Export file (. def). In DLL engineering, you can add a Module-definition file (. def file).. def files provide the linker with information about the export, properties, and other aspects of the linker program.
For the example above,. def can be like this:
LIBRARY "DLLDemo2"
Exports
ADD @ 1; Export the ADD function
The format of Module-definition file (. def) files is as follows:
The 1.LIBRARY statement describes the DLL corresponding to the. def file;
The 2.EXPORTS statement lists the names of the functions you want to export. You can add @n to the exported function name in the. def file, indicating that the ordinal number of the function to be exported is n (this ordinal number works when a function call is made).
Using the Def file, the DLL is generated and the client invokes the code as follows:
#include <windows.h>
#include <iostream>
using namespace Std;
typedef int (*ADDFUNC) (int a, int b);
int main (int argc, char *argv[])
{
Hmodule hDLL = LoadLibrary ("DLLDemo2.dll");
if (hDLL!= NULL)
{
Addfunc add = (addfunc) GetProcAddress (hDLL, Makeintresource (1));
if (add!= NULL)
{
Cout<<add (2, 3) <<endl;
}
FreeLibrary (hDLL);
}
}
As you can see, when you call the GetProcAddress function, the second parameter passed in is Makeintresource (1), where 1 is the ordinal number of the corresponding function in the Def file. (Project download)
extern "C"
Why use extern "C"? C + + Father in the design of C + +, considering that there is already a large number of C code, in order to support the original C code and already written C library, need to support C in C + +, and extern "C" is one of the strategies. In declaring the function, I noticed that I also used extern "C", which is to say in detail the extern "C".
extern "C" contains two meanings, first of all, it modifies the target is "extern", and secondly, the target that it modifies is "C". First of all, extern; in C + +, extern is used to indicate keywords for functions and variable scopes (visibility), which tells the compiler that the functions and variables that it affirms can be used in this module or in other modules. The role of extern is summed up in the following points:
1. Within a file, if the external variable is not defined at the beginning of the file, its valid range is limited to the beginning of the definition to the end of the file. If you need to refer to the variable before you define it, make an "external variable declaration" of the variable with the keyword "extern" before the reference, indicating that the variable is an external variable that has already been defined. With this declaration, the variable can be reasonably used from the declaration, for example:
/*
* * Filename:extern Demo
* * author:jelly Young
* * DATE:2013/11/18
* * Description:more Information
*/
#include <iostream>
using namespace Std;
int main (int argc, char *argv[])
{
extern int A;
cout<<a<<endl;
}
int a = 100;
2. In a multiple-file program, if you want to use the same external variable for multiple files, you cannot define an external variable in each file, otherwise a "duplicate definition" error occurs. The right thing to do is to define an external variable in any file, and other files to make an "external variable declaration" with extern to the variable. When compiling and linking, the system knows that the variable is an external variable that has already been defined elsewhere, and extends the scope of the external variable in another file to this file, so that the external variable can be legitimately used in this file. Anyone who has written an MFC program knows that in the header file of the Cxxxapp class, an extern is used to declare a variable of that class, and the actual definition of the variable is done in the implementation file of the Cxxxapp class;
3. External functions, when defining functions, if you add the keyword extern at the leftmost end, this function is an external function. The C language stipulates that if extern is omitted when defined, it is implied as an external function. The intrinsic function must precede the static keyword. In the file where you want to call this function, declare the function with extern to indicate that the function is an external function defined in another file.
Then say the meaning of "C". We all know that C + + supports overloaded mechanisms by different types of function arguments, and the compiler produces different internal identifiers for each overloaded function based on parameters; but what if C + + programs are encountered to invoke the C function that has been compiled? For example, the int Add (int a, int b) function above. The function is _add in the library after the C compiler, and the C + + compiler generates names such as _add_int_int to support function overloading and type safety. Because the compiled name is different, C + + programs can not directly call the C function, so C + + provides a C-connection exchange specified symbol extern "C" to solve this problem; In the above DLL, the Add function is declared in the form: extern "C" Exports_demo int ADD (int A, int b). This tells the C + + compiler, function Add is a C-linked function, should go to the library to find the name _add, instead of looking for _add_int_int. When we remove "C" from the DLL above, compile and build a new DLL, use the Dependency Walker tool to view the DLL, as shown in figure:
Note that the export method is C + + and the name of the exported add function adds a lot of things, and when you export it in this way, the code is the following when the client invokes it:
code as follows:
#include <windows.h>
#include <iostream>
using namespace Std;
typedef int (*ADDFUNC) (int a, int b);
int main (int argc, char *argv[])
{
Hmodule hDLL = LoadLibrary ("DLLDemo1.dll");
if (hDLL!= NULL)
{
Addfunc add = (addfunc) GetProcAddress (hDLL, "?) add@ @YAHHH @z ");
if (add!= NULL)
{
Cout<<add (2, 3) <<endl;
}
FreeLibrary (hDLL);
}
}
Note that the second parameter of the GetProcAddress function, which is the name of the exported function, is a strange name to write when encoding. When we use the extern "C" method to export, the screenshot is as follows:
Note that the export mode is C, and the function name is now the normal Add. When we use GetProcAddress again, we can specify add directly without adding that long string of strange names.
DLL Export variable
DLL-defined global variables can be accessed by the calling process, and DLLs can also access global data for the calling process. (Project download)
DLL Export class
DLL, or you can export the class that is defined in the Detailed engineering code, please see (engineering download)
Summarize
The explanation of the DLL to this end, because MFC in the current environment of less use, here is not to explain, if the project encountered MFC DLL related knowledge, I do summary. Finally, I hope you give some pertinent suggestions to my blog.