Chapter 2 DLL Basics
All functions provided by Windows API are included in DLL. Three most important dll: kernel32.dll (manage memory, processes, and threads), use32.dll (execute tasks related to the User Interface), and gdi32.dll (draw images and show text ).
19.1. dll and process address space
Level 1: DLL positioning Overview
Before an application (or other DLL) can call a function in a DLL, you must map the file image of the DLL to the address space of the calling process. Two methods: the link for implicit loading and the link for displaying runtime.
After ing, when a function in the DLL is called, the function will obtain the parameter passed to it in the thread stack, and store the local variables required by the function in the thread stack. In addition, any object created by the function in the DLL is owned by the calling thread or process.
19.2 overall
Level 2: Theoretical Process Overview
If an EXE needs to import functions or variables from another DLL module, you must:
Build the DLL first:
1) create a header file, including the function prototype, structure, and symbol exported in the DLL. To build the DLL, all DLL source files must contain this header file. The same header file is required for building an EXE.
2) create a source file to implement the functions and variables exported in the DLL module.
3) when constructing the DLL module, the compiler processes each source file and generates a. OBJ module.
4) When all. OBJ modules are created, the linker combines all. OBJ modules to generate a separate DLL.
5) if the linker detects that at least one function or variable is output from the DLL source file, the linker also generates a. Lib file. It only lists the symbolic names of all exported functions or variables.
Then construct the EXE (executable module ):
1) All source files that reference exported functions, variables, data structures, or symbols must contain the header file corresponding to the DLL.
2) When constructing an EXE, the compiler processes each source file and generates a. OBJ module.
3) after compilation, the linker combines all. OBJ modules to generate an EXE. The EXE (executable module) contains an import segment, which lists all the DLL modules it requires and the symbols it references from each DLL module. Execute EXE, And the OS loader will execute 5 ).
4) The loader first creates a virtual address space for the new process and maps the executable module to the address space of the new process. Load the program and parse the import segment of the executable module. For each DLL listed in the import segment, the loader locates the DLL module in the user system and maps the DLL to the address space of the process. The DLL module can import functions and variables from other DLL modules. Therefore, the DLL module may have its own import segments and map all its DLL modules to the address space of the process.
After the program maps the EXE and all DLL files to the address space of the process, the main thread of the process can start execution.
Layer 3: Detailed practices
19.2.1 build the DLL module
A dll can export variables, functions, or C ++ classes. Avoid exporting variables. The C ++ class can be exported only when the compiler used by the exported C ++ class module and the compiler used by the imported C ++ class module are provided by the same vendor.
Clever (Code p515): In the DLL header file
# Ifdef mylibapi
# Else
# Define mylibapi extern "C" _ declspec (dllimport)
# Endif
// Exported functions or variables
Mylibapi int add (INT nleft, int nright );
DLL source file
# Define mylibapi extern "C" _ declspec (dllexport) // It must be before the DLL header file
# Include "DLL header file"
EXE source file
# Include "DLL header file" // The mylibapi macro cannot be defined
In this way, mylibapi is defined as export in the DLL source file, and mylibapi In the EXE source file is defined as import.
_ Declspec (dllexport): You do not need to add this modifier before the exported variables and functions in the source file. Because the compiler will remember which variables and functions should be exported when parsing the header file.
_ Declspec (dllimport): add the exported function, variable, or C ++ class to the DLL header file. Not required, but can slightly improve efficiency. In the EXE source file, the compiler will know that this symbol is imported from the DLL module.
Extern "C": used only when writing C ++ code (C should not be used ). The C ++ compiler usually modifies the function name and variable name, and an error occurs when linking. This modifier tells the compiler not to adapt the variable name or function.
_ Stdcall: even if it is C, when this Convention is used, the Microsoft compiler will adapt the function name. The specific method is to add an underline prefix and a special suffix to the function name. The suffix consists of a @ symbol and the number of bytes that are passed to the function as a parameter. For example, _ declspec (dllexport)
Long _ stdcall myfunc (int A, int B); export to _ myfunc @ 8. So we need to prevent adaptation. Two Methods: Create a. Def file and include the following section in the. Def file:
Exports
Myfunc
The second method (not recommended) is to export the unadapted function name. Add the following to the DLL source file:
# Pragma comment (linker, "/export: myfunc = _ myfunc @ 8 ")
. Def file format:
Library XX (DLL name is not required, but must be the same as the generated DLL name)
Exports
[Function name] @ [function serial number]
Export class: note that the export class and the export class are similar to the export function, but the extern "C" symbol cannot be used in the export class.
Export segment: When the Microsoft C/C ++ compiler sees the variable, function, or C ++ class modified by _ declspec (dllexport), it is generated. some additional information is embedded in the OBJ file. The information is parsed when the linker links all. OBJ files in the DLL. The linker embeds an export symbol table in the generated DLL file. This export section lists the signed names of the exported variables, functions, or classes. The relative virtual address is also saved, indicating where each symbol can be found in the DLL module. (Add the dumpbin.exe tool to-exports to view the export segment of a DLL)
Import segment: When the linker sees the import symbol modified by _ declspec (dllimport), a special segment is embedded in the generated executable module. Its name is the import segment. The import section lists the DLL modules required by this module and the symbols it references from each DLL module. (Add the dumpbin.exe tool to imports to view the export segment of a DLL)
/***********************************Moudle: MyLib.h***********************************/#ifdef MYLIBAPI//MYLIBAPI should be defined in all of the DLL's source code //moudles before this header file is included.//All functions/variables are being exported.#else//This header file is included by an EXE source code moudle///Indicate that all functions/variables are being imported.#define MYLIBAPI extern "C" _declspec(dllimport)#endif////////////////////////////////////////////////Define any data structures and symbols here.////////////////////////////////////////////////Define exported variables here.(Note:Avoid exporting variables.)MYLIBAPI int g_nResult;///////////////////////////////////////////////Define exported function prototypes here.MYLIBAPI int Add(int nLeft, int nRight);////////////////////////End of File////////////////////////****************************************Moudle:MyLibFile1.cpp****************************************/#include <windows.h>#define MYLIBAPI extern "C" _declspec(dllexport)#include "MyLib.h"/////////////////////////////////////////int g_nResult;int Add(int nLeft, int nRight){g_nResult = nLeft + nRight;return g_nResult;}///////////////////End of File/////////////
19.2.2. Build an executable module
1) Export header file containing dll: # include <>; Be sure not to define the mylibapi macro.
2) contains the Lib file: # pragma comment (Lib, ""); to allow the linker to determine the DLL from which the import symbol in the Code comes from.
3) directly use the exported variables, functions, or C ++ classes.
19.2.3 run the executable module
The OS loader first creates a virtual address space for the process, maps the EXE to the address space, and then loads the program back to check the import segment of the exe, locate the required DLL and map them to the address space of the process.
Because the import segment only contains the DLL name and does not contain the dll path, the loader must search for the DLL in the following sequence:
1)
Directory containing executable files
2)
Windows System directory, which can be obtained through getsystemdirectory
3)
A 16-bit system directory, that is, the system subdirectory of the Windows directory
4)
Windows Directory, which can be obtained through getwindowsdirectory
5)
Current Directory of the process
6)
Directory listed in the PATH environment variable.
For example, if a DLL is created and the cmyclass class is exported, the client can use the DLL normally. Assume that the cmyclass object size is 30 bytes. If we need to modify the cmyclass class in the DLL so that it has the same functions and member variables, but add a private member variable int type to it, now the cmyclass object is 34 bytes in size. When the customer directly replaces the new DLL with the original 30-byte DLL, the customer's application expects a 30-Byte object, but now it has become a 34-Byte object, bad, the customer program error.
Similar problems: If the cmyclass class is not exported and cmyclass is used in the exported function, changing the object size will still cause problems. At this time, the only way to modify this problem is to re-compile the entire application for the header file of cmyclass in the customer program, so that the customer program uses 34 bytes of objects.
This is a serious problem. Sometimes, if the source code of the client program is not available, we cannot use this new DLL.
Then Baidu