4.2 Declaring the exported function
There are two ways to declare a function in a DLL: one for the 4.1-section example, plus __declspec (dllexport) in the function declaration, which is no longer illustrated here; another way is to use the module definition (. def) file declaration,. The DEF file provides the linker with information about the exported, attributes, and other aspects of the linked program.
The following code shows how to do the same. DEF file declares function add as DLL export function (you need to add Lib.def file in Dlltest project):
; Lib.def: Exporting DLL functions
Add @ 1
The rules for the. def file are:
(1) Description of the library statement. def file with the corresponding DLL;
(2) Lists the names of the functions to be exported after the exports statement. can be in. DEF file, the exported function name is added @n, which means that the ordinal number of the function to be exported is n (the ordinal number will play its role when the function call is made);
(3). The annotations in the Def file are separated by semicolons at the beginning of each comment line (;) specified, and the comment cannot share a row with the statement.
As you can see, the meaning of the Lib.def file in the example is to generate a dynamic-link library named "Dlltest", export the Add function, and specify the add function with an ordinal number of 1.
How the 4.3 DLL is invoked
In the 4.1 section example, we see the "Loadlibrary-getprocaddress-freelibrary" system API provided by the Trinity "DLL load-dll function address get-dll release" way, this call is called DLL dynamic invocation.
The feature of dynamic invocation is that the DLL is loaded and unloaded entirely by the programmer with API functions, and programmers can decide when the DLL file is loaded or not loaded, and the explicit link determines which DLL file to load at run time.
The corresponding to the dynamic call mode is the static calling mode, "there is action must have static", which originates from the unity of opposites of the material world. "Dynamic and Static", its opposition and unity has been countless times in the field of technology has been validated, such as static IP and DHCP, static routing and dynamic routing. As we already know, the library is divided into static library and dynamic library DLL, and unexpectedly, deep into the DLL, its calling mode is also divided into static and dynamic. "Move and quiet", everywhere. The book of Zhouyi has realized that there is a static and dynamic balance of movement, Yi. Words: "The movement has often, rigid-flexible broken." Philosophy means a universal truth, so we can often see the shadow of philosophy in the dull technical field.
The static invocation is characterized by a compilation system that completes the loading of the DLL and unloads the DLL at the end of the application. When the application that calls a DLL ends, Windows uses the DLL's application record minus 1 if there are other programs in the system that will not be released until all programs using the DLL end. Static invocation method is simple and practical, but not as flexible as dynamic invocation.
Let's take a look at the static invocation example (click here to download the project attachment) to compile the Dlltest project generated. Lib and. DLL file into the path where the Dllcall project is located, Dllcall executes the following code:
#pragma comment (lib, "DllTest.lib")
The. lib file is just a relocation of a function in its corresponding DLL file
extern "C" __declspec (dllimport) Add (int x,int y);
int main (int argc, char* argv)
int result = Add (2,3);
printf ("%d", result);
As can be seen from the above code, the static invocation of the smooth conduct of the need to complete two actions:
(1) Tell the compiler to correspond to the DLL. The path and filename of the lib file, #pragma comment (lib, "DllTest.lib") is the role.
When a programmer creates a DLL file, the connector automatically generates a corresponding one for it. LIB file, which contains the symbol name and ordinal number of the DLL export function (does not contain actual code). In the application,. The Lib file participates in the compilation as an alternate file for the DLL.
(2) Declare the import function, and the __declspec (dllimport) in the extern "C" __declspec (dllimport) Add (int x,int y) statement plays this role.
The static invocation method no longer requires the use of the system APIs to load, unload, and get the address of the exported function in the DLL. This is because, when the programmer compiles the build application through a static link, the application calls the. The function symbols that match the exported symbols in the Lib file are entered into the generated EXE file. The file name of the DLL file contained in the Lib file is also stored inside the exe file by the compiler. When the application is running and the DLL file needs to be loaded, Windows discovers and loads the DLL based on that information, and then implements dynamic links to the DLL functions through the symbol name. In this way, the EXE will be able to invoke the DLL's output function directly through the function name, just as other functions inside the program call.
4.4 DllMain function
When Windows loads a DLL, it needs a portal function, just as a console or DOS program requires a main function, the WIN32 program needs the WinMain function. In the previous example, the DLL did not provide the DllMain function, and the application engineering succeeded in referencing the DLL, because Windows would introduce a default DllMain function version from other runtime libraries that did not do anything when DllMain was 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. This means that the DllMain function cannot be referenced directly in the application engineering, and DllMain is automatically invoked.
Let's look at an example of a DllMain function (click here to download the project attachment).
BOOL apientry DllMain (HANDLE hmodule,
printf ("Process attach of DLL");
printf ("Thread Attach of DLL");
printf ("Thread Detach of DLL");
printf ("Process detach of DLL");
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, Ul_reason_for_call indicates the reason for the call. There are 4 reasons, namely Process_attach, Process_detach, Thread_attach, and Thread_detach, listed in the switch statement.
To read the DllMain function head bool apientry DllMain (HANDLE hmodule, WORD ul_reason_for_call, LPVoid lpreserved).
Apientry is defined as __stdcall, which means that the function is invoked in standard Pascal mode, which is the WINAPI method;
Each DLL module in the process is identified by a globally unique 32-byte hinstance handle, which represents the starting address of the DLL module in the process virtual space only if it is valid within a particular process. In Win32, the values of hinstance and hmodule are the same, and the two types can be substituted, which is the origin of the function parameter hmodule.
Execute the following code:
hDLL = LoadLibrary ("DebugdllTest.dll");
if (hDLL!= NULL)
Addfun = (lpaddfun) GetProcAddress (hDLL, Makeintresource (1));
Makeintresource directly using the serial number in the export file
if (Addfun!= NULL)
int result = Addfun (2, 3);
printf ("Call Add in dll:%d", result);
We see the output order as:
Process Attach of DLL
Call Add in Dll:5
Process Detach of DLL
This output sequence verifies the timing of DllMain being invoked.
The code in the GetProcAddress (hDLL, Makeintresource (1)) is noteworthy and it is passed directly. The order number specified for the Add function in the DEF file accesses the Add function, embodied in makeintresource (1), and Makeintresource is a macro that obtains the function name by ordinal, defined as (excerpt from Winuser.h):
#define MAKEINTRESOURCEA (i) (LPSTR) ((DWORD) (WORD) (i))
#define MAKEINTRESOURCEW (i) (LPWSTR) ((DWORD) (WORD) (i))
#define MAKEINTRESOURCE Makeintresourcew
#define MAKEINTRESOURCE Makeintresourcea
4.5 __stdcall Convention
If the DLL written by VC + + to be written in other languages of the program calls, the function should be declared as a __stdcall way, WINAPI All in this way, while the C + + default invocation method is __cdecl. The __stdcall method differs from the __cdecl in the way that the function name ultimately generates the symbol. In the case of C compilation (in C + + to declare a function as extern "C"), the __stdcall calling convention underlines the output function name followed by the "@" symbol and the number of bytes in the parameter, in the form of _functionname@number; The cdecl calling convention underlines only the output function name, in the form of _functionname.
Several common function type declaration macros in Windows programming are related to __stdcall and __cdecl (excerpt from windef.h):
#define CALLBACK __stdcall//This is the legendary callback function.
#define WINAPI __stdcall//This is the legendary WINAPI.
#define WINAPIV __cdecl
#define APIENTRY WINAPI//dllmain's entrance is right here.
#define Apiprivate __stdcall
#define PASCAL __stdcall
In Lib.h, you should declare the Add function this way:
int __stdcall Add (int x, int y);
function pointer types in application engineering should be defined as:
typedef int (__stdcall *lpaddfun) (int, int);
If the function is declared as a __stdcall call in Lib.h, and the typedef int (* lpaddfun) (int,int) is still used in the application engineering, the runtime will have an error (because the type does not match and is still the default __cdecl call in the application engineering). POPs up the dialog box as shown in Figure 7.
Figure 7 Run error when the calling convention does not match
The passage in Figure 8 actually gives the wrong reason for the error, namely "This is usually a.".