DLL compiling tutorial

Source: Internet
Author: User
Document directory
  • DLL advantages
  • The simplest dll
  • Load DLL (explicit call)
  • Run the dumpbin command to view functions in the DLL.
  • How to define output functions in dll
  • Def File
  • Explicitly call functions in DLL
  • _ Declspec (dllexport)
  • Extern "C"
  • Call DLL implicitly
  • _ Declspec (dllexport) and _ declspec (dllimport) pairs
  • Global variables and objects in DLL
  • Summary
  • Explicit call and implicit call
  • Def and _ declspec (dllexport)
  • Call DLL from other languages
  • Compile DLL in VC

 

This article makes a summary of the common DLL technology and provides the following download and package source code:

Http://www.blogjava.net/Files/wxb_nudt/DLL_SRC.rar

DLL advantages

To put it simply, dll has the following advantages:

1) memory saving. If the same software module is reused in the form of source code, it will be compiled into different executable programs, the binary codes of these modules are repeatedly loaded into the memory when these exe files are run at the same time. If dll is used, it is loaded only once in the memory. All processes that use the dll will share the memory (of course, something like global variables in dll will be copied by every process ).

2) if a software system uses a dll, the dll is changed (the function name remains unchanged, you do not need to recompile the entire system. In fact, many software are upgraded in this way. For example, the versions of games we often play, such as Starcraft and Warcraft, are also upgraded.

3) The Dll library can be used in multiple programming languages. For example, a dll written in c can be called in vb. At this point, DLL is not enough. Therefore, the COM technology was invented Based on dll to better solve a series of problems.

The simplest dll

Before writing a dll, you need a c/c ++ compiler and a linker and close your IDE. Yes, turn off your VC, C ++ BUILDER, and other things, and open the Notepad program that you used to only use to remember the phone. Otherwise, you may never understand the true meaning of the dll. I used the cl compiler and link linker that comes with VC. They are generally in the bin directory of vc. (If you do not select to register environment variables when installing vc, add their paths to path immediately.) If you are afraid of crying because you have left IDE, you can close this page and continue reading boring books such as VC ++ technical insider.

The simplest dll is not more difficult than c's helloworld. It only needs a DllMain function, including the objbase. h header file (a header file supporting COM technology ). If you think the header file name is hard to remember, you can use windows. H. The source code is as follows: dll_nolib.cpp

# Include <objbase. h>

# Include <iostream. h>

Bool apientry DllMain (HANDLE hModule, DWORD dwReason, void * lpReserved)

{

HANDLE g_hModule;

Switch (dwReason)

{

Case DLL_PROCESS_ATTACH:

Cout <"Dll is attached! "<Endl;

G_hModule = (HINSTANCE) hModule;

Break;

Case DLL_PROCESS_DETACH:

Cout <"Dll is detached! "<Endl;

G_hModule = NULL;

Break;

}

Return true;

}

DllMain is the entry function of each dll, just like the main function of c. DllMain has three parameters. hModule indicates the instance handle of the dll (ignore it if you do not understand it, but understand it if you have written a windows program). dwReason indicates the current status of the dll, for example, DLL_PROCESS_ATTACH indicates that the dll has just been loaded into a process, and DLL_PROCESS_DETACH indicates that the dll has just been detached from a process. Of course, it also indicates the state of loading to and detaching from the thread, Which is omitted here. The last parameter is a reserved parameter (currently it is related to some dll states, but rarely used ).

From the above program, we can see that when the dll is loaded into a process, the dll prints "Dll is attached! "Statement; when the dll is detached from the process, print" Dll is detached! "Statement.

To compile a dll, you need the following two commands:

Cl/c dll_nolib.cpp

This command compiles cpp into an obj file. If the/c parameter is not used, cl tries to continue linking obj to exe, but here is a dll without the main function, therefore, an error is reported. It doesn't matter. continue to use the link command.

