Detailed description of VC ++ mfc dll Dynamic Link Library
Although all functions implemented by dll can be replaced by COM, dll has many advantages and is easier to create. This article will discuss how to use vc mfc to create different types of DLL and how to use them.
1. Different types of DLL
You can use VC ++ to generate two types of DLL: MFC extension DLL and conventional DLL. Conventional dll can be divided into dynamic and static connections. Visual c ++ can also generate Win32 DLL, but it is not the main object discussed here.
1. MFC extension DLL
Each dll has a certain type of Interface: variables, pointers, functions, class accessed by the client program. Their role is to allow the client program to use the DLL. The MFC extension DLL can have a C ++ interface. That is, it can export the C ++ class to the client. The exported function can use the C ++/mfc data type as a parameter or return value. When exporting a class, the client can create a class object or derive this class. You can also use DLL and MFC In the DLL.
The MFC class library used by Visual C ++ is also saved in a DLL. The MFC extension DLL dynamically connects to the DLL of the MFC code base, and the client program must also dynamically connect to the DLL of the MFC code base. (The two DLL mentioned here, one is our own DLL and the other is the DLL for installing the MFC class library.) Currently, there are multiple versions of the DLL in the MFC code library, both the client program and the extended dll must use the same version of the MFC code DLL. So in order for the MFC extension DLL to work well, both the extension DLL and the client program must be dynamically connected to the MFC code library DLL. The dll must be run on the computer where the client is running.
2. Conventional DLL
One problem with using the MFC extension DLL is that the DLL can only work with the MFC client program. If you need a more widely used DLL, it is best to use the conventional DLL because it is not limited by the MFC. Conventional DLL also has a disadvantage: it cannot send pointer or reference to the MFC derived class and object with the client program. In a word, the interfaces of conventional DLL and client programs cannot use MFC, but they can still be used inside the DLL and client programs.
When the DLL of the MFC code library is used inside a conventional DLL, it can be a dynamic or static connection. If it is a dynamic connection, that is, the MFC Code required by the conventional DLL is not built into the DLL. This is a bit similar to the extended DLL, And the DLL of the MFC code library must be required on the computer where the DLL runs. If it is a static connection, the conventional DLL already contains the required MFC code, so that the DLL size will be relatively large, but it can run normally on a computer without the MFC code library DLL.
2. Create a DLL
By using the Wizard feature provided by Visual C ++, you can easily create a DLL that does not complete any substantive tasks. Here we will not talk much about it. The main task is how to add functions to the DLL, and use the DLL in the client program.
1. Export class
After the framework is created using the wizard, you can add the. cpp. h file of the class to be exported to the DLL, or use the Wizard to create the C ++ herder file/C ++ source file. To export this class, add "_ declspec (dllexport)" to the class declaration, for example:
Class _ declspec (dllexport) cmyclass
{
... // Declaration
}
If you create an MFC extension DLL, you can use the macro: afx_ext_class:
Class afx_ext_class cmyclass
{
... // Declaration
}
In this way, the export class method is the simplest. You can also use the. Def file for export.
2. Export variables, constants, and objects
In many cases, you do not need to export a class, so that the DLL can export a variable, constant, and object. to export them, you only need to make a simple declaration: _ declspec (dllexport) int Myint;
_ Declspec (dllexport) extern const colorref mycolor = RGB (0, 0 );
_ Declspec (dllexport) crect rect (10, 10, 20, 20 );
To export a constant, the keyword extern must be used; otherwise, a connection error occurs.
NOTE: If your program recognizes this class and has its own header file, only one class object can be exported. If a class is created in the DLL, the class cannot be recognized without using the header file.
When exporting an object or variable, each client program that loads the DLL has its own copy. That is, if two programs use the same DLL, the modifications made by one application will not affect the other.
When exporting, we can only export global variables or objects in the DLL, but not local variables and objects. Because they do not exist after the scope, the DLL will not work normally. For example:
Myfunction ()
{
_ Declspec (dllexport) int Myint;
_ Declspec (dllexport) cmyclass object;
}
3. Export Functions
The export function is similar to the export variable/object. You only need to add _ declspec (dllexport) to the start position of the function prototype:
_ Declspec (dllexport) int myfunction (INT );
If it is a conventional DLL, it will be used with the program written in C. The declaration method is as follows:
Extern "C" _ declspec (dllexport) int myfunction (INT );
Implementation:
Extern "C" _ declspec (dllexport) int myfunction (int x)
{
... // Operation
}
If you create a conventional DLL that dynamically connects to the MFC code library DLL, you must insert afx_manage_state as the first line of the export function. Therefore, the definition is as follows:
Extern "C" _ declspec (dllexport) int myfunction (int x)
{
Afx_manage_state (afxgetstaticmodulestate ());
... // Operation
}
Sometimes, for the sake of security, it is added to every common DLL, and there will be no problem, but this macro is invalid during static connection. This is the method for exporting functions. Remember that only the MFC extension DLL can use the data type of MFC for parameters and return values.
4. Export pointer
Export pointers as follows:
_ Declspec (dllexport) int * pint;
_ Declspec (dllexport) cmyclass object = new cmyclass;
If the pointer is initialized at the same time, you need to find a suitable local class to release the pointer. There is a function dllmain () in the extended DLL (). (Note that the two l in the function name should be lowercase letters), you can process the pointer in this function:
# Include "myclass. H"
_ Declspec (dllexport) cmyclass * pobject = new cmyclass;
Dllmain (hinstance, DWORD dwreason, lpvoid lpreserved)
{
If (dwreason = dll_process_attach)
{
.....//
}
Else if (dwreason = dll_process_detach)
{
Delete pobject;
}
}
A common dll has a class object processing DLL derived from cwinapp. You can use the Class Wizard to add the initinstance/exitinstance function.
Int cmydllapp: exitinstance ()
{
Delete pobject;
Return cwinapp: exitinstance ();
}
3. Use DLL in the client program
When compiling a DLL, two. DLL files and. Lib files will be created. First, copy the two files to the client program project folder. Pay attention to the DLL and client program version issues. Try to use the same version, both of which use release or both are DEBUG Versions.
Then you need to set the Lib file in the client program and open the Project Settings ---> link ---> Object/library modules and enter the Lib file name and path. For example, debug/sampledll. Lib. In addition to the DLL and Lib files, the client program needs to export header files for classes, functions, objects, and variables. The keyword for importing and adding is _ declspec (dllimport), for example:
_ Declspec (dllimport) int myfunction (INT );
_ Declspec (dllimport) int Myint;
_ Declspec (dllimport) cmyclass object;
Extern "C" _ declspec (dllimport) int myfunction (INT );
In some cases, to import the class, add the header file of the corresponding class to the client program. The difference is that the flag of the class declaration should be modified:
Class _ declspec (dllimport) cmyclass. If you create an extended DLL, both of them are:
Class afx_ext_class cmyclass.
A serious problem with using DLL is the compatibility between compilers. Different compilers have different implementation methods for C ++ functions at the binary level. Therefore, for C ++-Based DLL, It is very troublesome if the compiler is different. If you create an MFC extension DLL, there is no problem because it can only be dynamically connected to the client application of MFC. This is not the focus of this article.
I. recompilation
Let's first look at a problem that may be encountered in practice:
For example, if a DLL is created and the cmyclass class is exported, the client can use the DLL normally. Assume that the cmyclass object size is 30 bytes. If we need to modify the cmyclass class in the DLL so that it has the same functions and member variables, but add a private member variable int type to it, now the cmyclass object is 34 bytes in size. When the customer directly replaces the new DLL with the original 30-byte DLL, the customer's application expects a 30-Byte object, but now it has become a 34-Byte object, bad, the customer program error.
Similar problems: If the cmyclass class is not exported and cmyclass is used in the exported function, changing the object size will still cause problems. At this time, the only way to modify this problem is to replace the header file of cmyclass in the customer program, re-compile the entire application, and let the customer program use 34 bytes of objects.
This is a serious problem. Sometimes, if the source code of the client program is not available, we cannot use this new DLL.
Ii. Solution
To avoid re-compiling the client program, we will introduce two methods: (1) using the interface class. (2) Use static functions for creating and destroying classes.
1. Use the Interface Class
The second class is created for the interface class, which serves as the interface for exporting the class. Therefore, when the export class is changed, you do not need to re-compile the client program because the interface class has not changed.
Assume that the exported cmyclass class has two functions: functiona functionb. Now, create an interface class cmyinterface. The following is the header file code of the cmyinterface class in the DLL:
# Include "myclass. H"
Class _ declspec (dllexport) cmyinterface
{
Cmyclass * pmyclass;
Cmyinterface ();
~ Cmyinterface ();
Public:
Int functiona (INT );
Int functionb (INT );
};
The header files in the client program are slightly different. The include statement is not required because the client program does not copy the files. Instead, a forward declaration of cmyclass can be compiled even if no header file is available:
Class _ declspec (dllexport) cmyinterface
{
Class cmyclass; // Forward Declaration
Cmyclass * pmyclass;
Cmyinterface ();
~ Cmyinterface ();
Public:
Int functiona (INT );
Int functionb (INT );
};
The implementation of cmyinterface in DLL is as follows:
Cmyinterface: cmyinterface ()
{
Pmyclass = new cmyclass ();
}
Cmyinterface ::~ Cmyinterface ()
{
Delete pmyclass;
}
Int cmyinterface: functiona ()
{
Return pmyclass-> functiona ();
}
Int cmyinterface: functionb ()
{
Return pmyclass-> functionb ();
}
.....
For each member function of the export class cmyclass, The cmyinterface class provides its own function. The customer program has no contact with cmyclass, so that any cmyclass change will not be a problem, because the size of the cmyinterface class has not changed. Even if you add a function to the cmyinterface class in order to access the new variables in cmyclass, there is no problem.
However, this method also has obvious problems. Each function and member variable of the export class must be implemented accordingly, and sometimes this interface class will be huge. It also increases the time required for client program calling. Increases program overhead.
2. Use static functions
You can also use static functions to create and destroy class objects. When creating an export class, add two static public functions createme ()/destroyme (). The header file is as follows:
Class _ declspec (dllexport) cmyclass
{
Cmyclass ();
~ Cmyclass ();
Public:
Static cmyclass * createme ();
Static void destroyme (cmyclass * PTR );
};
The implementation function is:
Cmyclass * cmyclass: cmyclass ()
{
Return new cmyclass;
}
Void cmyclass: destroyme (cmyclass * PTR)
{
Delete PTR;
}
Then export the cmyclass class like other classes. The methods for using this class in the client program are slightly different. If you want to create a cmyclass object, it should be:
Cmyclass X;
Cmyclass * PTR = cmyclass: createme ();
Delete after use:
Cmyclass: destroyme (PTR );