1. Start your first DLL project
1.File->Close all->File->New[DLL>
Code : |
//Automatically generate code as follows library PRoject2; //This is nonsense. uses SysUtils, Classes; {$R *.RES} Begin end. |
2. Add a Func to enter:
Code : |
library Project2; uses SysUtils, Classes; Function MyMax ( X , Y : integer ) : integer ; stdcall ; Begin if X > Y then Results := X else Results := Y ; end ; //Remember: The name of Library does not matter, but the case of DLL-Func is related. // Writing MyMax in DLL-Func-Name is different from myMAX. If it is written wrong, immediately // The result is that you ask that the AP that uses this DLL cannot be opened at all. //The upper and lower case of the parameters is OK. It doesn't even have to have the same name. If the prototype is (X, Y: integer) // Write it as (A,B:integer) in time, that's OK. //Remember: add another stdcall. The book says that if you are writing DLLs using Delphi, and hope not only to // If Delphi-AP also hopes to use BCB/VC-AP, etc., then you'd better add a Stdcall; // Parameter pattern: Delphi has many variable patterns, which are of course not what DLL like // , the native language of Windows/DLL should be C. So if we want to pass in and out the parameters of the DLL, we // Use as much as possible according to the rules. If you write these two, the latter will be much trouble. If you are not familiar with C // If that's fine. We'll talk about it later. {$R *.RES} Begin end. |
3. Send these shareable Funcs out of the DLL and let the outside world (it's your Delphi-AP) use: Guangru
Therefore, your AP cannot use these, you need to add Exports.
Code : |
{$R *.RES} exports MyMax ; Begin end. |
4. Okay, you can press Ctrl-F9 to compile. Do not press F9 at this time. DLL is not EXE┌ that cannot be executed separately. If you press F9, there will be ErrorMsg. If the DLL has an error at this time, please correct it. Press Ctrl-F9 again. Warning may be there at this time, it doesn’t matter, just study it and take a look. Press Ctrl-F9 again, and then "Done, Compiled". There will be a *.dll in the same directory. Congratulations, the task is done.
2. Conduct a test: Open a new application:
1. Add a TButton
Code : |
ShowMessage ( IntToStr(MyMax(30,50)) ); |
2. Tell Exe to go there to catch a Func
Code : |
//Add to Form, interface, var Function MyMax ( X , Y : integer ) : integer ; stdcall ; external 'MyTestDLL.dll' ; // MyTestDLL.dll writes the DLL project name for you before // It doesn't matter if the DLL name is upper and lower. But remember to add extension .DLL. On Win95 or NT, // There is no need to add extension, but these two OSs may be less and less. You need to add extension. |
OK, it's simple.
Is the above example very simple? Friends who are familiar with Delphi can see that the above code is basically the same as writing a general Delphi program, except that there is an additional stdcall parameter after the TestDll function and the TestDll function is declared using the exports statement. Just compile the above code and you can get a dynamic link library called Delphi.dll. Now, let's see what needs attention. 1. All functions or procedures written in DLL must be added with stdcall call parameters. In Delphi 1 or Delphi 2 environment, the call parameter is far. After Delphi 3, this parameter was changed to stdcall, with the purpose of using standard Win32 parameter transfer technology instead of the optimized register parameters. Forgot to use the stdcall parameter is a common error. This error will not affect the compilation and generation of the DLL, but a serious error will occur when calling this DLL, resulting in deadlocks of the operating system. The reason is that the register parameter is the default parameter of Delphi.
2. The functions and procedures written should be declared as external functions using the exports statement.
As you can see, the TestDll function is declared as an external function. This allows the function to be seen externally. The specific method is to use the "Quick View" function to view the DLL file by just right-clicking the mouse. (If there is no Quick View option, you can install it from a Windows CD.) The TestDll function appears in the Export Table bar. Another good reason is that if we do not declare this way, the functions we write will not be called, which is something that no one wants to see.
3. When long string type parameters and variables are used, ShareMem should be referenced.
The string type in Delphi is very powerful. We know that the length of ordinary strings is up to 256 characters, but the string type in Delphi can reach 2G by default. (Yes, you read it right, it is indeed two megabytes.) At this time, if you insist on using a string type parameter, variable or even recording information, you must refer to the ShareMem unit, and it must be the first reference. It is the first referenced unit after the uses statement. As shown in the following example:
uses
ShareMem,
SysUtils,
Classes;
Another point is that the same thing should be done in your project file (*.dpr) instead of the unit file (*.pas). Delphi's own help file is not explained clearly, causing a lot of misunderstandings. If you don't do this, you're likely to pay a crash. The way to avoid using string type is to declare parameters, variables, etc. of string type as Pchar or ShortString (such as: s:string[10]) type. The same problem occurs when you use dynamic arrays, the solution is as described above.
Chapter 3: Static call to DLL top in Delphi
Calling a DLL is easier than writing a DLL. First, I will introduce the static calling method to you. I will introduce the dynamic calling method later, and compare the two methods. Similarly, let's first give an example of static calls.
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 in this line is the code we really wrote
function TestDll(i:integer):integer;stdcall;
external 'Delphi.dll';
procedure TForm1.Button1Click(Sender: TObject);
Begin
Edit1.Text:=IntToStr(TestDll(1));
end;
end.
In the example above, we placed an edit box (Edit) and a Button on the form, and wrote very little code to test the Delphi.dll we just wrote. You can see that the only job we do is to put the description part of the TestDll function in the implementation and specify the location of Delphi.dll with the external statement. (In this example, the call program and Delphi.dll are in the same directory.) It is exciting that the TestDll function we wrote ourselves was quickly recognized by Delphi. You can do an experiment like this: enter "TestDll(", and soon Delphi will use the fly-by prompt bar to prompt you what the parameters you should enter, just as simple as using other functions defined in Delphi. Notes include
Next:
1. Use stdcall to call parameters.
As mentioned above, when referring to functions and procedures in DLL, you must also use the stdcall parameter, for the same reason as mentioned above.
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 and the main program that called it are in the same directory. If the DLL file is in C:/, we can write the above reference statement as external 'C:/Delphi.dll'. Note that the file's suffix.dll must be written.
3. Global variables cannot be called from the DLL.
If we declare some kind of global variable in the DLL, such as: var s:byte . In this way, the global variable s can be used normally in the DLL, but s cannot be used by the calling program, and s cannot be passed as a global variable to the calling program. However, variables declared in the calling program can be passed as parameters to the DLL.
4. The called DLL must exist.
This is important. When using a static call method, it is required that the DLL file being called, the function or procedure to be called, etc. must exist. If the specified path and file name do not exist or the specified path and file name are incorrect, the system will prompt "An error occurred while starting the program" or "Not found *.dll file" when running the main program.
Chapter 4 Dynamically Calling DLL Top in Delphi
Dynamically calling DLLs is relatively complicated, but very flexible. To illustrate the problem thoroughly, this time we give an example of calling a DLL written in C++. First, compile the following DLL source program 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. There is only one function TestC that returns an integer type in the DLL. For the sake of convenience, we still refer to the above calling program, but replace the original statement in the 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 TestC function}
end
else
ShowMessage('TestC function not found');
Finally
FreeLibrary(Th); {Release DLL}
end
else
ShowMessage('Cpp.dll not found');
end;
As you have seen, this dynamic calling technique is very complicated, but as long as you modify the parameters, such as modifying the DLL name in LoadLibrary('Cpp.dll') to be 'Delphi.dll', you can dynamically change the called DLL.
1. Define the type of the function or procedure to be called.
In the above code we define a TIntFunc type, which corresponds to the function TestC we are going to call. The same definition work should be done in other calls. And also add stdcall call parameters.
2. Release the called DLL.
We called a DLL dynamically with LoadLibrary, but remember that you must manually release the DLL with FreeLibrary after use, otherwise the DLL will take up memory until you exit Windows or shut down.
Now let’s evaluate the advantages and disadvantages of the two methods of calling DLL. The static method is simple to implement, easy to master, and generally slightly faster, and is safer and more reliable; however, the static method cannot flexibly load and unload the required DLL at runtime, but loads the specified DLL when the main program starts to run until The DLL is released only at the end of the program, and only compiler-based systems such as Delphi can use this method. Dynamic methods better solve the shortcomings in static methods, and can easily access functions and procedures in DLLs, and even newly added functions or procedures in some old versions of DLLs; however, dynamic methods are difficult to fully master, because of different usage. A function or procedure needs to define many complex types and calling methods. For beginners, the author recommends that you use static methods and then use dynamic calling methods after you are proficient.
Chapter 5 Practical Tips for Using DLL Top
1. Writing skills.
1. In order to ensure the correctness of the DLL, you can first write it as part of an ordinary application, debug it correctly, and then separate it from the main program and compile it into DLL.
2. In order to ensure the universality of the DLL, you should prevent the names of visual controls from appearing in the DLL you wrote yourself, such as: Edit1 name in Edit1.Text; or customize non-Windows-defined types, such as some record.
3. To facilitate debugging, each function and process should be as short and concise as possible, and should be accompanied by specific and detailed annotations.
4. Try-finally should be used to deal with possible errors and exceptions. Note that you should refer to the SysUtils unit at this time.
5. Reference as few units as possible to reduce the size of the DLL, especially do not refer to visual units, such as Dialogs units. For example, in general, we can not reference Classes units, which can reduce the compiled DLL by about 16Kb.
2. Calling skills.
1. When using static methods, you can rename the called function or procedure. In the DLL example written in C++ mentioned above, if the extern "C" statement is removed, C++ will compile some strange function names, and the original TestC function will be named @TestC$s and other ridiculous weird names. This is because C++ uses C++ name mangling technology. This function name is illegal in Delphi, we can solve this problem like this:
Rewrite the reference function as
function TestC(i:integer):integer;stdcall;
external 'Cpp.dll';name '@TestC$s';
The function of name is to rename.
2. You can put the DLLs we wrote in the Windows directory or the Windows/system directory. Doing so can write only the name of the DLL without writing the path in the external statement or in the LoadLibrary statement. But it is a bit inappropriate to do this. There are a large number of important system DLLs in these two directories. If the DLLs you compile are duplicated with them, the consequences will be unimaginable. Moreover, your programming technology will not be enough to put the DLLs you wrote yourself into It's in the system directory!
3. Debugging skills.
1. We know that DLL cannot be run and debugged step by step when writing. There is a way to do this, that is, set up a host program in the Run|parameters menu. Add the name of the host program to the Host Application bar of the Local page to perform step-by-step debugging, breakpoint observation and running.
2. Add DLL version information. The opening remarks mentioned that version information is very important for DLLs. If version information is included, the size of the DLL will be increased by 2Kb. It's worth adding such a little space. Unfortunately, it is not possible to use the Version option in the Project|options menu directly. This is not mentioned in Delphi's help file. After research, I found that just add a line of code. As shown in the following example:
library Delphi;
uses
SysUtils,
Classes;
{$R *.RES}
//Note that the above line of code must be added in this position
function TestDll(i:integer):integer;stdcall;
Begin
Results:=i;
end;
exports
TestDll;
Begin
end.
3. In order to avoid duplicating the names with other DLLs, it is best to use a mix of characters, numbers and underscores when naming the DLLs you write. For example: jl_try16.dll.
4. If you have already compiled some DLLs in Delphi 1 or Delphi 2, the DLL you compiled is 16-bit. Just recompile the source code in the new Delphi 3 or Delphi 4 environment and you can get a 32-bit DLL.
[After note]: In addition to the most commonly used methods of using DLLs introduced above, DLLs can also be used as resource carriers. For example, changing icons in Windows is the resource in the DLL used. In addition, having mastered DLL design technology has many benefits for using more advanced OLE, COM and ActiveX programming.