A DLL is a library that contains code and data that can be used by multiple programs at the same time. For example: in Windows operating system In, the Comdlg32 DLL performs common functions related to dialog boxes. Therefore, each program can use the functions contained in the DLL to implement the open dialog box. This helps to promote code reuse and efficient memory use. The purpose of this article is to let you understand and master DLL at one time.
Why use DLL (Dynamic Link Library)?
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. Common examples are various application frameworks, which are published in the form of source code. Because this reuse is at the source code level and the source code is completely exposed to programmers, it is called "white box reuse". White box reuse has the following three disadvantages:
- Exposure of source code and multiple copies, resulting in storage waste;
- It is easy to have naming conflicts with the programmer's local code;
- It is difficult to update the module function, which is not conducive to the modular implementation of the problem;
In order to make up for these shortcomings, a "binary level" code reuse is proposed. The use of binary level code reuse hides the source code to a certain extent. There are more than DLL s for "black box reuse", static link libraries and even more advanced COM components.
Using DLL has the following advantages:
- Use less resources; When multiple programs use the same function library, DLL s can reduce the amount of duplication of code loaded on disk and physical memory. This can greatly affect not only the programs running on the foreground, but also other programs running on the Windows operating system;
- Promote modular architecture;
- Simplify deployment and installation.
Create DLL
Open Visual Studio 2012 and create a project as shown in the following figure:
Enter the project name and click [OK];
Click [Finish] and the project is created. Now we can add our code to the project. Add two files: MyCode.h and MyCode.cpp; 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 MyCode.cpp:
When the project is compiled, the DLLDemo1.dll file will be generated. In the code, there are many details, which I will explain in detail later.
- #include "stdafx.h"
- #include "MyCode.h"
- int Add ( int a , int b )
- {
- return ( a + b );
- }
Use DLL
When our program needs to use DLL, we need to load DLL. There are two methods to load DLL in the program: load time dynamic link and run-time dynamic link.
- In load time dynamic link, the application program calls the exported DLL function like a local function. To use load time dynamic links, you need to provide header files and import library files (. lib) when compiling and linking applications. When doing so, the linker will provide the system with the information required to load the DLL, and resolve the location of the exported DLL function during loading;
- In runtime dynamic links, the application calls the LoadLibrary function or LoadLibraryEx function to load the DLL at runtime. After the DLL is successfully loaded, you can use the GetProcAddress function to obtain the address of the exported DLL function to be called. When using runtime dynamic links, you do not need to use import library files.
There are two ways to use DLL in actual programming, so which one should be used? During actual development, the following points are considered:
- Startup performance if the initial startup performance of the application is important, run-time dynamic links should be used;
- Ease of use in dynamic link during loading, the exported DLL functions are similar to local functions, and we can easily call these functions;
- Application logic is dynamically linked at run time, and applications can branch to load different modules as needed.
Next, I will use two methods to call the DLL Dynamic link library.
Dynamic link on load:
Runtime 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;
- }
- #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 codes are in DLLDemo1 project. ( Project Download).
DllMain function
When Windows loads the DLL, it needs an entry function, just as the console program needs the main function. Sometimes, the DLL does not provide the DllMain function, and the application can successfully reference the DLL. This is because when Windows cannot find the DllMain, the system will introduce a default DllMain function version that does not do any operation from other runtime libraries, which does not mean that the DLL can Discard the DllMain function.
According to the writing specification, Windows must find and execute the DllMain function in the DLL as the basis for loading the DLL, which enables the DLL to be retained in memory. This function does not belong to the export function, but the internal function of the DLL, which means that the DllMain function cannot be called directly on the client, and the DllMain function is called automatically.
The DllMain function is called when the DLL is loaded and unloaded. The DllMain function is also called when a single thread starts and terminates. The parameter ul_reason_for_call indicates the reason for calling DllMain. There are four cases:
DLL_PROCESS_ATTACH: when a DLL is loaded into the process address space for the first time, the system will call the DllMain function of the DLL, and the passed ul_reason_for_call parameter value is DLL_PROCESS_ATTACH. This happens only when the DLL is mapped for the first time;
DLL_THREAD_ATTACH: this notification tells all DLLs to execute thread initialization. When a process creates a new thread, the system will view all DLL file mappings in the process address space, and then use DLL_THREAD_ATTACH to call the DllMain function in the DLL. It should be noted that the system will not use the value DLL_THREAD_ATTACH to call the DllMain function in the DLL for the main thread of the process;
DLL_PROCESS_DETACH: when the DLL is unmapped from the address space of the process, the value of the parameter ul_reason_for_call is DLL_PROCESS_DETACH. When the DLL processes DLL_PROCESS_DETACH, the DLL should handle the cleanup operations related to the process. If the process terminates because a thread in the system calls TerminateProcess to terminate, the system will not use DLL_PROCESS_DETACH Call the DllMain function in the DLL to clean up the process. This will cause data loss;
DLL_THREAD_DETACH: this notification tells all DLLs to execute thread cleanup. Note that if the thread termination is completed by using TerminateThread, the system will not use the value DLL_THREAD_DETACH to execute thread cleanup. That is, data loss may occur, so do not use TerminateThread to terminate threads. All the above explanations are in work DLLMainDemo( Project Download )All reflect.
Function export method
In the process of creating DLL, I use_ There is another way to export functions in declspec (dllexport), that is to use the export file (. def). You can add a module definition file (. def) file to the DLL project The def file provides the linker with information about the exports, properties, and other aspects of the linked program.
For the above example,. def can be as follows:
- LIBRARY "DLLDemo2"
- EXPORTS
- Add @ 1 ;Export the Add function
The format of the module definition file (. DEF) file is as follows:
- The LIBRARY statement describes the DLL corresponding to the. def file;
- The names of the functions to be exported are listed after the EXPORTS statement. You can add @ n after the exported function name in the. def file to indicate that the sequence number of the function to be exported is n (this sequence number plays a certain role in function calls).
Using the def file, a DLL is generated, and the client calling code is as follows:
You can see that when calling the GetProcAddress function, the second parameter passed in is MAKEINTRESOURCE(1), where 1 is the sequence number of the corresponding function in the def file. ( Project Download)
- #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);
- }
- }
extern "C"
Why use extern "C"? When designing C + +, the father of C + + considered that a large number of C code existed at that time. In order to support the original C code and the written C library, it is necessary to support C in C + + as much as possible, and extern "C" is one of the strategies. When declaring functions, I noticed that I also used extern "C". Here I want to talk about extern "C" in detail .
Extern "C" has two meanings. First, the target it modifies is "extern"; second, the target it modifies is "C". Let's talk about extern first. In C/C + +, extern is used to indicate the scope (visibility) of functions and variables Keyword that tells the compiler that the functions and variables it declares can be used in this module or other modules. The functions of extern are summarized as follows:
- In a file, if an external variable is not defined at the beginning of the file, its valid range is only limited from the beginning of the definition to the end of the file. If you need to reference the variable before definition, you should make an "external variable declaration" on the variable with the keyword "external" before reference, indicating that the variable is a defined external variable. With this declaration, you can The variable has been used reasonably since the declaration, for example:
- /*
- ** FileName : Extern Demo
- ** Author : Jelly Young
- ** Date : 2013/11/18
- ** Description : More information, please go to http://www.jellythink.com
- */
- #include <iostream>
- using namespace std;
- int main(int argc, char *argv[])
- {
- extern int a;
- cout<<a<<endl;
- }
- int a = 100;
- In a multi file program, if multiple files need to use the same external variable, you cannot define an external variable in each file, otherwise the error of "repeated definition" will appear. The correct way is to define an external variable in any file and make an "external variable declaration" on the variable in other files with extern When compiling and linking, the system will know that the variable is an external variable that has been defined elsewhere, and extend the scope of the external variable in another file to this file, so that the external variable can be used legally in this file. As everyone who has written MFC program knows, in the header file of CXXXApp class, a variable of this class is declared with extern, and The actual definition of variables is completed in the implementation file of CXXXApp class;
- When defining an external function, if the keyword extern is added at the leftmost end, it means that the function is an external function. C language stipulates that if extern is omitted during definition, it is implied as an external function. The internal function must be preceded by the static keyword. In the file that needs to call this function, the function is declared with extern, indicating that the function is defined in other files External functions.
We all know that C + + supports the overload mechanism through different types of function parameters, and the compiler generates different internal identifiers for each overloaded function according to the parameters. However, what should we do if a C + + program calls a compiled c function? For example, int Add (int a, int b) above Function. The name of the function in the library after being compiled by the C compiler is _Add, while the C + + compiler will generate names such as _Add _int _intto support function overloading and type safety. Due to different compiled names, C + + programs cannot directly call C functions, so c + + provides a C connection to exchange the specified symbol extern "C" To solve this problem; therefore, in the above DLL, the declaration format of the Add function is: extern "C" exports_demo int Add (int a, int b) This tells the C + + compiler that the function Add is a C-connected function. You should find the name _addin the library instead of _Add_int_int. when we remove the "C" in the DLL above, compile and generate a new DLL, and use the Dependency Walker tool to view the DLL, as shown in the figure:

