Examples of creating complex delphi dlls. Using Dll in Delphi


Dear colleagues!

In this article I will try to answer the questions: What is DLL? What is it for? And how to create and use DLL with help Delphi.

What is DLL?

Dynamic Link Library or for short DLL is a library that contains a set of data or functions for use in other programs.

Areas of use:

  • Storage of resources: icons, sounds, cursors, etc. We save on the size of executable files by combining resources into a single library.
  • Placement of individual program modules and interface forms. We get the opportunity to partially update the application, and with a dynamic connection, it is possible to update modules without restarting the main program.
  • Use as plugins (PlugIn). We provide the opportunity to expand the functionality of the application without rewriting the main program code.
  • The library can be used in different programming languages, regardless of the language in which it was written.

Creating your own DLL.

To create a library, go to the menu File -> Other and choose Delphi Projects -> Dynamic-link Library.
The code text with a template for creating a library will open:

Library Project1; uses System.SysUtils, System.Classes; ($R *.res) begin end.

Resource placement

Let's add an icon to the library, which we will use later in the main program.
How to add resources to a project is described in detail in the article.

Let’s add an “About the program” form.
Click File -> New -> VCL Form. Let's add text and an "OK" button:

Let's add a function that will display the standard MessageBox with a question, buttons “Yes”, “No” and with a result in the form True or False.

Function YesNoDlg(const Question: PChar): boolean; stdcall; begin Result:= (MessageBox(0, Question, "Confirmation", MB_YESNO + MB_ICONQUESTION) = ID_YES); end;

Pay attention to the keyword stdcall. It determines exactly how parameters and results will be passed when calling functions. You can read more on the Calling Agreement wiki page.

We will also add a procedure that will be used as a plugin for the main program. Which will add an “About the program” button to the main program menu to open the window we created.
Procedure code:

Procedure PlugIn(Form: TForm); stdcall; var i: integer; mi: TMenuItem; begin for i:= 0 to Form.ComponentCount - 1 do begin if (Form.Components[i].ClassName = "TMenuItem") and (Form.Components[i].Name = "miHelp") then begin mi:= TMenuItem .Create(Form.Components[i]); mi.Caption:= "About the program"; mi.OnClick:= fmAbout.onAboutButtonClick; TMenuItem(Form.Components[i]).Add(mi); Exit; end; end; end;

The form of the program is passed to the procedure as a parameter. We check whether there is a menu item named “ miHelp"and if the menu is found, then add our button to it.

Now we will indicate which functions and procedures can be used from our library.
Let's add the line:

Exports PlugIn, YesNoDlg;

Let's compile the function Project -> Build or using a hotkey Shift+F9.
If there are no errors in the code, then a file with the extension should appear in the project folder DLL.

Now let's move on to creating an application that will use our library.

Let's create a form in the application Main in which we will add a component with the following buttons: Program -> Exit and Help. For the last one, let's set a name - miHelp:

Let's move on to the form code.

Functions from the library DLL can be connected in two ways:
Static— the library is connected when the program starts. If the library or function name is not found, the program will generate an error and will not run.
Dynamic— the library is connected either immediately before a function call or upon a specific event.

Let's consider the static connection method:

Type TfmMain = class(TForm) MainMenu: TMainMenu; miProgram: TMenuItem; miExit: TMenuItem; miHelp: TMenuItem; procedure FormCreate(Sender: TObject); procedure miExitClick(Sender: TObject); private public end; procedure PlugIn(Form: TForm); stdcall; external "SampleDLL.dll"; var...

Keyword external indicates that this function is connected from an external library.

For the event onCreate form, add a procedure call PlugIn:

Procedure TfmMain.FormCreate(Sender: TObject); begin PlugIn(Self); end;

As a parameter Form we pass the current form to the procedure (keyword Self).

When starting the program, we should have the “About the program” item in the “Help” section of the main menu.

Let's move on to the dynamic connection method.

We will need three functions WinApi:

LoadLibrary
Loads the library into the computer's memory. As a result, returns a pointer to the library in memory. In case of error, it will return 0.

LoadLibrary(lpLibFileName: LPCWSTR): HMODULE;

lpLibFileName— Library file name.

GetProcAddress
Find a function in a library by name. The result will be a function pointer. If the function is not found, it will return nil.

GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC;

hModule
lpProcName— Function name.