Link/dll dll_nolib.obj

This command generates dll_nolib.dll.

Note: The compilation command is relatively simple, so this article does not discuss nmake. If you are interested, you can use nmake or write a bat batch to compile the link dll.

Load DLL (explicit call)

There are two methods to use dll: explicit call and implicit call. Here we will first introduce explicit calls. Write a client program: dll_nolib_client.cpp

# Include <windows. h>

# Include <iostream. h>

Int main (void)

{

// Load our dll

HINSTANCE hinst =: LoadLibrary ("dll_nolib.dll ");

If (NULL! = Hinst)

{

Cout <"dll loaded! "<Endl;

}

Return 0;

}

Note: when calling the dll using the LoadLibrary function, its parameters are the dll path and name, and the return value is the dll handle. Use the following command to compile and link the client:

Cl dll_nolib_client.cpp

Run dll_nolib_client.exe and get the following result:

Dll is attached!

Dll loaded!

Dll is detached!

The above results indicate that the dll has been loaded by the client. However, in this way, only the dll can be loaded into the memory, and the functions in the dll cannot be found.

Run the dumpbin command to view functions in the DLL.

Run the Dumpbin command to view the name of the output function in a dll. Enter the following command:

Dumpbin-exports dll_nolib.dll

You can see that dll_nolib.dll does not output any function.

How to define output functions in dll

In general, there are two methods. One is to add a def definition file, in which the function to be output in the dll is defined; the second is to add the _ declspec (dllexport) keyword before the function to be output in the source code.

Def File

First, write a dll with an output function. The source code is as follows: dll_def.cpp

# Include <objbase. h>

# Include <iostream. h>

Void FuncInDll (void)

{

Cout <"FuncInDll is called! "<Endl;

}

Bool apientry DllMain (HANDLE hModule, DWORD dwReason, void * lpReserved)

{

HANDLE g_hModule;

Switch (dwReason)

{

Case DLL_PROCESS_ATTACH:

G_hModule = (HINSTANCE) hModule;

Break;

Case DLL_PROCESS_DETACH:

G_hModule = NULL;

Break;

}

Return TRUE;

}

The def file of this dll is as follows: dll_def.def

;

; Dll_def module-definition file

;

LIBRARY dll_def.dll

DESCRIPTION '(c) 2007-2009 Wang Xuebin'

EXPORTS

FuncInDll @ 1 PRIVATE

You will find that the syntax of def is very simple. First, it is the LIBRARY keyword, specifying the dll name; then an optional keyword DESCRIPTION, followed by copyright and other information (either not written ); the last is the EXPORTS keyword, followed by all the function names or variable names to be output in the dll, followed by @ and numbers (from 1 to N), and finally the modifier.

Use the following command to compile a dll with a def file:

Cl/c dll_def.cpp

Link/dll dll_def.obj/def: dll_def.def

Call dumpbin to view the generated dll_def.dll:

Dumpbin-exports dll_def.dll

The following result is displayed:

Dump of file dll_def.dll

File Type: DLL

Section contains the following exports for dll_def.dll

0 characteristics

46E4EE98 time date stamp Mon Sep 10 15:13:28 2007

0.00 version

1 ordinal base

1 number of functions

1 number of names

Ordinal hint RVA name

1 0 00001000 FuncInDll

Summary

2000. data

1000. rdata

1000. reloc

6000. text

Observe this line

1 0 00001000 FuncInDll

The dll outputs the FuncInDll function.

Explicitly call functions in DLL

Write a client program for dll_def.dll: dll_def_client.cpp

# Include <windows. h>

# Include <iostream. h>

Int main (void)