Please note that the export method is C + +, and many things are added to the name of the exported Add function. When this method is used for export, the client calls, and the code is 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);
- }
- }
Please note the second parameter of GetProcAddress function. The parameter name is the exported function name. Isn't it strange to write such a name when encoding. When we export using extern al "C", the screenshot is as follows:
Note that the export method is C, and the function name is now an ordinary Add. When we use GetProcAddress again, we can directly specify Add instead of adding a long list of strange names.
DLL export variables
The global variables defined by the DLL can be accessed by the calling process; the DLL can also access the global data of the calling process.
DLL export class
Classes defined in DLL can also be exported. For detailed engineering code, see( Project Download)
summary
This is the end of the explanation of DLL. Since MFC is rarely used in the current environment, it will not be explained here. If I encounter MFC DLL related knowledge in future projects, I will make a summary. Finally, I hope you can put forward some pertinent suggestions to my blog.
******************************************************************************************************
Refer to the above content and work on the VS2010 development environment test The test steps are as follows:
1. Package the required functions into DLL


MyCode.cpp file:
- #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
When the project is compiled, the DllDemo.dll file will be generated under the Debug file.
- #include "MyCode.h"
- int Add ( int a , int b )
- {
- return ( a + b );
- }
2. Call DLL in dynamic link mode during loading