FreeLibrary
Unloads the library from the computer's memory. The result will be True in case of success and False in case of error.

FreeLibrary(hLibModule: HMODULE): BOOL;

hLibModule— Pointer to the loaded library.

Now, using the dynamic method, we will get resources, our icon and add a function call to the “Exit” button YesNoDlg to confirm the program is closed.
Add the code to the same onCreate event:

Procedure TfmMain.FormCreate(Sender: TObject); var DLLHandle: THandle; begin PlugIn(Self); DLLHandle:= LoadLibrary("SampleDLL.dll"); if DLLHandle = 0 then raise Exception.Create("Could not include library 'SampleDLL'!"); try Self.Icon.LoadFromResourceName(DLLHandle, "my_icon"); finally FreeLibrary(DLLHandle); end; end;

And for the event onClick menu item "Exit":

Procedure TfmMain.miExitClick(Sender: TObject); var DLLHandle: THandle; Dlg: function(const Question: PChar): boolean; stdcall; begin DLLHandle:= LoadLibrary("SampleDLL.dll"); if DLLHandle = 0 then raise Exception.Create("Could not include library 'SampleDLL'!"); try @Dlg:= GetProcAddress(DLLHandle, "YesNoDlg"); if not Assigned(@Dlg) then raise Exception.Create("The function named "YesNoDlg" was not found in the library "SampleDLL"!"); if Dlg("Exit the program?") then Close; finally FreeLibrary(DLLHandle); end; end;

If you wrote everything correctly, then after starting the program the form icon should change, the “About the program” button should be added, when clicked on it the form will show About and when you press the exit button, the program will ask for confirmation: “Exit the program?”

I hope you find this small example of using the features useful. DLL libraries.
The project sources can be downloaded.

I bring to your attention the next issue of the newsletter, in which I continue to discuss
issues of developing and using DLLs in Borland Delphi. For new subscribers I inform you,
that they can look at the first part of the article in the mailing archive, issue number 13.
I apologize to those who wrote to me but did not receive a response. I'll try to fix this in the near future.
So let's continue.

Before you start using any procedure or function located in a dynamic library,
you need to load the DLL into RAM. The library can be loaded
one of two ways: static loading and dynamic loading.
Both methods have both advantages and disadvantages.
Static loading means that the dynamic library is loaded automatically
when the application using it is launched. To use this download method,
you need to use the external keyword when describing what is being exported from
dynamic library function or procedure. The DLL is automatically loaded when the program starts,
and you can use any routines exported from it in the same way as
as if they were described inside application modules.
This is the easiest way to use code placed in a DLL.
The disadvantage of this method is that if the library file on which
there is a link in the application, if it is missing, the program will refuse to load.
The point of the dynamic method is that you do not load the library when the application starts,
and at the moment when you really need it. Judge for yourself, because if the function described
in a dynamic library, used only in 10% of program launches, then absolutely not
It makes no sense to use a static loading method. Unloading the library from memory in this case
is also carried out under your control. Another advantage of this method
loading DLLs means reducing (for obvious reasons) the startup time of your application.
What are the disadvantages of this method? The main one, it seems to me, is that the use
This method is more troublesome than the static loading discussed above.
First you need to use the Windows API LoadLibrary function.
To obtain a pointer to the exported procedure or function, you must
use the GetProcAddress function. After finishing using the DLL
must be unloaded using FreeLibrary.
Calling procedures and functions loaded from DLLs.
The way procedures and functions are called depends on how you loaded the dynamic library,
in which these subroutines are located.
Calling functions and procedures from statically loaded DLLs is quite simple. Originally in the app
must contain a description of the exported function (procedure). After that you can use them
just as if they were described in one of your application modules.
To import a function or procedure contained in a DLL, you must use
external modifier in their declaration. For example, for the HelloWorld procedure we considered above
The calling application must have the following line:
procedure SayHello(AForm: TForm); external myfirstdll.dll";
The external keyword tells the compiler that the procedure can be found in
dynamic library (in our case - myfirstdll.dll).
The call to this procedure then looks like this:
...
HelloWorld(self);
...
When importing functions and procedures, be especially careful when writing their names and interfaces!
The fact is that during application compilation there is no check for the correctness of object names,
exported from the DLL will not be implemented, and if you incorrectly described any function,
then the exception will be thrown only at the execution stage of the application.
Import from DLL can be carried out by procedure (function) name, sequence number or
with a different name.
In the first case, you simply declare the name of the procedure and the library from which you are importing it
(we looked at this a little higher). Importing by sequence number requires you to specify this very number:
procedure HelloWorld(AForm: TForm); external myfirstdll.dll index 15;
In this case, the name you give to the procedure when importing does not have to be the same as
which was specified for it in the DLL itself. Those. the above entry means,
that you are importing from the dynamic library myfirstdll.dll the procedure that was exported in it
fifteenth, and within your application this procedure is named SayHello.
If for some reason you do not use the import method described above,
but still want to change the name of the imported function (procedure), you can use the third method:
procedure CoolProcedure; external myfirstdll.dll name "DoSomethingReallyCool";
Here, the imported CoolProcedure procedure is named DoSomethingReallyCool.
Calling procedures and functions imported from dynamically loaded libraries
somewhat more complicated than the method we discussed above. In this case, you need to declare
a pointer to the function or procedure you are going to use.
Remember the HelloWorld procedure? Let's see what needs to be done to
to call it to execute in case of dynamic loading of a DLL. First of all, you
it is necessary to declare a type that would describe this procedure:
type
THelloWorld = procedure(AForm: TForm);
Now you must load the dynamic library, using GetProcAddress get
a pointer to a procedure, call this procedure for execution, and finally unload the DLL from memory.
Below is code demonstrating how this can be done:

