C++dll Programming Detailed

Source: Internet
Author: User
Tags export class types of functions

DLL (Dynamic Link Library), you can simply think of a DLL as a repository that provides you with variables, functions, or classes that you can use directly. In the history of the warehouse has experienced the "No library-static link library-dynamic link library" era.

Both static and dynamic link libraries are shared code, and if you use a static link library, the instructions in Lib are included directly in the resulting EXE file, whether you want to or not. However, if you use a DLL, the DLL does not have to be included in the final EXE file, exe file can be "dynamically" to reference and unload the DLL file with EXE Independent. Another difference between a static-link library and a dynamic-link library is that the static-link library can no longer contain other dynamic-link libraries or static libraries, and other dynamic or static link libraries may be included in the dynamic-link library.

Dll:

(1) DLL is not related to specific programming language and compiler
  DLLs written in various languages can call each other as long as they follow the agreed specification and invocation of DLL interfaces . For example, Windows provides a system DLL (which includes Windows APIs) that can be called in any development environment, regardless of whether it is visual Basic, Visual C + +, or Delphi.

(2) dynamic link library everywhere
We see in the System32 folder in the Windows directory that most of the APIs for Kernel32.dll, User32.dll, and Gdi32.dll,windows are included in these DLLs. The functions in Kernel32.dll mainly handle the memory management and process scheduling, the functions in User32.dll mainly control the user interface, and the functions in Gdi32.dll are responsible for the operation of Graphics.

General programmers have used a function like the MessageBox, which is actually included in the User32.dll Dynamic link library. This shows that DLLs are not unfamiliar to us.

(3) The classification of VC dynamic link Library
Visual C + + supports three types of DLLs, namely NON-MFC DLLs (non-MFC dynamic Libraries), MFC Regular DLLs (MFC regular DLLs), MFC Extension DLLs (MFC extension DLLs).

Non-MFC Dynamic Library: Does not adopt the MFC class library structure, its export function is the standard C interface, can be called by non-MFC or MFC-written applications;

MFC Rule DLL: Contains a class that inherits from CWinApp, but its no message loop

MFC extension DLL: Created with the dynamic Link version of MFC, it can only be called by an application written by the MFC class library.

Lib:

Create a new static library project called Libtest in vc++6.0, and create a new lib.h and lib.cpp two files, with the following source code for Lib.h and Lib.cpp:
Files: lib.h
#ifndef Lib_h
#define Lib_h
extern "C" int Add (int x,int y); External functions declared as C join mode
#endif

Files: lib.cpp
#include "Lib.h"
int add (int x,int y)
{
return x + y;
}

Compile this project to get a. lib file, which is a library of functions that provides the functionality of Add. Once the header file and the. lib file are submitted to the user, the user can directly use the Add function.

How to use this library, create a new Libcall project. The Libcall project contains only a single main.cpp file,

#include
#include "Path \lib.h"
#pragma comment (lib, "Path \\libTest.lib")//Specify to connect with the static library
int main (int argc, char* argv[])
{
printf ("2 + 3 =%d", add (2, 3));
}

#pragma comment (lib, "path \\libTest.lib") means that the. obj file generated by this file should be connected with libTest.lib.

If you do not use #pragma comment specified, you can directly in VC + + settings, select Tools, Options, directories, library files menu or options, fill in the library file path.

Non-MFC DLLs:

The above gives the method of providing an add function interface in the form of a static link library, and then see how to implement an add function with the same function using the dynamic link library. In VC + + to create a new Win32 Dynamic-link library project Dlltest. Note Do not select MFC AppWizard (DLL).
Add MyDll.h and MyDll.cpp files to the established project, the source code is as follows:

/* File name: MyDll.h */

#ifndef Mydll_h

#define Mydll_h

extern "C" int __declspec (dllexport) Add (int x, int y); Declaring the function add as the exported function of the DLL

#endif


/* File name: MyDll.cpp */

#include "MyDll.h"

int add (int x, int y)

{

return x + y;

}

Call Mode:

To build the application engineering Dllcall, it calls the function add in the DLL, whose source code is as follows:


#include <stdio.h>

#include <windows.h>