{

// Define a function pointer

Typedef void (* DLLWITHLIB) (void );

// Define a function pointer variable

DLLWITHLIB pfFuncInDll = NULL;

// Load our dll

HINSTANCE hinst =: LoadLibrary ("dll_def.dll ");

If (NULL! = Hinst)

{

Cout <"dll loaded! "<Endl;

}

// Find the dll FuncInDll Function

PfFuncInDll = (DLLWITHLIB) GetProcAddress (hinst, "FuncInDll ");

// Call the functions in the dll

If (NULL! = PfFuncInDll)

{

(* PfFuncInDll )();

}

Return 0;

}

There are two points worth noting: the first is the definition and use of function pointers. If you don't understand them, you can look for this c ++ book. The second is the use of GetProcAddress, this API is used to find the function address in the dll. The first parameter is the DLL handle, that is, the handle returned by LoadLibrary, and the second parameter is the function name in the dll, that is, the name of the function output in dumpbin (note that the function name here refers to the compiled function name, not necessarily the name of the function in the dll source code ).

Compile and link the client program and run the following command:

Dll loaded!

FuncInDll is called!

This indicates that the client successfully calls the function FuncInDll In the dll.

_ Declspec (dllexport)

It is complicated to write def for each dll. Currently, def is rarely used, and _ declspec (dllexport) is used to define the dll output function in the source code.

Dll is written in the same way as above. Remove the def file and add the Declaration _ declspec (dllexport) before each function to be output. For example:

_ Declspec (dllexport) void FuncInDll (void)

Here we provide a dll source program dll_withlib.cpp, and then compile the link. You do not need to specify the/DEF: parameter when linking. Simply add the/DLL parameter,

Cl/c dll_withlib.cpp

Link/dll dll_withlib.obj

Run the dumpbin command to view the result:

1 0 00001000? FuncInDll @ YAXXZ

The name of the compiled function is? FuncInDll @ YAXXZ, not FuncInDll. This is because the c ++ compiler will change the function name based on the function overload considerations. When explicit calling is used, you must also use the changed function name, which is obviously troublesome for the customer. To avoid this problem, you can use the extern "C" command to command the c ++ compiler to name the function in the form of a c compiler. The modified function declaration is:

Extern "C" _ declspec (dllexport) void FuncInDll (void)

Dumpbin command result:

1 0 00001000 FuncInDll

In this way, you only need to find the function named FuncInDll for explicit calling.

Extern "C"

Using the extern "C" keyword is actually equivalent to a compiler switch. It can compile a function in c ++ into a function name in C language. That is, keep the compiled function symbol name equal to the function name in the source code.

Call DLL implicitly

Explicit calling is very complex. Every time LoadLibrary is required, and each function must use GetProcAddress to obtain the function pointer. This is a problem for a large number of users who use dll functions. Implicit calling can use functions in dll like using c function libraries, which is very convenient and quick.

The following is an implicit call example: dll contains two files: dll_withlibAndH.cpp and dll_withlibAndH.h.

The Code is as follows: dll_withlibAndH.h

Extern "C" _ declspec (dllexport) void FuncInDll (void );

Dll_withlibAndH.cpp

# Include <objbase. h>

# Include <iostream. h>

# Include "dll_withLibAndH.h" // No. This is the header file we added.

Extern "C" _ declspec (dllexport) void FuncInDll (void)

{

Cout <"FuncInDll is called! "<Endl;

}

Bool apientry DllMain (HANDLE hModule, DWORD dwReason, void * lpReserved)

{

HANDLE g_hModule;

Switch (dwReason)

{

Case DLL_PROCESS_ATTACH:

G_hModule = (HINSTANCE) hModule;

Break;

Case DLL_PROCESS_DETACH:

G_hModule = NULL;

Break;

}

Return TRUE;

}

Compile the link command:

Cl/c dll_withlibAndH.cpp

Link/dll dll_withlibAndH.obj

When performing an implicit call, you need to introduce the header file on the client and specify the lib file corresponding to the dll During the Link (if the dll has function output, the link will generate a lib file with the same name as the dll) location and name. Then, call the functions in the dll just like the functions in the api function library, without the explicit LoadLibrary and GetProcAddress. It is the most convenient to use. The client code is as follows: dll_withlibAndH_client.cpp