DLLInstance: THandle ;

HelloWorld:THelloWorld;

begin

(load DLL)

(we get a pointer)

(call the procedure for execution)

HelloWorld(Self) ;

(unload DLL from RAM)

FreeLibrary(DLLInstance) ;

end ;

As mentioned above, one of the disadvantages of statically loading a DLL is the inability to
continuation of application operation in the absence of one or more libraries. In the case of dynamic
By downloading, you have the opportunity to programmatically handle such situations and prevent the program from
fell out" on its own. Based on the values ​​returned by the LoadLibrary and GetProcAddress functions, you can
determine whether the library was loaded successfully and whether the procedure required by the application was found in it.
The code below demonstrates this.

procedure TForm1.DynamicLoadBtnClick (Sender: TObject ) ;

type

THelloWorld = procedure (AForm: TForm);

DLLInstance: THandle ;

HelloWorld:THelloWorld;

begin

DLLInstance:= LoadLibrary("myfirstdll.dll" ) ;

if DLLInstance = 0 then begin

MessageDlg( "Unable to load DLL", mtError, [ mbOK], 0 ) ;

Exit ;

end ;

@HelloWorld:= GetProcAddress(DLLInstance, "HelloWorld" ) ;

if @HelloWorld nil then

HelloWorld (Self)

else

MessageDlg( "The required procedure was not found!.", mtError, [ mbOK], 0 ) ;

FreeLibrary(DLLInstance) ;

end ;

DLLs can store not only code, but also forms.
Moreover, creating and placing forms in a dynamic library is not too much different from working
with forms in a regular project. First we'll look at how a library can be written,
containing forms, and then we'll talk about using MDI technology in a DLL.
I will demonstrate the development of a DLL containing a form using an example.
So, first, let's create a new dynamic library project.
To do this, select the File|New menu item, and then double-click on the DLL icon.
After this you will see code similar to the following:

Save the resulting project. Let's call it DllForms.dpr.
Now you need to create a new form. This can be done in different ways.
For example, by selecting the File|New Form menu item. Add some components to the form.
Let's name the form DllForm and save the resulting module under the name DllFormUnit.pas.
Let's return to the main module of the project and place the ShowForm function in it, the task of which will include
creating a form and displaying it on the screen. Use the code below for this.

Form: TDLLForm;

begin

Result:= Form.ShowModal ;

Form.Free ;

end ;

Please note that in order for the project to be compiled without errors, you need to add the Forms module to the uses section.
We export our function using the exports keyword:
exports
ShowForm;
We compile the project and get the dllforms.dll file. These simple steps are everything
what you need to do to note that the ShowForm function is declared using the stdcall keyword.
It signals the compiler to use the convention when exporting a function
by standard call calling convention. Exporting a function this way creates
the ability to use the developed DLL not only in applications created in Delphi.
Calling conventions determine how arguments are passed when calling a function.
There are five main conventions: stdcall, cdecl, pascal, register and safecall.
You can learn more about this by looking at the "Calling Conventions" section in the Delphi help file.
Also note that the value returned by the ShowForm function is
corresponds to the ShowModal value. This way you can transfer some information
about the state of the form to the calling application.
Below are two listings, the first of which contains the complete code for the file
DLL project (the module with the form is not shown here), and the second is the calling application module,
which uses the library we just developed.

