Link library dynamic link library details

  • 2020-04-01 21:24:53
  • OfStack

In Windows, there are two types of link libraries: static link libraries.lib and dynamic link libraries.dll. Among them, when the dynamic link library is used, usually also provides a. Lib, called import library, it mainly provides the function exported by the Dll and symbol name, so that when the link can find the corresponding function mapping in the Dll.
Static link libraries and dynamic link libraries are similar in that they are resources for other programs to call. Among them, the invocation methods of the dynamic link library are divided into implicit invocation (static import invocation) and display invocation (dynamic import invocation).  

Compile environment :
Microsoft Visual Stdio 2010
--------------------------------------------------------------------------------
DLL export symbol
For example, first generate a dll1.dll and dll1.lib
 
//DLL1 engineering, DLL1. CPP
//_declspec(dllexport) is the export symbol
_declspec(dllexport) int add(int a, int b) 
{ 
return a + b; 
} 

Use Microsoft's depends tool to view dll1.dll and export the following symbols:
(link: http://images.cnblogs.com/cnblogs_com/monotone/201211/201211161317592435.png)  
The meanings of the fields are Ordinal (symbol number, reference value when using GetProcAddress), Hint (I don't quite understand this, it is said that I don't need to understand), Function (this is the symbol name after the Function is exported), and EntryPoint (this is the address of the Function in DLL).
The reason why the name of the function is this way is that the compiler you use compiles by default in C++. Since C++ supports overloading, you need to add extra symbols to the function name to distinguish it from the overloaded function with the same name in order to locate it by symbol name in the DLL.
Here you can do a simple test, new console test project DllTest as follows.
 
//DllTest engineering, dlltest.cpp
#include <iostream> 
using namespace std; 
int main(void) 
{ 
// extern int add(int a, int b); 
//_declspec(dllimport) is an import declaration, which is more efficient than the above method and allows the compiler to compile more efficient code.
_declspec(dllimport) int add(int a, int b); 
cout << add(1,2) << endl; 
getchar(); 
return 0; 
} 

Unresolved external symbol "s (dllimport) int cdecl add(int,int)" (s) Referenced in function _main) referenced in function _main, the compiler obviously renamed the add function at compile time, just like the one from depends above. It means that the definition of this symbol was not found.

Add the code as follows :(note that the output directory of the two projects here is debugged in the same directory as the solution. To avoid copying the lib file again for each change, use the relative path declaration directly.)
 
//DllTest engineering, dlltest.cpp
#include <iostream> 
using namespace std; 
#pragma comment(lib, "../debug/dll1.lib") //The declaration shown is linked to dll1.lib for implicit invocation
int main(void) 
{ 
// extern int add(int a, int b); 
//_declspec(dllimport) is an import declaration, which is more efficient than the above method and allows the compiler to compile more efficient code.
_declspec(dllimport) int add(int a, int b); 
cout << add(1,2) << endl; 
getchar(); 
return 0; 
} 

After compiling and running, use the depends tool to view the dlltest.exe as follows:
(link: http://images.cnblogs.com/cnblogs_com/monotone/201211/201211161318006961.png)  
As you can see, dlltest.exe introduces a dependency on dll1.dll through dll1.lib.

--------------------------------------------------------------------------------

DLL provides the header file
Usually, when you get a.dll, you don't know which function calls it provides (exactly, how it's called). Because we can use the depends tool to look at the DLL's exported functions and their serial Numbers, there may be other ways to know how to use them, but we certainly can't know the internal implementation details. Therefore, in order to be easy to use, it is common to provide an.h file for the DLL to declare how and how it is provided to the client to use. This header file is used by the client to import the used interface. However, to avoid the declaration of these functions in many places, all interfaces are usually imported directly from the client in the.h file and used as exports when the Dll is compiled. Here's how:
 
//DLL1 project, dll1.h
#ifndef DLL1_API 
#define DLL1_API _declspec(dllimport) 
#endif 
//The above code indicates that if the DLL1_API macro is not defined before including the header file, then all subsequent DLL1_API macros are expanded to _declspec(dllimport), that is, imported.
//Because the client does not normally define the macro (assuming, of course, that the macro is not defined by any other file in the client), the client USES the header file for import.
DLL1_API int add(int a, int b); 

 
//DLL1 engineering, DLL1. CPP
#define DLL1_API _declspec(dllexport) 
//Note that the above line defines the DLL1_API macro before the header file is included so that the DLL1_API in the header file is expanded to _declspec(dllexport) to declare the function as an export.
#include "dll1.h" 
//Export declared functions in the header file, do not declare exports.
int add(int a, int b) 
{ 
return a + b; 
} 

Accordingly, after the TestDll project contains the.h file, there is no need to declare it.
 
//DllTest engineering, dlltest.cpp
#include <iostream> 
using namespace std; 
#include "../dll1/dll1.h" //Once the header file is included, there is no need to declare it later
#pragma comment(lib, "../debug/dll1.lib") //The declaration shown is linked to dll1.lib for implicit invocation
int main(void) 
{ 
cout << add(1,2) << endl; 
getchar(); 
return 0; 
} 

This basically explains why DLLS are usually referred to with a header file, and there's a lot of #ifndef in the header file.