typedef int (*lpaddfun) (int, int); Macro definition function pointer type

int main (int argc, char *argv[])

{

HINSTANCE hDLL; DLL handle

Lpaddfun Addfun; function pointers

hDLL = LoadLibrary ("Path \\dllTest.dll");

if (hdll! = NULL)

{

Addfun = (lpaddfun) GetProcAddress (hDLL, "add");

if (addfun! = NULL)

{

int result = Addfun (2, 3);

printf ("%d", result);

}

FreeLibrary (hDLL);

}

return 0;

}

There are two types of functions within a DLL:

(1) DLL export function, can be called by external application;

(2) DLL intrinsic function, which can only be used in DLLs.

There are two ways to declare declarations for exported functions in a DLL:

A __declspec is added to the function declaration (dllexport;

Another way is to use the module definition (. def) file declaration, which provides the linker with information about the exported, attributes, and other aspects of the linked program. The following code demonstrates how to declare a function add as a DLL export function with a. def file

; Lib.def: Exporting DLL functions

LIBRARY Dlltest

Exports

Add @ 1

The rules for def files are:

(1) The library statement describes the corresponding DLL for the. def file;

(2) The name of the function to be exported is listed after the exports statement. You can add @n to the exported function name in a. def file to indicate the ordinal of the function to be exported

is n (the sequence number will play its role when the function call is made);

(3) The comments in the. def file are separated by a semicolon 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 ordinal of the Add function as 1.

How DLLs are called:

Dynamic invocation: The "Loadlibrary-getprocaddress-freelibrary" System API provides DLL-loaded-dll function addresses to get the-dll release method. As the example above.

Static invocation: This method differs from the static library invocation method, which is done by the compilation system to load the DLL and unload the DLL at the end of the application. When the application that calls a DLL ends, if there are other programs in the system that use the DLL, the Windows application record for the DLL is reduced by 1 until all programs that use the DLL are finished. Static invocation is a simple and practical method, but not as flexible as dynamic invocation.

Static Invocation Example: The static call method needs to complete two actions:

(1) Tell the compiler the path and file name of the. lib file that corresponds to the DLL, #pragma comment (lib, "DllTest.lib") is the function. When a programmer builds a DLL file, the connector automatically generates a corresponding. lib file that contains the symbolic name and ordinal number of the DLL's exported function (which does not contain the 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.

Static invocation does not require the use of the system API to load, unload, and get the address of the exported function in the DLL. This is because when the programmer builds the application by statically linking, the function symbols that are called in the application that match the exported symbols in the. lib file are entered into the generated EXE file, and the file names of the corresponding DLL files contained in the. lib file are also stored inside the exe file by the compiler. When a DLL file needs to be loaded while the application is running, Windows will discover and load the DLL based on that information, and then dynamically link the DLL functions with symbolic names. In this way, the EXE will be able to call the DLL's output function directly from the function name, just like any other function inside the calling program. Look at an example:

Copy the. lib and. dll files generated by the compiled DLL project into the path where the Dllcall project is located, Dllcall execute the following code:

#pragma comment (lib, "DllTest.lib")//.lib file is simply the relocation information about the 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);

return 0;

}

DllMain function

When Windows loads a DLL, it needs an entry function, just as a console or DOS program requires the main function, and the WIN32 program needs the WinMain function. In the previous example, the DLL did not provide the DllMain function, and the application project could successfully reference the DLL, because Windows could not find the DllMain when the system introduced a default version of DllMain function from other runtimes that did nothing. Does not mean that the DLL can discard the DllMain function. According to the writing specification, Windows must find and execute the DllMain function in the DLL as the basis for loading the DLL, which allows the DLL to remain in memory. This function is not an export function, but a DLL's intrinsic function. This means that the DllMain function cannot be referenced directly in the application project, and DllMain is automatically called.

See an example of a DllMain function:
BOOL apientry DllMain (HANDLE hmodule,

DWORD Ul_reason_for_call,

LPVOID lpreserved

)

{

Switch (Ul_reason_for_call)

{

Case Dll_process_attach:

printf ("\nprocess Attach of DLL");

Break

Case Dll_thread_attach:

printf ("\nthread Attach of DLL");

Break

Case Dll_thread_detach:

printf ("\nthread Detach of DLL");

Break

Case Dll_process_detach:

printf ("\nprocess Detach of DLL");

Break

}

return TRUE;

}