# Include "dll_withLibAndH.h"

// Note the path. Another method for loading dll is Project | setting | link

# Pragma comment (lib, "dll_withLibAndH.lib ")

Int main (void)

{

FuncInDll (); // as long as this is done, we can call the functions in the dll.

Return 0;

}

_ Declspec (dllexport) and _ declspec (dllimport) pairs

The above implicit call method is good, but problems may occur when calling objects in DLL and overload functions. Because the output functions are modified using extern "C", the overload functions are certainly problematic because they will all be compiled into the same output symbol string (the C language does not support overloading ).

In fact, it is feasible not to use extern "C". In this case, the function will be compiled into a c ++ symbol string, for example (? FuncInDll @ YAXH @ Z ,? FuncInDll @ YAXXZ), which can be called correctly and implicitly when the client is also c ++.

Consider the following situation: If DLL1.CPP is the source, DLL2.CPP uses the function in DLL1, but DLL2 is also a DLL, and some functions must be output for Client. CPP. In DLL2, how can we declare all functions, including the functions introduced from DLL1 and the functions to be output. In this case, you need to use both _ declspec (dllexport) and _ declspec (dllimport. The former is used to modify the output functions in this dll, and the latter is used to modify the functions introduced from other dll.

All source codes include DLL1.H, DLL1.CPP, DLL2.H, DLL2.CPP, and Client. cpp. The source code can be found in the downloaded package. You can compile the link and run it.

It is worth noting that a encoding method is used in both DLL1 and DLL2. For details, see DLL2.H.

# Ifdef DLL_DLL2_EXPORTS

# Define DLL_DLL2_API _ declspec (dllexport)

# Else

# Define DLL_DLL2_API _ declspec (dllimport)

# Endif

DLL_DLL2_API void FuncInDll2 (void );

DLL_DLL2_API void FuncInDll2 (int );

Define the macros DLL_DLL2_EXPORTS and DLL_DLL2_API in the header file in this way to ensure that the functions of the DLL end are modified with _ declspec (dllexport), while the functions of the client end are modified with _ declspec (dllimport. Of course, remember to add the parameter/D "DLL_DLL2_EXPORTS" when compiling the dll, or simply add # define DLL_DLL2_EXPORTS to the first line of the dll cpp file.

The code generated by VC is also like this! It turns out that I copied it, hoho!

Global variables and objects in DLL

Solve the Problem of overload functions, so the global variables and objects in the dll are not a problem, but there is a little attention to the syntax. As shown in the source code: dll_object.h

# Ifdef DLL_OBJECT_EXPORTS

# Define DLL_OBJECT_API _ declspec (dllexport)

# Else

# Define DLL_OBJECT_API _ declspec (dllimport)

# Endif

DLL_OBJECT_API void FuncInDll (void );

Extern DLL_OBJECT_API int g_nDll;

Class DLL_OBJECT_API CDll_Object {

Public:

CDll_Object (void );

Show (void );

// TODO: add your methods here.

};

The Cpp file dll_object.cpp is as follows:

# Define DLL_OBJECT_EXPORTS

# Include <objbase. h>

# Include <iostream. h>

# Include "dll_object.h"

DLL_OBJECT_API void FuncInDll (void)

{

Cout <"FuncInDll is called! "<Endl;

}

DLL_OBJECT_API int g_nDll = 9;

CDll_Object: CDll_Object ()

{

Cout <"ctor of CDll_Object" <endl;

}

CDll_Object: show ()

{

Cout <"function show in class CDll_Object" <endl;

}

Bool apientry DllMain (HANDLE hModule, DWORD dwReason, void * lpReserved)

{

HANDLE g_hModule;

Switch (dwReason)

{

Case DLL_PROCESS_ATTACH:

G_hModule = (HINSTANCE) hModule;

Break;

Case DLL_PROCESS_DETACH:

G_hModule = NULL;

Break;

}

Return TRUE;

}

After the compilation link is complete, Dumpbin will show that five symbols are output:

1 0 00001040 ?? 0CDll_Object @ QAE @ XZ

2 1 00001000 ?? 4CDll_Object @ QAEAAV0 @ ABV0 @ Z

3 2 00001020? FuncInDll @ YAXXZ

4 3 00008040? G_nDll @ 3HA

5 4 00001069? Show @ CDll_Object @ QAEHXZ

They represent CDll_Object, constructor, FuncInDll, global variable g_nDll, and member function show of the class respectively. The following is the client code: dll_object_client.cpp

# Include "dll_object.h"

# Include <iostream. h>

// Note the path. Another method for loading dll is Project | setting | link

# Pragma comment (lib, "dll_object.lib ")

Int main (void)

{

Cout <"call dll" <endl;

Cout <"call function in dll" <endl;

FuncInDll (); // as long as this is done, we can call the functions in the dll.

Cout <"global var in dll g_nDll =" <g_nDll <endl;

Cout <"call member function of class CDll_Object in dll" <endl;

CDll_Object obj;

Obj. show ();

Return 0;

}

Run this client and you will see:

Call dll

Call function in dll

FuncInDll is called!

Global var in dll g_nDll = 9

Call member function of class CDll_Object in dll

Ctor of CDll_Object

Function show in class CDll_Object

We can see that the client successfully accesses the global variables in the dll, creates the C ++ object defined in the dll, and calls the member functions of the object.

Summary

Keep in mind that, in the end, DLL is a dynamic link technology corresponding to C language, which is convenient and quick to output C Functions and variables. In addition, various means are required to Output C ++ classes and functions, and there is no perfect solution, unless the client is also c ++.

Remember, only COM is a technology that corresponds to the C ++ language.

The following is a summary of each problem.

Explicit call and implicit call

When is explicit call used? When to use implicit call? In my opinion, it is reasonable to use explicit calls only when the client is not C/C ++. In this case, it cannot be called implicitly. For example, use VB to call the dll written in C ++. (Vb I won't, so there is no example)

Def and _ declspec (dllexport)

In fact, def functions are equivalent to extern "C" _ declspec (dllexport), so it can only process C functions, rather than overload functions. The use of _ declspec (dllexport) and _ declspec (dllimport) can adapt to any situation. Therefore, _ declspec (dllexport) is a more advanced method. Therefore, the general view is that def files are not used. I also agree with this view.

Call DLL from other languages

Calling DLL from other programming languages has two major problems: the first is the function symbol problem, which has been mentioned many times. There is a dilemma here. If extern "C" is used, the function name remains unchanged and the call is convenient, but a series of c ++ functions such as function overloading are not supported; if you do not use extern "C", you need to check the compiled symbols before calling. this is inconvenient.

The second problem is the function call pressure stack sequence, namely _ cdecl and _ stdcall. _ Cdecl is a conventional C/C ++ call convention. In such a call convention, the caller completes the stack cleanup after a function call. _ Stdcall is a standard call Convention, that is, these functions will delete the parameters from the stack before they are returned to the caller.

These two problems cannot be solved very well by using the DLL. But in COM, the solution is perfect. Therefore, to achieve language independence on the Windows platform, you must use COM middleware.

All in all, unless the client also uses C ++, dll is not easy to support function overloading, class and other c ++ features. DLL supports c functions very well. I think this is one of the reasons why windows function libraries use C + dll.

Compile DLL in VC

It is very convenient to create, compile, and Link dll in VC. Click file à New à Project à Win32 Dynamic-Link Library, enter the dll name dll_InVC, and then click OK. Select a dll that export some symbols and click Finish. To obtain a complete DLL.

Check the source code carefully. Are there many places that seem familiar? haha!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.