libraryDllForms;

uses

DllFormUnit in "DllFormUnit.pas" (DllForm) ;

($R *.RES)

function ShowForm: Integer ; stdcall ;

Form: TDLLForm;

begin

Form:= TDLLForm.Create(Application) ;

Result:= Form.ShowModal ;

Form.Free ;

end ;

begin

end.


unit TestAppUnit;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls;

type

TForm1 = class(TForm)

Button1: TButton;

procedure Button1Click(Sender: TObject ) ;

private

(Private declarations)

public

(Public declarations)

end ;

Form1: TForm1;

function ShowForm: Integer ; stdcall ;

External "dllforms.dll" ;

implementation

($R *.DFM)

procedure TForm1.Button1Click (Sender: TObject ) ;

begin

end ;

end.

Please note that the stdcall keyword was also used when exporting the function.
You should pay special attention to working with child forms in DLLs. If, for example,
in the calling application, the main form has a FormStyle property value equal to MDIForm,
then when you try to call the MDIChild-form from the DLL, an error message appears on the screen,
which will say that there is no active MDI form.
The moment you try to show your child window, VCL checks for correctness
FormStyle properties of the application's main form. However, in our case everything seems to be true.
So what's the deal? The problem is that when performing such a check, the Application object is considered,
belonging not to the calling application, but to the dynamic library itself.
Well, naturally, since the DLL does not have a main form, the check throws an error.
In order to avoid this situation, you need to assign the Application object of the dynamic library
the Application object of the calling application. Naturally, this will only work if
when the calling program is a VCL application. In addition, before unloading the library from memory
it is necessary to return the value of the library's Application object to its original state.
This will allow the memory manager to clean up the RAM occupied by the library.
Therefore, you need to store a pointer to the library's native Application object
in a global variable that can be used to restore its value.
So, let's go back a little and list the steps we need to work with placed
in DLL MDIChild forms.
In the dynamic library we create a global variable of type TApplication.
We store a pointer to the Application DLL object in a global variable.
We assign a pointer to Application to the Application object of the dynamic library
calling application.
We create an MDIChild form and work with it.
We return the value of the Application object of the dynamic library to its original state
and unload the DLL from memory.
The first step is simple. We simply place the following code at the top of the DLL module:
var
DllApp:TApplication;
Then we create a procedure that will change the value of the Application object and create a child form.
The procedure might look something like this:

procedure ShowMDIChild(MainApp: TApplication) ;

Child: TMDIChild;

begin

if not Assigned (DllApp) then begin

DllApp:= Application;

Application:= MainApp;

end ;

Child:= TMDIChild.Create(Application.MainForm) ;

Child.Show ;

end ;

All we need to do now is provide the return value of the Application object
to its original state. We do this using the MyDllProc procedure:

procedure MyDLLProc(Reason: Integer ) ;

begin

if Reason = DLL_PROCESS_DETACH then

(DLL is unloaded. Restore the value of the Application pointer)

if Assigned (DllApp) then

Application:= DllApp;

end ;

Instead of a conclusion.
Using dynamic link libraries is not as difficult as it might seem at first glance.

Using dynamic link libraries is not as difficult as it might seem at first glance.
DLLs provide extensive opportunities for optimizing application performance,
as well as the work of the programmers themselves. Use DLL and maybe your life will become easier!
http://subscribe.ru/
Email: [email protected] Search
to APORT on Subscribe.Ru

  • Concept of DLL
  • Creating DLLs in Delphi (export)
  • Using DLLs in Delphi (import)
  • DLLs that use VCL objects to manipulate data
  • Exceptions in DLLs
  • Concept of DLL

Let's remember the programming process in DOS. Converting the source code of a program into machine code involved two processes - compilation and linking. During the linking process, the link editor, which assembled individual program modules, placed into the program code not only declarations of functions and procedures, but also their complete code. You prepared one program in this way, another, a third... And everywhere the code of the same functions was placed completely in the program.

