Chapter 1 Why dynamic link library (DLL)
When you mention a DLL, you will not be unfamiliar. in Windows, there are a large number of files suffixed with DLL, which are an important guarantee to ensure the normal operation and maintenance of Windows. (For example, the Win95 System directory contains more than 500 DLL files .) In fact, DLL is a special executable file. It is special because it generally cannot be directly run and can be used only when the host Program, such as *. EXE or dynamic calls of other DLL programs, is required. In short, a DLL is usually a collection of compiled functions and processes.
There are several main reasons for using DLL technology:
1. Reduce the size of executable files.
A large part of DLL technology is generated to reduce the size of executable files. When the operating system entered the Windows era, its size has reached dozens or even hundreds of megabytes. If we still use the single-execution File System in the DOS era, the size of an executable file may reach dozens of megabytes, which is unacceptable to all. The solution is to use dynamic link technology to split a large executable file into many small executable programs.
2. Achieve resource sharing.
Resource Sharing involves many aspects, including Memory Sharing and code sharing. Early programmers often encountered such a problem and wrote the same code in different programming tasks. This method clearly wastes a lot of time. To solve this problem, we have compiled a variety of libraries. However, these libraries are generally unavailable because of different programming languages and environments, and these libraries are also required for running the program, which is inconvenient. The emergence of DLL is like the establishment of a standard, so that these libraries have a unified specification. In this way, programmers of different programming languages can conveniently use the DLL compiled in other programming languages. In addition, DLL also has a prominent feature: It is loaded only once in the memory, which can save limited memory and provide services for multiple processes at the same time.
3. Easy maintenance and upgrade.
Careful friends may find that some DLL files have version instructions. (View the properties of the DLL file, but not every DLL file is available) to facilitate maintenance and upgrade. For example, there was a BUG in Win95 in the early days, that is, in a leap year, the day of June February 29 could not be correctly displayed. Later, Microsoft released a patch to correct the BUG. We did not reinstall Win95, but replaced the old version of DLL with the new version. (The specific DLL file cannot be remembered at the moment .) Another common example is Driver Upgrade. For example, the famous DirectX has been upgraded several times and has now reached version 6.0. Even better, when we try to install a later version of DLL, the system will prompt us to avoid human operation errors. For example, when we upgrade a hardware driver, we often encounter Windows prompts that the driver we are currently installing is older than the original driver.
4. relatively secure.
The security mentioned here also includes many aspects. For example, DLL files are more vulnerable to virus attacks than normal EXE files. In addition, because it is a dynamic link, it brings some difficulties in disassembly for some "Masters" who are engaged in destructive work.
Chapter 2 compiling DLL top in Delphi
Note: Here I assume that the reader is using Delphi 3 or Delphi 4 with so many opening remarks, so it is time to get down to the truth. Writing a DLL is not very difficult, but it is enough to pay attention to some issues. For ease of instruction, let's give an example.
Library Delphi;
Uses
SysUtils,
Classes;
Function TestDll (I: integer): integer; stdcall;
Begin
Result: = I;
End;
Exports
TestDll;
Begin
End.
Is the above example very simple? If you are familiar with Delphi, you can see that the above Code is basically the same as the compilation of the General Delphi Program, but after the TestDll function, you have added an stdcall parameter and declared the TestDll function with the exports statement. Compile the above Code to obtain a dynamic link library named Delphi. dll. Now, let's take a look at what needs attention. 1. stdcall call parameters must be added to functions or processes written in DLL. In Delphi 1 or Delphi 2, the call parameter is far. After Delphi 3, this parameter is changed to stdcall to replace the optimized register parameter with the standard Win32 parameter transfer technology. It is a common error to forget to use the stdcall parameter. This error does not affect DLL compilation and generation. However, when this DLL is called, a very serious error occurs, resulting in a deadlock in the operating system. The reason is that the register parameter is the default parameter of Delphi.
2. The written functions and procedures should be declared as external functions using the exports statement.
As you can see, the TestDll function is declared as an external function. In this way, the function can be seen externally. The specific method is to right-click and use the Quick View function to View the DLL file. (If you do not have the "Quick View" option, you can install it on Windows CD .) The TestDll function appears in the Export Table column. Another good reason is that, without such declaration, the functions we write will not be called.
3. ShareMem must be referenced when long string parameters and variables are used.
The string type in Delphi is very powerful. We know that the length of a common string is up to 256 characters, but in Delphi, the string type can be 2 GB by default. (Yes, You are not mistaken. It is indeed two megabytes .) At this time, if you insist on using string-type parameters, variables, or even record information, you must reference the ShareMem unit, which must be the first reference. It is the first referenced unit after the uses statement. For example:
Uses
ShareMem,
SysUtils,
Classes;
Also, in your project file (*. dpr) instead of the unit file (*. also do the same job, this is not clearly stated in the Help file that comes with Delphi, causing a lot of misunderstanding. If you do not do this, you are likely to pay for the crash. To avoid using the string type, declare parameters and variables of the string type as Pchar or struct string (for example, s: string [10. The same problem occurs when you use a dynamic array.
Chapter 3 static call of DLL top in Delphi
Calling a DLL is easier than writing a DLL. First, we will introduce static call methods. Later we will introduce dynamic call methods and compare them. Let's take a static call example first.
Unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
Type
TForm1 = class (TForm)
Edit1: TEdit;
Button1: TButton;
Procedure Button1Click (Sender: TObject );
Private
{Private declarations}
Public
{Public declarations}
End;
Var
Form1: TForm1;
Implementation
{$ R *. DFM}
// The following code is the code we actually write.
Function TestDll (I: integer): integer; stdcall;
External 'delphi. dll ';
Procedure TForm1.Button1Click (Sender: TObject );
Begin
Edit1.Text: = IntToStr (TestDll (1 ));
End;
End.
In the above example, we placed an Edit box and a Button on the form, and wrote a little code to test the Delphi. dll we just compiled. We can see that the only task we do is to place the description of the TestDll function in implementation, and specify the location of Delphi. dll using the external statement. (In this example, the calling program and Delphi. dll are in the same directory .) The excitement is that the TestDll function we wrote was quickly recognized by Delphi. You can do this experiment: Enter "TestDll (", and soon Delphi will use the fly-by prompt to prompt you what parameters should be entered, it is as simple as using other functions defined in Delphi. Note:
Below:
1. Use stdcall to call parameters.
As mentioned above, the stdcall parameter must be used to reference functions and procedures in DLL, for the same reason as previously mentioned.
2. Use the external statement to specify the path and name of the called DLL file.
As you can see, we specify the name of the DLL file to be called in the external statement. There is no write path because the DLL file is in the same directory as the main program that calls it. If the DLL file is in C:/, we can write the above reference statement as external 'C:/Delphi. dll '. Note that the file suffix. dll must be written.
3. global variables cannot be called from DLL.
If we declare a global variable in the DLL, such as var s: byte. In this way, the global variable s in DLL can be used normally, but s cannot be used by the calling program, and s cannot be passed to the calling program as a global variable. However, variables declared in the calling program can be passed to the DLL as parameters.
4. The called DLL must exist.
This is very important. When a static call method is used, the DLL file called and the function or process to be called must exist. If it does not exist or the specified path and file name are incorrect, the system will prompt "errors during program startup" or "cannot find *. dll file" and other running errors when running the main program.
Chapter 4 Dynamic calling of DLL top in Delphi
Dynamic calling of DLL is much more complicated, but flexible. To fully illustrate this problem, we will give an example of calling a DLL compiled by C ++. First, compile the following DLL source code in C ++.
# Include
Extern "C" _ declspec (dllexport)
Int WINAPI TestC (int I)
{
Return I;
}
After compilation, a DLL file is generated. Here we call this file Cpp. dll, which contains only one function TestC that returns an integer. For convenience, we still reference the above calling program, but replaced the statements in the original Button1Click process with the following code.
Procedure TForm1.Button1Click (Sender: TObject );
Type
TIntFunc = function (I: integer): integer; stdcall;
Var
Th: Thandle;
Tf: TIntFunc;
Tp: TFarProc;
Begin
Th: = LoadLibrary ('cpp. dll '); {load DLL}
If Th> 0 then
Try
Tp: = GetProcAddress (Th, PChar ('testc '));
If Tp <> nil
Then begin
Tf: = TIntFunc (Tp );
Edit1.Text: = IntToStr (Tf (1); {call the TestC function}
End
Else
ShowMessage ('testc function not found ');
Finally
FreeLibrary (Th); {release DLL}
End
Else
ShowMessage ('cpp. dll not found ');
End;
As you can see, this dynamic calling technology is complicated, but you only need to modify the parameters, such as modifying LoadLibrary ('cpp. dll ') is named 'delphi. dll 'to dynamically change the called DLL.
1. define the type of the function or process to be called.
In the above Code, we define a TIntFunc type, which corresponds to the TestC function we will call. The same definition is required for other calls. You must also add the stdcall call parameter.
2. Release the called DLL.
We use LoadLibrary to call a DLL dynamically, but remember to manually release it with FreeLibrary after use, otherwise, the DLL will occupy the memory until you exit Windows or shut down.
Now let's evaluate the advantages and disadvantages of the two methods for calling DLL. Static methods are easy to implement, easy to master, and generally a little faster, and more secure and reliable. However, static methods cannot flexibly unload the required DLL during running, instead, the specified DLL is loaded at the beginning of the main program until the end of the program. In addition, this method can only be used by the compiler and linker-based systems (such as Delphi. The dynamic method effectively solves the shortcomings in the static method, so that you can easily access the functions and processes in the DLL, and even some newly added functions or processes in the old version DLL; however, it is difficult to fully grasp the dynamic methods. Because different functions or processes need to define many complex types and call methods. For beginners, I suggest you use static methods and use dynamic calling methods after you become proficient.
Chapter 5 practical tips for using DLL
I. Writing Skills.
1. To ensure the correctness of the DLL, You can first compile it into a part of a common application, debug it correctly, then separate it from the main program, and compile it into a DLL.
2. To ensure the versatility of the DLL, you should prevent the name of the visualization control from appearing in the DLL you have compiled, such as the Edit1 name in Edit1.Text or custom non-Windows-defined types, such as a record.
3. In order to facilitate debugging, each function and process should be as short and concise as possible, with detailed annotations.
4. try-finally should be used to handle possible errors and exceptions. Note that SysUtils unit should be referenced at this time.
5. Use as few reference units as possible to reduce the DLL size. In particular, do not reference visualization units, such as Dialogs units. For example, in general, we can not reference the Classes unit, which can reduce the size of the compiled DLL by about 16 kb.
Ii. Call skills.
1. When using static methods, you can rename the called function or process. In the preceding DLL example written in C ++, if the extern "C" statement is removed, C ++ will compile some strange function names, the original TestC function will be named as @ TestC $ s and so on. This is because C ++ uses C ++ name mangling technology. This function name is invalid in Delphi. We can solve this problem as follows:
Rewrite the reference function
Function TestC (I: integer): integer; stdcall;
External 'cpp. dll '; name' @ TestC $ s ';
The role of name is rename.
2. You can put the compiled DLL in the Windows directory or the Windows/system directory. In this way, you can write only the DLL name in the external or LoadLibrary statement without writing the path. But there is something wrong with this. There are a lot of important system DLL under these two directories. If the DLL you have compiled is the same as them, the consequences are simply unimaginable, besides, your programming technology is not as good as putting your own DLL into the system directory!
Iii. debugging skills.
1. We know that the DLL cannot be run or debugged in a single step during compiling. One way is to set a Host Program in the Run | parameters menu. You can add the Host program name to the Host Application column on the Local page for single-step debugging, breakpoint observation, and running.
2. Add the DLL version information. The version information mentioned in the opening remarks is very important for the DLL. if the version information is included, the DLL size will increase by 2 kb. It is worth adding such a space. Unfortunately, it is not possible to directly use the Version option in the Project | options menu, which is not mentioned in the Help File of Delphi. The author found that you only need to add a line of code. For example:
Library Delphi;
Uses
SysUtils,
Classes;
{$ R *. RES}
// Note that the above line of code must be added to this position
Function TestDll (I: integer): integer; stdcall;
Begin
Result: = I;
End;
Exports
TestDll;
Begin
End.
3. To avoid renaming a DLL with another DLL, it is best to use a mix of characters, numbers, and underscores when naming the DLL. For example, jl_try16.dll.
4. If you have already compiled some DLL files in Delphi 1 or Delphi 2, the original DLL files are 16-bit. You only need to re-compile the source code in the New Delphi 3 or Delphi 4 environment to get a 32-bit DLL.
[Postscript]: in addition to the most common DLL usage method described above, DLL can also be used as a resource carrier. For example, changing the icon in Windows is the resource in the DLL used. In addition, mastering the DLL design technology is of great benefit to the use of more advanced OLE, COM, and ActiveX programming.
How To Call DLL in Delphi
The following instructions are available:
1. DLL to be dynamically linked must be placed in the same directory as the execution file or Windows System directory 2. check the prototype of the Function Derived from DLL export. In the current situation, only the function prototype of C is obtained. Pay attention to the type corresponding to C and object Pascal. If necessary, define the required category in interface
3. Declare the function to be used in implementation. The syntax is roughly as follows:
Procedure ProcName (Argu...); far; external 'dll file name ';
Index n;
Function FuncName (Argr...): DataType; far;
External 'dll filename '; index n;
If index n is not written at the time of declaration, it is the so-called import by name method in reference materials. At this time, we need to find this function from the DLL name table. Therefore, the link execution speed is a little slower than import by ordinal. In addition, there is a new name, which is not used by me. You can check the reference materials, this function can be called by another program after the import.
4. then, the call and use are no different from the general Delphi 5. the above is directly written to the Program unit of the Call DLL function. In addition, you can also centralize the call declaration of the DLL to an Import unit and the WinTypes included in Delphi, winProcs is an example,
You can refer to and observe the Data Types of C and Pascal. in addition to the static import method described above, there is also a dynamic import method, which first declares a program type (procedural-type). When the program is executed, Load it with the LoadLibrary () API, then use the GetProcAddress () API to get the address of the interface to link the call, in the ObjectPascal Language Guide P.132-133 has an example, you can refer to see
For example, the following is a piece recorded from my previous programs:
(* For CWindows 3.1 *)
Unit Ime31;
Interface
Uses
SysUtils, WinTypes, WinProcs, Dialogs;
Type
(* Necessary data type announcement *)
TDateNTime = record
WYear, wMonth, wDay: word;
WHour, wMin, wSec: word;
End;
TImePro = record
HWndIme: HWnd; {IME handle}
DtInstDate: tDateNTime; {Date and time of installation}
WVersion: word; {the version of IME}
SzDescription: array [0 .. 49] of byte; {Description of IME module}
SzName: array [0 .. 79] of byte; {Module name of the IME}
SzOptions: array [0 .. 29] of byte; {options of IME at startup}
FEnable: boolean; {IME status; True = activated, False = deactivated}
End;
PTImePro = ^ TImePro;
Function SetIme (const sImeFileName: string): boolean; far;
Implementation
(* Begin calls the declaration of winnls. dll export function *)
Function ImpSetIme (hWndIme: HWND; lpImePro: pTImePro): boolean; far; external 'winnls. dll ';
(* Declaration of the end call to the winnls. dll export function *)
(*--------------------------------------------------*)
(* SetIme (const sImeFileName: string): boolean;
(* =
(* Switch to a specific input method
(*
(* Input reference:
(* SImeFileName: name of the IME file for the input method, for example, phon. ime;
(* Null String: English numeric Input Method
(*
(* Return value:
(* True: Switch successful
(* False: Failed
(*--------------------------------------------------*)
Function SetIme (const sImeFileName: string): boolean;
Var
PImePro: pTImePro;
Begin
Result: = False;
If MaxAvail <SizeOf (TImePro) then
Begin
MessageDlg ('memory insufficiency ', mtWarning, [mbOk], 0 );
Exit;
End
Else
Begin
New (pImePro );
Try
If sImeFileName = ''then (* empty string, restored to the English Data Input Method *)
PImePro ^. szName [0]: = 0
Else
StrPCopy (@ pImePro ^. szName, sImeFileName );
Result: = ImpSetIme (0, pImePro); (* Call ImpSetIme *)
Finally
Dispose (pImePro );
End; {of try}
End;
End; {of SetIme}
End.
;