The DllMain function is called when the DLL is loaded and unloaded, and the DllMain function is called when the single thread starts and terminates, Ul_reason_for_call indicates the reason for the call. There are 4 kinds of reasons, namely Process_attach, Process_detach, Thread_attach, and Thread_detach, listed as switch statements.
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 the form of standard Pascal, which is the WINAPI mode;

Each DLL module in the process is identified by a globally unique 32-byte hinstance handle, which is valid only within a particular process, and the handle represents the starting address of the DLL module in the process virtual space. In Win32, the values of hinstance and hmodule are the same, and the two types can be substituted for use, which is the origin of the function parameter hmodule.

Execute the following code:
hDLL = LoadLibrary (".. Path \\dllTest.dll ");

if (hdll! = NULL)

{

Addfun = (lpaddfun) GetProcAddress (hDLL, Makeintresource (1));

Makeintresource directly using the ordinal in the export file

if (addfun! = NULL)

{

int result = Addfun (2, 3);

printf ("\ncall Add in dll:%d", result);

}

FreeLibrary (hDLL);

}

GetProcAddress in the code (hDLL, Makeintresource (1)), which accesses the add function directly through the sequence number specified by the Add function in the Def file, Makeintresource is a macro that gets 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))

#ifdef UNICODE

#define MAKEINTRESOURCE Makeintresourcew

#else

#define MAKEINTRESOURCE Makeintresourcea

Out of order: The output sequence verifies the timing of the DllMain call

Process Attach of DLL

Call Add in Dll:5

Process Detach of DLL


DLL Export variables:

DLL-defined global variables can be accessed by the calling process, and DLLs can also access the global data of the calling process to see examples of variables referenced in the DLL in the application engineering
/* File name: MyDll.h */

#ifndef Mydll_h

#define Mydll_h

extern int Dllglobalvar;

#endif


/* File name: MyDll.cpp */

#include "MyDll.h"

#include <windows.h>


int Dllglobalvar;


BOOL apientry DllMain (HANDLE hmodule, DWORD ul_reason_for_call, LPVOID lpreserved)

{

Switch (Ul_reason_for_call)

{

Case Dll_process_attach:

Dllglobalvar = 100; Assigning a global variable to 100 when the DLL is loaded

Break

Case Dll_thread_attach:

Case Dll_thread_detach:

Case Dll_process_detach:

Break

}

return TRUE;

}


; File name: Mydll.def

; Export a variable in a DLL

LIBRARY "Dlltest"

Exports

Dllglobalvar CONSTANT

; or Dllglobalvar DATA

Getglobalvar
As can be seen from MyDll.h and MyDll.cpp, the definition and use of global variables in DLLs is the same as for general programming. To export a global variable, we need to add it after the exports of the. def file:


Variable name CONSTANT//Obsolete method
A new method for the hint of variable name DATA//vc++

Refer to the global variables defined in the DLL in the main function:

#include <stdio.h>

#pragma comment (lib, "DllTest.lib")

extern int Dllglobalvar;

int main (int argc, char *argv[])

{

printf ("%d", * (int*) dllglobalvar);

* (int*) Dllglobalvar = 1;

printf ("%d", * (int*) dllglobalvar);


return 0;

}

In particular, it is important to note that using the extern int Dllglobalvar declaration is not the global variable itself in the DLL, but its address, and the application must use the global variables in the DLL by forcing pointer conversions. This, from * (int*) Dllglobalvar can be seen. Therefore, when referencing DLL global variables in this way, never do this assignment:
Dllglobalvar = 1; The result is that the contents of the Dllglobalvar pointer change, and the program will no longer reference the global variables in the DLL. A better way to refer to global variables in a DLL in an application project is to:
#include <stdio.h>

#pragma comment (lib, "DllTest.lib")

extern int _declspec (dllimport) Dllglobalvar; Import with _declspec (dllimport)

int main (int argc, char *argv[])

