Dynamic Link Library (DLL) Programming Principle in Win32 Environment

zhaozj2021-02-08  195

Li Xin

Big large applications consist of many modules that complete relatively independent features, which work together to complete the entire software system. Among them, there may be some modules that are more common and will still be used when constructing other software systems. When building a software system, if you still compile all the source code of all modules to the entire application EXE file, some issues are generated: A disadvantage is to increase the size of the application, which will take up more disk space, program operation At the time, there will be a large memory space, causing waste of system resources; another disadvantage is that when writing large EXE programs, the compilation of all source code must be adjusted at each modification, and the complexity of the compilation process is added. It is also not conducive to the phase of the unit test.

A completely different more efficient programming and operational environments on the Windows system platform, you can create a separate program module as a smaller DLL (Dynamic Linkable library) file and can be compiled and tested separately. At runtime, the system is loaded into memory space only when the exe program does call these DLL modules. This method not only reduces the size of the EXE file and the demand for memory space, but also allows these DLL modules to be used by multiple applications simultaneously. Microsoft Windows will implement some of the main system functions in the form of a DLL module. For example, some of the basic functions in IE are implemented by a DLL file, which can be called and integrated by other applications.

In general, the DLL is a disk file (usually with a DLL extension), which consists of global data, service functions, and resources, which are filed in virtual spaces that are loaded into the process at runtime, which becomes part of the calling process. If there is no conflict with other DLLs, the file is typically mapped to the same address of the process virtual space. A variety of export functions are included in the DLL module for serving the outside world. Windows matches the process function call with the export function of the DLL file when loading the DLL module. In the Win32 environment, each process copies its own read / write global variables. If you want to share memory with other processes, you must use a memory map file or declare a shared data segment. The stack memory required by the DLL module is allocated from the stack of the runtime process. DLL is now more easier to write. Win32 has greatly simplified its programming mode and has many support from AppWizard and MFC class libraries.

First, the matching of the export and import functions

A DLL file contains an export function table. These export functions are linked by their symbolic names and integers called identification number. The address of the function in the DLL is also included in the function table. When the application loads the DLL module, it does not know the actual address of the call, but it knows the symbolic name and identification number of the function. The dynamic link process dynamically establishes a function call to the corresponding table of the function address when the DLL module is loaded. If you recompile and rebuild a DLL file, you don't need to modify your application unless you change the symbol name and parameter sequence of export functions. Simple DLL files only provide export functions for the application, more complex DLL files, in addition to providing export functions, in addition to providing export functions, and other functions in other DLL files. In this way, a special DLL can both import functions and import functions. This is not a problem because the dynamic link process can handle cross-related situations. In the DLL code, you must clearly declare the export function as described below: __DECLSPEC (DLLEXPORT) INT MyFunction (INT N); but can also list export functions in the module definition (DEF) file, but doing so often cause more trouble . In terms of application, requires the following statements to express the corresponding input functions: __Declspec (dllimport) INT MyFunCITION (INT N); only import and export declarations do not enable the function call inside the application to the corresponding DLL file. The application's project must specify the desired input library (lib file) for the linker. Moreover, the application must instance must include at least one call to the DLL function. Second, establish a link with the DLL module

There are two ways to link the application import function to the export function in the DLL file: implicit links and explicit links. The so-called implicit link refers to the actual storage path of the DLL file in the application, and the programmer does not need to care about the actual loading of the DLL file. The explicit link is opposite to this. With implicit link, the programmer automatically generates a corresponding LIB import file when establishing a DLL file. This file contains the symbol name and optional identification number of each DLL export function, but does not contain actual code. The lib file is compiled into the application project as an alternate file for the DLL. When the programmer recompores an application by static link mode, the call function in the application matches the export sign in the lib file, these symbols or identification numbers enter the generated EXE file. The corresponding DLL file name (but not complete path name) is also included in the lib file, and the link is stored inside the EXE file. When the DLL file is required during the application run, Windows discovers and loads the DLL according to this information, and then dynamic links to the DLL function via the symbol name or identification number. Explicit link mode is more suitable for integrated development languages ​​(e.g., VB). With an explicit link, the programmer does not have to use the import file, but directly call the Win32 LoadLibary function, and specify the path to the DLL as a parameter. LoadLibary returns the Hinstance parameter, the application uses this parameter when calling the getProcAddress function. The GetProcAddress function converts the symbol name or identification number to the address within the DLL. Suppose there is a DLL file that exports the following function: extern "c" __declspec (dLlexPort) Double Squareroot (Double D); the following is an example of explicit link to the export function: typedef double (SQRTPROC) (double); Hinstance Hinstance; sqrtproc * pfunction; verify ("c: //winnt//system32/Mydll.dll"); verify (pfunction = (sqrtproc *) :: getProcaddress (Hinstance, "Squareroot") ); Double D = (* pfunction) (81.0); // Calling the DLL function In implicit link, all DLL files called by the application are loaded in memory when the application EXE file is loaded; If the explicit link is used, the programmer can determine when the DLL file is loaded or not loaded. Explicit link decide which DLL file is loaded at runtime. For example, a DLL module with a string resource can be loaded in English, while the other is loaded in Spanish. The application is loaded with the corresponding DLL file after the user selects the appropriate language. Third, using symbolic links and identification number links