The operation results are as follows:
- // DllTest.cpp : Defines the entry point for the console application.
- #include "stdafx.h"
- #include <iostream>
- //#include "..\\DLLDemo1\\MyCode.h"
- using namespace std;
- #pragma comment(lib, "..\debug\DllDemo.lib") //*********************************************************************** Question 1
- extern "C" _declspec(dllimport) int Add(int a, int b);
- int _tmain(int argc, _TCHAR* argv[])
- {
- cout<<Add(2, 3)<<endl;
- while(1);//The program runs here to see the running results
- return 0;
- }

3. Call DLL in runtime dynamic link mode
- // DllTest1.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <iostream>
- #include <windows.h>
- using namespace std;
- typedef int (*AddFunc)(int a, int b);
- int _tmain(int argc, _TCHAR* argv[])
- {
- HMODULE hDll = LoadLibrary(_T("DllDemo.dll"));
- if (hDll != NULL)
- {
- AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
- if (add != NULL)
- {
- cout<<add(2, 3)<<endl;
- }
- FreeLibrary(hDll);
- }
- while(1);
- }

4. Export functions in the form of. def files (module definition files) (functions are not exported in the form of _declspec(dllexport)):


MyCode.cpp file:
- #ifndef _MYCODE_H_
- #define _MYCODE_H_
- extern "C" int Add (int a , int b);
- #endif
Then add a module definition file (. def file):
- #include "MyCode.h"
- int Add ( int a , int b )
- {
- return ( a + b );
- }

Add code:
Compile the project and generate the DllDemo.dll file immediately.
- LIBRARY "DllDemo" //The string name here should be consistent with the project name
- EXPORTS
- Add @1;Export the Add function
Project code download:
- // DllTest2.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <windows.h>
- #include <iostream>
- using namespace std;
- typedef int (*AddFunc)(int a, int b);
- int _tmain(int argc, _TCHAR* argv[])
- {
- HMODULE hDll = LoadLibrary("DllDemo.dll");
- if (hDll != NULL)
- {
- AddFunc add = (AddFunc)GetProcAddress(hDll, MAKEINTRESOURCE(1));
- if (add != NULL)
- {
- cout<<add(2, 3)<<endl;
- }
- FreeLibrary(hDll);
- }
- while(1);
- }