{

printf ("%d", Dllglobalvar);

Dllglobalvar = 1; This can be used directly, without forcing a pointer conversion

printf ("%d", Dllglobalvar);

return 0;

}

Importing through _declspec (dllimport) is the global variable itself in the DLL and is no longer its address, and it is recommended to use this method in all possible cases.

DLL Export class:

The classes defined in the DLL can be used in the application engineering.

In the following example, the point and circle two classes are defined in the DLL and referenced in the Application project//file name: Declaration of the Point.h,point class

#ifndef Point_h

#define Point_h

#ifdef Dll_file

Class _declspec (dllexport) point//Export Classes Point

#else

Class _declspec (dllimport) point//import type Point

#endif

{

Public

Float y;

float x;

Point ();

Point (float x_coordinate, float y_coordinate);

};

#endif


File name: Implementation of the Point.cpp,point class

#ifndef Dll_file

#define Dll_file

#endif

#include "Point.h"

Default constructor for class point

Point::p oint ()

{

x = 0.0;

y = 0.0;

}

Constructor for class point

Point::p oint (float x_coordinate, float y_coordinate)

{

x = x_coordinate;

y = y_coordinate;

}


File name: Declaration of the Circle.h,circle class

#ifndef Circle_h

#define Circle_h

#include "Point.h"

#ifdef Dll_file

Class _declspec (dllexport) circle//Export Classes Circle

#else

Class _declspec (dllimport) Circle//import Type Circle

#endif

{

Public

void Setcentre (const point¢repoint);

void Setradius (float R);

float Getgirth ();

float Getarea ();

Circle ();

Private

float radius;

Point Centre;

};

#endif


File name: Implementation of the Circle.cpp,circle class

#ifndef Dll_file

#define Dll_file

#endif

#include "circle.h"

#define PI 3.1415926

Constructors for the Circle class

Circle::circle ()

{

Centre = point (0, 0);

Radius = 0;

}

Get the area of the circle

Float Circle::getarea ()

{

return PI *radius * RADIUS;

}

Get the perimeter of the circle

Float Circle::getgirth ()

{

Return 2 *pi * RADIUS;

}

Set Center coordinates

void Circle::setcentre (const point¢repoint)

{

Centre = Centrepoint;

}

Set the radius of a circle

void Circle::setradius (float R)

{

Radius = R;

}

A reference to the class:
#include ". \circle.h "//Include class declaration header file

#pragma comment (lib, "DllTest.lib");
int main (int argc, char *argv[])

{

Circle C;

Point P (2.0, 2.0);

C.setcentre (P);

C.setradius (1.0);

printf ("Area:%f girth:%f", C.getarea (), C.getgirth ());


return 0;

}

From the above source code can be seen, because in the DLL's class implementation code defined macro Dll_file, so in the implementation of the DLL contains the class declaration is actually:

Class _declspec (dllexport) point//Export Classes Point

{

...

}


And
Class _declspec (dllexport) circle//Export Classes Circle

{

...

}

Dll_file is not defined in application engineering, so the class declarations introduced after Point.h and circle.h include:


Class _declspec (dllimport) point//import type Point

{

...

}

And
Class _declspec (dllimport) Circle//import Type Circle

{

...

}

Yes, it is through the DLL


Class _declspec (dllexport) class_name//Export Classes Circle

{

...

}

With the in-app
Class _declspec (dllimport) class_name//Import Classes

{

...

}

A pair to complete the export and import of the Class! We often decide to compile the class _declspec (dllexport) Class_name or Class _declspec (dllimport) class_name version by using a macro in the declaration header file of the classes, This eliminates the need for two header files. This procedure is used in:
#ifdef Dll_file

Class _declspec (dllexport) class_name//Export classes

#else

Class _declspec (dllimport) class_name//Import Classes

#endif

In fact, in the explanation of the MFC DLL, you will see a simpler approach than this one, and this is just to illustrate the problem of _declspec (dllexport) and _declspec (dllimport). Thus, almost everything in the DLL can be seen in application engineering, including functions, variables, and classes, which are the powerful capabilities that DLLs provide. As long as the DLLs release these interfaces, the application will use it as if it were using the program in this project!

C++dll Programming Detailed

Related Article

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.