In the Win16 environment, the symbolic link is less efficient, and all the identification number link is the main link mode. In the Win32 environment, the efficiency of the symbolic link is improved. Microsoft now recommends using symbolic links. However, the DLL version in the MFC library still uses the identification number link. A typical MFC program may be linked to hundreds of MFC DLL functions. The exe file of the application using the identification number link is relatively small because it does not have to contain a long string symbol name of the import function.

Fourth, write a DLLMAIN function

The DLLMAIN function is the default entry point of the DLL module. This function is called when the Windows loads the DLL module. The system first calls the constructor of the global object and then calls the global function DLLMAIN. The DLLMAIN function is called not only when the DLL link is loaded into the process, but also when the DLL module is separated from the process (and other time) is also called. Below is an example of a framework DLLMAIN function. HINSTANCE g_hInstance; extern "C" int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {if (dwReason == DLL_PROCESS_ATTACH) {TRACE0 ( "EX22A.DLL Initializing / n!"); // initialize} else where IF (dwreason = DLL_PROCESS_DETACH) {trace0 ("ex22a.dll terminating! / n"); // Clear work here} Return 1; // Success} If the programmer does not write a DLLMAIN function for the DLL module, the system will In other runs, a version of the default DLLMain function that does not do any operation is introduced. DLLMAIN functions are also called when a single thread starts and terminates. Just as indicated by the DWReason parameter. V. module handle

Each DLL module in the process is identified by the globally unique 32-byte Hinstance handle. The process yourself have a Hinstance handle. All of these module handles are only valid within a particular process, which represents the starting address of the DLL or EXE module in the process virtual space. In Win32, the value of Hinstance and HModule is the same, and this two types can be replaced. The process module handle is almost equal to 0x400000, and the default handle of the DLL module load address is 0x10000000. If the program uses several DLL modules, each will have different Hinstance values. This is because different base sites are specified when creating a DLL file, or because the loader is relocated to the DLL code. The module handle is particularly important for loading resources. There is a Hinstance parameter in the win32 FindResource function. EXE and DLL have their own resources. If the application needs resources from DLL, this parameter is specified as a DLL module handle. If the resource included in the EXE file is required, the module handle of the EXE is specified. But there is a problem before using these handles, how do you get them? If you need to get the EXE module handle, call the WIN32 function getModuleHandle with the null parameter; if the DLL module handle is required, the WIN32 function getModuleHandle is called to the DLL file name.

6. How do applications find a DLL file?

If the application uses the LoadLibrary Explicit link, you can specify the full path to the DLL file in the parameter of this function. If you do not specify a path, or for implicit links, Windows will follow the search order below to locate the DLL: 1. Contains the directory of the EXE file, 2. The current working directory of the process, 3. Windows system catalog, 4. Windows directory, 5. A series of directories listed in the PATH environment variable. Here is a trap that is easily wrong. If you use VC to conduct project development, and create a project for the DLL module, then copy the generated DLL file to the system directory, call the DLL module from the application. So far, everything is fine. Next, a new DLL file is regenerated after some modifications to the DLL module, but you forget to copy the new DLL file to the system directory. Next time you run the app, it still loads the old version of the DLL file, you have to be your heart! Seven, debug DLL program

Microsoft's VC is a valid tool for developing and testing DLLs, just running a debugger from the DLL project. When you do this, the debugger asks you the path to the Exe file. Since then, each time the DLL is run in the debugger, the debugger automatically loads the EXE file. The EXE file then discovers the DLL file with the above search sequence, which means that you have to set the PATH environment variable that allows it to contain the disk path to the DLL file, or you can copy the DLL file to the directory path in the search sequence.

转载请注明原文地址:https://www.9cbs.com/read-1195.html

New Post(0)