Program1 Program2: : MyFunc(:) MyFunc(:) : : function code MyFunc function code MyFunc other function code other function code

In a multitasking environment, such an approach would be at least reckless, since it is obvious that a huge number of the same functions are responsible for drawing user interface elements, accessing system resources, etc. would be completely duplicated in all applications, which would lead to rapid depletion of the most expensive resource - RAM. As a solution to this problem, the concept of dynamic linking was proposed even on UNIX-like platforms (see Fig. 2).

But what is the difference between Dynamic Link Library (DLL) and regular applications? To understand this, you need to clarify the concepts of a task, an instance (copy) of an application (instance) and a module (module).

When running multiple instances of the same application, Windows loads only one copy of the code and resources into RAM - the application module, creating several separate data segments, a stack and a message queue (see Figure 3), each set of which represents a task, in the sense Windows. The application copy represents the context in which the application module runs.

DLL - library is also a module. It is located in memory in a single copy and contains a code segment and resources, as well as a data segment (see Fig. 4).

A DLL is a library; unlike an application, it has neither a stack nor a message queue. Functions placed in a DLL are executed in the context of the calling application, using its stack. But these same functions use a data segment that belongs to the library, not a copy of the application.

Due to this organization of the DLL, memory savings are achieved due to the fact that all running applications use one DLL module, without including certain standard functions in their modules.

Often, separate sets of functions are created in the form of DLLs, united according to certain logical criteria, similar to how modules (in the sense of unit) are conceptually planned in Pascal. The difference is that functions from Pascal modules are linked statically, at the linking stage, while functions from DLLs are linked dynamically, that is, at run-time.

Creating DLLs in Delphi (export)

For DLL programming, Delphi provides a number of keywords and syntax rules. The main thing is that a DLL in Delphi is the same project as a program.

Consider the DLL template:


The project file name for such a template should be MYDLL.DPR.

Unfortunately, the Delphi IDE automatically generates only the program project, so you will have to prepare the DLL project manually. In Delphi 2.0 this inconvenience is eliminated.

Like a program, a DLL has a uses section. The initialization part is optional. The exports section lists the functions that should be accessed from external applications.

Exporting functions (and procedures) can be done in several ways:

  • by number (index)
  • by name

Depending on this, different syntax is used:


Since in Windows there is a concept of “resident functions” of a DLL, that is, those functions that are in memory throughout the entire lifetime of the DLL in memory, Delphi has tools for organizing and exporting this kind of thing:


then the indexing of the exported functions will be done automatically by Delphi, and such an export will be considered an export by name that matches the name of the function. Then the declaration of the imported function in the application must match the name of the function declaration in the DLL. As for the directives imposed on already imported functions, we will talk about this below.

Using DLLs in Delphi (import)

To organize imports, i.e. Delphi provides standard tools for accessing functions exported from DLLs, as well as for exporting them.

For the examples shown above, your program should declare the functions imported from the DLL this way:


This method is called static import.

As you may have noticed, the extension of the file containing the DLL is not specified - the default is *.DLL and *.EXE files. What then to do if the file has a different extension (for example, like COMPLIB.DCL in Delphi), or if dynamic determination of DLLs and imported functions is required (for example, your program works with different graphic formats, and for each of them there is a separate DLL)?

To solve this kind of problem, you can contact the Windows API directly, using the so-called dynamic import:


uses WinTypes, WinProcs, ... ; type TMyProc = procedure ; var Handle:THandle; MyImportProc: TMyProc; begin Handle:= LoadLibrary("MYDLL"); if Handle >= 32 then ( if begin@MyImportProc:= GetProcAddress(Handle, "MYEXPORTPROC"); if MyImportProc nil then ... (using imported procedure) end; FreeLibrary(Handle); end;

Syntax diagrams for export/import declarations, substitution of DLL exit points, and other examples can be found in OnLine Help Delphi, Object Pascal Language Guide, included in the Borland RAD Pack for Delphi, and, for example, in the book "Teach Yourself Delphi in 21 Days".

If we don’t talk about the code generated by the compiler (now it is more optimized), then all the syntax rules remain the same as in Borland Pascal 7.0

DLLs that use VCL objects to manipulate data

When creating your own dynamic library, you can use function calls from other DLLs. An example of such a DLL is in the Delphi distribution (X:\DELPHI\DEMOS\BD\BDEDLL). This DLL contains a form that displays data from the table and uses VCL objects (TTable, TDBGrid, TSession) to access it, which in turn call BDE functions. As the comments to this example indicate, this DLL has a limitation: it cannot be used by multiple tasks at the same time. This is because the Session object, which is created automatically when a DB module is attached, is initialized for the module, not for the task. If you try to load this DLL a second time from another application, an error will occur. To prevent multiple tasks from loading a DLL at the same time, you need to take some steps. In the example, this is a procedure for checking whether a DLL is currently in use by another task.

Exceptions in DLLs

An exception occurring in a DLL created in Delphi will cause the entire application to terminate if the exception was not handled within the DLL. Therefore, it is advisable to provide for all possible troubles at the time of DLL development. It is recommended to return the result of the imported function as a string or number and, if necessary, re-raise the exception in the program.


function MyFunc: string; begin try (the actual function code) except on EResult: Exception do Result:=Format(DllErrorViewingTable, ) else Result:= Format(DllErrorViewingTable, ["Unknown error"]); end; end;

Code in the program:


StrResult:= MyFunc; if StrResult "" then raise Exception.Create(StrResult);

A DLL library allows you to combine reusable code into one whole. Functions from DLL libraries can be linked dynamically at runtime, in contrast to functions from Delphi packages, which are linked statically at the compilation stage of the application.

In order to create a DLL library, first you need to execute the File|New|Other menu command and select the DLL Wizard element on the New page of the New Item dialog.

The DLL Wizard will automatically create a blank template for the DLL. Unlike a regular module, which begins with the unit keyword, a DLL library module begins with the library keyword. The uses section of the DLL module requires the inclusion of only two packages: SysUtils and Classes.

Creating a DLL function consists of several steps:

1. First, in the module implementation section, you must enter the function signature and program the code that the function executes.

3. Finally, a function that is supposed to be used not only inside a module, but also called from other applications, should be declared as exportable in the exports section.

Functions from a DLL can be called both from applications developed in Delphi and from applications written in other programming languages, such as C++.

The order of allocating memory for parameters and freeing it is different for different programming languages. To avoid a run-time error, the function declaration in the DLL and the function declaration in the application must use the same parameter passing mechanism. When declaring a procedure or function, one of the following mechanisms for passing parameters can be specified:

The method of passing parameters is indicated with a semicolon after the function description. For example:

function F1 (X, Y, Z: Real]: Real; stdcall;.

The different parameter passing methods determine the order in which parameters are passed (left to right or right to left) and also indicate who will deallocate stack memory (the called procedure or the calling procedure). When using DLLs as components called from applications in other programming languages, you should use the appropriate call modifier. For C++ applications, the stdcall call modifier is used.

In order for a function described in a DLL to be called from another application, the function must be exported. The list of all exported functions is indicated in the exports section, separated by commas

and ends with a semicolon. Exporting functions can be done in three ways:

By the function name used in the DLL;

By function name specified as export name;

By the index assigned to the function.

In order to assign an index to a function, it should be specified in the exports section after the function name with the index keyword.

In order for the exported function to be called by a name different from the name used in the DLL library, in the exports section after the function name, you must specify the keyword name and the new export name for this function.

DLL - the library is not an executable module. To obtain its code, it is enough to compile the project.

library project;

SysUtils, Classes;

function F1(X, Y: Integer): Integer; stdcall;

Statically linking a DLL library

The DLL can be linked either statically or dynamically. When you include a DLL, it is loaded into application memory.

With a static connection, the DLL is loaded once when the application starts. Throughout the application's execution, the name of a function imported from a DLL that was statically linked points to the same function (the entry point to the DLL) in the same DLL. All functions from the DLL that will be used initially in the application must be declared as external. In this case, you should specify, if necessary, a call modifier. If a function is called by index, it must be given the name used in the application and the index of the function in the DLL.

Declarations of external functions are performed in the implementation section before using these functions.

Declaration of external functions with the external keyword specifies that static linking will be used.

TForml = class(TForm)

Editl: TEdit; [Field for entering the first value)

Edit2: TEdit; (Field for entering the second value)

Edit3: TEdit; (Field to display the result

execute a function from a DLL)

Buttonl: TButton; (A call is made to the function used by name)

Button2: TButton; [A function call is made using the index)

procedure ButtonlClickfSender: TObject);

procedure Button2Click(Sender: TObject);

(Private declarations)

(Public declarations)

(Declaration of exported functions)

function Fl (i: Integer; j: Integer): Integer; stdcall;

external "Projectl.dll";

function F2 (i: Integer; j:Integer): Integer; stdcall;

external "Projectl.dll index 2;

procedure TForml.ButtonlClick(Sender: TObject);

(Call exported function)

Edit3.Text:=IntToStr(Fl(StrToInt(Editl.Text),StrToInt(Edit2.Text) ));

procedure TForml.Button2Click(Sender: TObject);

Edit3.Text:=JntToStr(F2(StrToInt(Editl.Text),StrToInt(Edit2.Text)));

Dynamically linking a DLL library

Unlike statically linking a DLL, which occurs when the application loads, dynamically linking a DLL can be done at any point in the program's execution. After calling a function from a DLL, you can disable it. When using several DLLs simultaneously, this provides significant memory savings. Windows API functions are used to dynamically connect a DLL library. Windows API - this is a set of standard functions used to implement interaction with the operating system.

When calling a function from a dynamically linked DLL, instead of defining the function name as external in the case of static linking, you should define a new type corresponding to the type of the function being called and create a variable of that type.

To make a function call from a dynamic link DLL, follow these steps:

1. Create a new type. corresponding to the type of the called function (the name of the new type can be entered after the type section).

For example:

TMyFl=function(i,j:Integer):Integer; stdcall;

2. In the var section of the interface section of the module, create a variable of the created function type. For example: MyFl: TMyFl;

3. Before loading the DLL library, declare a variable of type Integer, which will contain the descriptor of the library being connected.

4. Call the LoadLibrary method, which loads the DLL. For example; h:=LoadLibrary("Projectl.dll");

5. Check if the library connection is successful. If the DLL name is incorrect or the DLL is not found, the LoadLibrary function will return 0.

6. If you successfully connect the DLL library, you next need to get the function address. To do this, the Windows API function GetProcAddress is used, the parameters of which are the DLL library descriptor and the name of the connected function. For example: @MyFl: =GetProcAddress(h, "Fl");

7. If the function address is received, then the value of the address (in our example @MyFl) should not be equal to nil.

8. At this point, you can call a function from a dynamically linked DLL.

9. To free and therefore unload the DLL, call the FreeLibrary method, which disables the DLL.

Windows, Messages, SysUtils, Variants, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls;

TForml = class(TForm)

Button3: TButton;

procedure Button3Click

procedure TForml.Button3Click(Sender: TObject);

h:=LoadLibrary("Projectl.dll");

if h<>0 then

@MyFl:=GetProcAddress(h,"Fl");

if @MyFl<>nil then

Edit3.Text:=IntToStr(MyFl(StrToInt(Editl.Text),

StrToInt(Edit2.Text)));

Using a DLL to call common modal dialogs.

The result of executing a procedure from a DLL library can be the display of some modal dialog. To do this, create a form object in the exported method, display it as a modal dialog, and then delete the form object. In this case, the form itself should provide a call to the Close method to end the dialog.

To create a form, use the Create method, which is passed as a parameter a pointer to the parent form - the form of the calling application. This parameter is passed to the called DLL function.

library project;

Unitl_DLL in "Unitl_DLL.pas" (Forml);

procedure MyModalForm (var Z:Integer ;F:TForm1); stdcall;

Form1:=TForml.Create(F);

(The F parameter is passed when calling the procedure and contains a pointer

to the parent form - the form of the calling application)

More than once I have received letters asking me to tell about the creation and use of DLLs in Delphi. In this article, we will figure it all out and create our own library. Dynamically linked libraries (Dynamic Link Libraries) enable different applications to use a common set of resources in their work. The important thing is that the procedures and functions placed in the DLL are executed within the process that uses them. A DLL provides all applications with one single copy of a resource that is shared among all applications that request it, as opposed to routines, which run a separate copy for each application that calls them. Also, in contrast to DLLs and subroutines, you can also include the fact that DLLs can export only procedures and functions, but not types, constants, etc.

I would like to quote an excerpt from “Delphi Lessons” about the structure of DLLs in memory:

A DLL is a library; unlike an application, it has neither a stack nor a message queue. Functions placed in a DLL are executed in the context of the calling application, using its stack. But these same functions use a data segment that belongs to the library, not a copy of the application. Due to this organization of the DLL, memory savings are achieved due to the fact that all running applications use one DLL module, without including certain standard functions in their modules. Often, separate sets of functions are created in the form of DLLs, united according to certain logical criteria, similar to how modules (in the sense of unit) are conceptually planned in Pascal. The difference is that functions from Pascal modules are linked statically, at the linking stage, while functions from DLLs are linked dynamically, that is, at run-time.

Creating a DLL

The DLL structure is not much different from the normal module structure in Object Pascal. The DLL must begin with the word Library, followed by the name of the library. The functions and procedures that the DLL will make available to other users (exported) are listed after the exports directive.

For each procedure or function, you can specify its number using the Index directive. If the number is missing, the compiler will perform automatic indexing. Instead of a procedure number, you can use a unique name, which is specified using the name directive. If neither the function name nor its number is specified, then Delphi will perceive this as an export by name, which will coincide with the name of the function.

The library may also contain initialization code that will be executed when it is loaded. It is placed between begin and end. Here is the general structure of the DLL:

Library First_Dll; uses<используемые модули>; <объявления и описания функций>exports<экспортируемые функции> <описание процедур и функций>begin<инициализационная часть>end.

I will give examples of descriptions of exported functions in the exports section:

Exports Function1 index 2; Fucntion2 name "My_sqr"; Function3;

As you may have guessed, the name of the function may not coincide with the name for export!!!

Using DLLs

A module that needs to use procedures and functions from a DLL must use the external directive. There are two ways to use DLL (dynamic and static). In the first case, the application calling the function from the DLL knows the name of the library and its entry point, and it is assumed that the library does not change. In the second case, before using the DLL, you should make sure that the required library exists and that it contains the necessary routine.

You can import a subroutine by its name and number. Searching for a subroutine by number is faster, but it is always convenient.

Below are examples of importing functions from our First_DLL, which was discussed in the example:

(import by specified name) Function ImportByName; external "First_DLL" name "My_sqr"; ( import by index ) Function ImportByOrdinal; external "First_DLL" index 2; (import by original name) Function Fucntion3; external "First_DLL";

We looked at the static method of using a DLL. But in some cases it is not known in advance which library will be needed, so you should use the dynamic method:

Uses WinTypes, WinProcs, ... ; type TMyProc = procedure ; var Handle: THandle; MyImportProc: TMyProc; begin Handle:=LoadLibrary("FirstDLL"); if Handle>=32 then ( if<=32 - ошибка! } begin @MyImportProc:=GetProcAddress(Handle,"My_sqr"); if MyImportProc<>nil then ...... (here we use the resulting function) end; FreeLibrary(Handle); end;

But in my opinion, everything that is written here is not very clear and I want real, complete examples. I was always upset when articles had few examples and only theory, so I bring to your attention a simple example of using a DLL.

Click on the File -> New menu and select DLL. Save the finished template as suggested under the name Project1.dpr.

Below is its full code:

Library Project1; uses SysUtils,Classes; Function Function1(x,y:integer):integer; export; bgin result:=x+y; end; Function Function2(x,y:real):real; export; var t:real; begin t:=exp(y*ln(x)); result:=t; end; exports Function1 index 1, Function2 name "My_sqr"; begin end.

There are two functions here, the first one calculates the sum of two numbers and is exported by number, and the second one calculates x to the power of y and is exported by name.

Now let's create a new project and save it under some other name, for example, DemoDLL. Let's place two buttons on the form, clicking on the first of them will call the first procedure, and clicking on the second will call the second. Here is the complete code for this demo project:

Unit demo; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private ( Private declarations ) public ( Public declarations ) end; var Form1: TForm1; implementation ($R *.DFM) function ImportSumm(x,y:integer):integer; external "Project1" index 1; //import by number function ImportSqr(x,y:real):real; external "Project1" name "My_sqr"; //import by name procedure TForm1.Button1Click(Sender: TObject); var t:real; begin //Find out how much two to the third power is t:=ImportSqr(2,3); Showmessage(FloatTostr(t)); end; procedure TForm1.Button2Click(Sender: TObject); var t:integer; begin //Find out how much 10+10 will be t:=ImportSumm(10,10); Showmessage(IntTostr(t)); end; end.

Delphi, MySQL programmer. Higher education. Specialty: information technology software.







2024 gtavrl.ru.