--------------------------------------------------------------------------------
Dynamically linked libraries export classes
Of course, the dynamic link library can also export classes, note that it is declared in class ll1_api CSample, not DLL1_API class CSample.
Also, note that when you export a class, all its member functions are also exported, but the class member variable access restrictions are still followed.
If the member functions of a class are exported separately (declared in the same way as global functions), then the class object can be instantiated on the client side and the exported member functions can be called, not the unexported member functions (even if public).

--------------------------------------------------------------------------------
An adapted symbol name
When you export symbols, you learned that C++ rewrites function names to support function overloading. Then there is a problem, if you use a different C++ compiler (resulting in a different symbol name) or the client USES a C compiler call, there will be a link error such as LNK2019, can not find the symbol. This problem greatly limits the use of DLLS.
Solution 1:
Use extern "C" (note that this C must be capitalized) to indicate that the function is compiled in C. This problem can be avoided by compiling the exported functions in C without rearranging the symbol names.
 
//DLL1 project, dll1.h
#ifndef DLL1_API 
#define DLL1_API extern "C" _declspec(dllimport) 
#endif 
//The above code indicates that if the DLL1_API macro is not defined before including the header file, then all subsequent DLL1_API macros are expanded to _declspec(dllimport), that is, imported.
//Because the client does not normally define the macro (assuming, of course, that the macro is not defined by any other file in the client), the client USES the header file for import.
DLL1_API int add(int a, int b); 
//class CSample 
//{ 
//public: 
// DLL1_API int substract(int a,int b);//  In this case, the derived class member function, the compilation cannot pass  
//}; 

Note that both.h and.cpp have extern "C" added so that both imports and exports are compiled in C.
 
//DLL1 engineering, DLL1. CPP
#define DLL1_API extern "C" _declspec(dllexport) 
//Note that the above line defines the DLL1_API macro before the header file is included so that the DLL1_API in the header file is expanded to _declspec(dllexport) to declare the function as an export.
#include "dll1.h" 
//Export declared functions in the header file, do not declare exports.
int add(int a, int b) 
{ 
return a + b; 
} 
// 
//int CSample::substract(int a,int b) 
//{ 
// return a - b; 
//} 

Then use depends to check:
(link: http://images.cnblogs.com/cnblogs_com/monotone/201211/2012111613180059.png)  
The exported function symbol name is the same as when the function was declared. Since the import is also used in the extern "C" manner by the client, the client also USES the function's original name notation when compiling the link.
Shows that C++ classes and member functions cannot be exported in this way because of the C compile-link approach.
In addition, if we add the standard calling convention to the function declaration: DLL1_API int _stdcall add(int a, int b); Note that _stdcall is also added to the function definition. So the result is determined using depends and the symbol is called _add@8, which means the symbol name is changed again.
Solution 2:
Use the module definition file. Def, this file format specification to view MSDN, search. Def. The LIBRARY command is used to name the def file for exporting the LIBRARY file, and EXPORTS is used to name the exported function symbol name. That is, the.def file is mainly used to control information such as export symbols.
 
LIBRARY dll1 
EXPORTS 
add11=add 

I'm going to call the add function add11, but notice that we also need to declare add as add11 in the.h file. Once the.def is provided, any calling convention provided in.cpp is no longer valid because.def specifies the generated symbol name. Here, as long as you understand that.def controls the Dll's export symbol, when the client USES it, as long as you provide a declaration and link to the.lib file, you can use it.
Add: VC6.0 after the IDE in the LINK option in the input- "module define file, specify. Def file, compiler will use this. Def file.

Remark:
I'm a bit confused right now about calling conventions and whether or not extern "C" is added. After the understanding, then come here to supplement, welcome visitors to provide me with a better introduction of this piece of information.

--------------------------------------------------------------------------------
Display link (dynamic import link)
As mentioned earlier, the exported function has no name, so how can the client call it? You can use ordinal in the symbol table (which you can view with the tool), or you can import using the function name. Dynamic imports do not require lib files and.h files (if you know the function name).
 
//DllTest engineering, dlltest.cpp
#include <iostream> 
using namespace std; 
#include <windows.h> 
int main(void) 
{ 
HMODULE hModule = ::LoadLibraryA("dll1.dll"); 
if(NULL != hModule) 
{ 
typedef int (*ADDPROC)(int a, int b); 
//ADDPROC add = (ADDPROC)::GetProcAddress(hModule, "add11"); //  Import by function name  
ADDPROC add = (ADDPROC)::GetProcAddress(hModule, MAKEINTRESOURCEA(1)); //With the ordinal import, notice that the second parameter is placed ina low byte position, as shown in the MSDN instructions.
if(NULL != add) 
cout << add(1,1) << endl; 
::FreeLibrary(hModule); 
} 
getchar(); 
return 0; 
} 

It is worth mentioning that when dynamic imports are based on function names, they are actually based on symbol names, that is, the symbol names provided by the DLL are the same as the function declarations provided to the user.

In addition, when dynamic link library is imported, the required input information cannot be seen when.exe.

--------------------------------------------------------------------------------
Afterword.
The first time I wrote such a detailed and long blog post, it can be seen that the writing has become increasingly rough. Because by the time you get to the end, you don't know what you're going to write, because if you go any further, you're going to have too much to add. At the same time, part of the reason is that I don't understand the following content very well and use it very little. Anyway, I'm pretty messed up right now. Here I would like to express my deep admiration for those who write blogs.

Finally, I would like to state that these are my own reference videos to sort out and summarize, there must be some unprofessional or even wrong places, please kindly provide guidance, I will timely modify after learning and understanding, thank you.

Related articles: