Creating active libraries in delphi. Creation and use of dynamic libraries (DLL) in Delphi. After the function text we assign

More than once I had to receive letters asking me to talk about creating and using DLLs in Delphi. In this article, we will figure it out and create our own library. Dynamically linked libraries (Dinamic Link Library) enable various applications to use a common set of resources during their work. The important thing is that the procedures and functions placed in the DLL are executed inside the process that uses them. The DLL provides for all applications one single copy of the resource that is shared by all the applications that requested it, unlike routines that run for each application that calls them a separate copy. Also, unlike DLLs from routines, you can include the fact that DLLs can only export procedures and functions, but not types, constants, etc.

I would like to give an excerpt from Delphi's Lessons on the structure of DLLs in memory:

DLL - a library, unlike an application, has neither a stack nor a message queue. Functions placed in the DLL are executed in the context of the calling application using its stack. But these functions use the data segment belonging to the library, and not a copy of the application. Due to the organization of DLLs, memory savings are achieved due to the fact that all running applications use one DLL module, not including those or other standard functions in their modules. Often, in the form of DLLs, separate sets of functions are created, united by one or another logical attribute, similar to how conceptually the planning of modules (in the sense of unit) occurs in Pascal. The difference is that the functions from the Pascal modules are linked statically - at the linking stage, and the functions from the DLL are linked dynamically, that is, at run-time.

DLL creation

The structure of the DLL is not much different from the usual module structure in Object Pascal. The DLL should start with the word Library, followed by the name of the library. The functions and procedures that the DLL will provide to other users (export) 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 automatically index it. Instead of the procedure number, you can use a unique name, which is set using the name directive. If neither the name of the function nor its number is specified, then Delphi will take it as an export by name, which will coincide with the name of the function.

A 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 the description of exported functions in the exports section:

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

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

Using DLL

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

You can import a subprogram by its name and number. Finding a subroutine by number is faster, but always convenient.

The following are examples of importing functions from our First_DLL, which was examined in the example:

  (import by the 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 examined a static method for using DLLs. 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 \u003d procedure; var Handle: THandle; MyImportProc: TMyProc; begin Handle: \u003d LoadLibrary ("FirstDLL"); if Handle\u003e \u003d 32 then (if<=32 - ошибка! } begin @MyImportProc:=GetProcAddress(Handle,"My_sqr"); if MyImportProc<>nil then ...... (here we use the received 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 there were few examples in the articles, but only one theory, so I bring to your attention a simple example of using DLLs.

Click on the menu File -\u003e New and select the 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: \u003d x + y; end; Function Function2 (x, y: real): real; export; var t: real; begin t: \u003d exp (y * ln (x)); result: \u003d t; end; exports Function1 index 1, Function2 name "My_sqr"; begin end.

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

Now create a new project and save it under some other name, for example, DemoDLL. 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 \u003d 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 function number ImportSqr (x, y: real): real; external "Project1" name "My_sqr"; // import named procedure TForm1.Button1Click (Sender: TObject); var t: real; begin // Find out how many two will be in the third power t: \u003d 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: \u003d ImportSumm (10,10); Showmessage (IntTostr (t)); end; end.

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

I bring to your attention the next issue of the newsletter, in which I continue to discuss
   development and use of DLLs in Borland Delphi. For new subscribers inform
   that they can see 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 an answer. In the near future I will try to fix it.
  So, let's continue.

Before you start using a procedure or function located in a dynamic library,
  You need to load the DLL into RAM. Library loading can be done
  in one of two ways: static loading and dynamic loading.
Both methods have both advantages and disadvantages.
  Static loading means the dynamic library loads automatically
  when starting to execute the application using it. In order to use this download method,
  you need to use the external keyword when describing exported from
   dynamic library functions or procedures. DLL is loaded automatically when the program starts,
   and you can use any routines exported from it in the same way
   as if they were described inside the 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 to which
   there is a link in the application, missing, the program will refuse to load.
  The meaning of the dynamic method is that you do not load the library when the application starts,
  and at that moment when you really need it. Judge for yourself, because if the function described
  in a dynamic library, used only at 10% of program launches, then absolutely not
  it makes sense to use a static boot method. Unloading the library from memory in this case
  also carried out under your control. Another advantage of this method
  DLL loading is a decrease (for obvious reasons) in the start time of your application.
  And what are the disadvantages of this method? The main, it seems to me, is that using
   This method is more troublesome than the static load discussed above.
   First you need to use the Windows API LoadLibrary function.
   To get a pointer to the exported procedure or function must
   GetProcAddress function is used. After using the DLL
   Must be unloaded using FreeLibrary.
  Calling procedures and functions loaded from a DLL.
  The way you call procedures and functions depends on how you loaded the dynamic library,
  in which these routines are located.
  Calling functions and procedures from statically loaded DLLs is quite simple. Originally in the app
  The description of the exported function (procedure) should be included. After that you can use them
   exactly as if they were described in one of the modules of your application.
  To import a function or procedure contained in a DLL, you must use
external modifier in their ad. For example, for the HelloWorld procedure we examined above
   the following line should be placed in the calling application:
  procedure SayHello (AForm: TForm); external myfirstdll.dll ";
  The external keyword tells the compiler that this procedure can be found in
   dynamic library (in our case - myfirstdll.dll).
  Next, the call to this procedure is as follows:
...
  HelloWorld (self);
...
  When importing functions and procedures, be especially careful when writing their names and interfaces!
   The fact is that during the compilation of the application there is no check on the correctness of the names of objects,
  exported from a DLL will not be implemented, and if you incorrectly described any function,
  this exception will be generated only at the stage of the application execution.
  Import from DLL can be performed by the name of the procedure (function), serial number or
  with the assignment of a different name.
  In the first case, you simply declare the name of the procedure and the library from which you import it
   (we examined this a little higher). Import by serial number requires you to specify this very number:
  procedure HelloWorld (AForm: TForm); external myfirstdll.dll index 15;
  In this case, the name that you give to the procedure during import does not have to be the same as
   which was specified for her in the DLL itself. Those. the above entry means
  what do you import from the dynamic myfirstdll.dll library the procedure that was exported in it
   the fifteenth, and at the same time, as part of your application, this procedure is named SayHello.
  If for some reason you do not use the import method described above,
  but nevertheless you 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 examined above. In this case, you need to declare
   pointer to the function or procedure that you are going to use.
   Remember the HelloWorld procedure? Let's see what needs to be done in order
   to execute it in case of dynamic loading of DLL. First you
  you must declare a type that describes this procedure:
  type
   THelloWorld \u003d procedure (AForm: TForm);
Now you have to load the dynamic library using GetProcAddress to get
  a pointer to a procedure, call this procedure to execute, and finally unload the DLL from memory.
  Below is a code demonstrating how to do this:

DLLInstance: THandle;

HelloWorld: THelloWorld;

begin

(load the DLL)

(we get a pointer)

(call the procedure to execute)

HelloWorld (Self);

(we unload DLL from random access memory)

FreeLibrary (DLLInstance);

end;

As mentioned above, one of the disadvantages of static DLL loading is the inability to
  Continuation of the application 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 "independently. The values \u200b\u200breturned by the LoadLibrary and GetProcAddress functions can be
   determine whether the library was downloaded successfully and if the necessary procedure was found in it.
   The code below demonstrates this.

procedure TForm1.DynamicLoadBtnClick (Sender: TObject);

type

THelloWorld \u003d procedure (AForm: TForm);

DLLInstance: THandle;

HelloWorld: THelloWorld;

begin

DLLInstance: \u003d LoadLibrary ("myfirstdll.dll");

if DLLInstance \u003d 0 then begin

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

Exit

end;

   @HelloWorld: \u003d GetProcAddress (DLLInstance, "HelloWorld");

if @HelloWorld nil then

HelloWorld (Self)

else

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

FreeLibrary (DLLInstance);

end;

In a DLL, you can store not only code, but also forms.
  Moreover, the creation and placement of forms in a dynamic library is not too different from work
   with forms in a regular project. First, we’ll look at how you can write a library,
  containing forms, and then we'll talk about using MDI technology in DLLs.
  I will demonstrate the development of a DLL containing a form using an example.
  So, firstly, create a new dynamic library project.
   To do this, select the File | New menu item, and then double-click on the DLL icon.
   After that, you will see something like the following code:

Save the received project. Let's call it DllForms.dpr.
  Now you should create a new form. This can be done in many ways.
   For example, by selecting the menu item File | New Form. Add any components to the form.
  Let's name the DllForm form and save the resulting module as DllFormUnit.pas.
  Let's go back to the main module of the project and put 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: \u003d Form.ShowModal;

Form.Free;

end;

I draw your attention to the fact that in order for the project to be compiled without errors, it is necessary 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 all
   What you need to do to c Note that the ShowForm function is declared using the stdcall keyword.
   It signals the compiler to use the convention when exporting the function.
   by standard call calling convention. Exporting a function in this way creates
  the ability to use the developed DLL not only in applications created in Delphi.
  The calling conventions determine how arguments are passed when the function is called.
  There are five main conventions: stdcall, cdecl, pascal, register, and safecall.
  You can learn more about this by looking at the Calling Conventions section of the Delphi help file.
  Also note that the value returned by the ShowForm function is
   corresponds to the value of ShowModal. This way you can transfer some information
   The state of the form to the calling application.
  Below are two listings, the first of which contains the full file code
  DLL project (the module with the form is not given here), and the second is the module of the calling application,
  which uses the library we just developed.

library DllForms;

uses

DllFormUnit in "DllFormUnit.pas" (DllForm);

($ R * .RES)

function ShowForm: Integer; stdcall;

Form: TDLLForm;

begin

Form: \u003d TDLLForm.Create (Application);

Result: \u003d Form.ShowModal;

Form.Free;

end;

begin

end.


unit TestAppUnit;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls;

type

TForm1 \u003d 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.
  Particular attention should be paid to working with child forms in DLLs. If, for example,
   in the calling application, the main form has a FormStyle value of 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 the correctness
  FormStyle properties of the main form of the application. However, in our case, everything seems to be true.
  So what's the deal? The problem is that when conducting such a check, the Application object is considered,
  belonging not to the calling application, but to the dynamic library itself.
   Well, of course, since there is no main form in the DLL, the check produces an error.
   In order to avoid this situation, it is necessary to assign a dynamic library to the Application object
   Application object of the calling application. Naturally, this will work only 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 Application object of the library to its original state.
  This will allow the memory manager to clear the RAM occupied by the library.
   Therefore, you need to keep the pointer to the Application object native to the library
  in a global variable that can be used to restore its value.
  So, let's go back a bit and list the steps we need to work with the placed
   in DLL with MDIChild forms.
  In a dynamic library, create a global variable of type TApplication.
  We save the pointer to the Application DLL object in a global variable.
  We assign to the Application object of the dynamic library a pointer to Application
   the calling application.
  Create an MDIChild form and work with it.
  Return to the initial state the value of the Application object of the dynamic library
   and unload the DLL from memory.
  The first step is simple. Just put 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: \u003d Application;

Application: \u003d MainApp;

end;

Child: \u003d TMDIChild.Create (Application.MainForm);

Child.Show;

end;

All we now need to do is envisage returning the value of the Application object
   in the initial state. We do this using the MyDllProc procedure:

procedure MyDLLProc (Reason: Integer);

begin

if Reason \u003d DLL_PROCESS_DETACH then

(DLL is unloaded. We restore the value of the Application pointer)

if Assigned (DllApp) then

Application: \u003d 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 the broadest possibilities for optimizing the work of applications,
   as well as the work of the programmers themselves. Use a DLL and perhaps your life will be easier!
http://subscribe.ru/
  E-mail: [email protected] Search
  on APORT on Subscribe.Ru

To create a new DLL in Delphi, select the menu command File\u003e New\u003e Other. In the panel Items Categories   window New items   select node Delphi projectsthen double click on the item Dynamic link library   in the right pane of the window.

Master DLL Wizard   creates the main source file of the DLL library, which looks almost the same as the source code generated for a regular application. The only difference is. that this file begins with a reserved word library, but not    program.

Library Project1; (Important note about DLL memory management: ShareMem must be the first unit in your library "s USES clause AND your project" s (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL - even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters.) (Important note regarding DLL library memory management: the ShareMem module must be the first module in the uses statement of your library and in the uses statement of your project (select the menu command Project -\u003e View Source (Project -\u003e Bye specify the source code)) if your DLL exports any procedures or functions that pass strings as parameters or results of function execution. This applies to all lines that are passed or received from your DLL, and even those lines that are nested in records and classes. The ShareMem module is the interface module for the shared memory manager BORLNDMM.DLL, which you must deploy with your DLL. To avoid using BORLNDMM.DLL, pass string information using the PChar or ShortString parameters. ) uses SysUtils, Classes; ($ R * .res) begin end.

All you have to do now is add the subroutine before the block begin-end, that's all. After that, you will get an internal routine that can be used in the DLL, but not in external applications. If you want to call a routine from other applications and other DLLs, you will need to export it. To export a routine by name, add it to the list. exports. List exports   has the same syntax as a list usesexcept on the list exports   any element is a subroutine, not a module.

List exports   usually placed immediately before the block begin-end. Take a look at Listing 1, which shows the source code for a simple library. FirstLib.dllexporting a single function.

Listing 1. Simple DLL

Library FirstLib; function Max3 (Num1, Num2, Num3: Integer): Integer; stdcall; begin Result: \u003d Num1; if Num2\u003e Result then Result: \u003d Num2; if Num3\u003e Result then Result: \u003d Num3; end; (Export Max3 function) exports Max3; begin end.

When you add a routine to the list exports, you thereby export the routine by its name. You can also export a subprogram under a different name using the directive name   or by ordinal value using the directive index. However apply the directive index   Not recommended.

The following is an example of exporting a directive using an ordinal value or under a different name:

Exports Max3 name "MyMax3Function", SaySomething index 1;

Static loading is the easiest of two possible ways to load a DLL. Static loading is also called dynamic connection at boot time ( load-time dynamic linking), because the DLLs used are automatically loaded at application startup time.

To statically load the DLL, you need to copy the subroutine declaration and the calling application and mark it with the directive external, which tells the compiler that the routine is either in the object file or in the DLL.

When you import routines from a DLL, you must mark them with the directive external, followed by the name of the DLL that contains the implementation of the routine. The following is an example of a function import. MachZ   from the library FirstLib.dll:

Function Max3 (Num1, Num2, Num3: Integer): Integer; stdcall; external "FirstLib.dll";

If you wish, you can even rename the subroutine during its import. To do this, you must declare the subroutine under a different name, and at the end of the declaration indicate the original name using the directive name:

Function Max (Num1, Num2, Num3: Integer): Integer; stdcall; external "FirstLib.dll" name "Max3";

You can also import a function from the DLL. To do this, create an import module and write a standard subprogram header in the section interface, and its external implementation is in the section implementation    of this module. Listing 2 shows the complete library import module code FirstLib.dll.

Listing 2. FirstLib.dll library import module.

Unit FirstLibInf; interface function Max3 (Num1, Num2, Num3: Integer): Integer; stdcall; implementation const FirstLib \u003d "FirstLib.dll"; (The compiler is informed that the implementation of the Max3 function is in the FirstLib.dll library) function Max3; external FirstLib; end.

After you create the DLL and its import module, test the DLL to make sure. that the subroutine is working fine. Since the DLL itself cannot be started, you need to create a test application that will access the DLL. This can be done most quickly if you create a project team by adding a new project to the current project. To do this, right-click on an item ProjectGroup1   in the window    Project manager   (Project Manager) and select the command in the context menu Add new projectas shown in fig. 1.

Listing 3. Checking the Max3 routine imported from the FirstLib.dll library.

Unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, FirstLibInf, StdCtrls; type TMainForm \u003d class (TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Max3Button: TButton; procedure Max3ButtonClick (Sender: TObject); private (Private declarations) public (Public declarations) end; var MainForm: TMainForm; implementation ($ R * .dfm) procedure TMainForm.Max3ButtonClick (Sender: TObject); var LargestNumber: Integer; begin LargestNumber: \u003d Max3 (StrToInt (Edit1.Text), StrToInt (Edit2.Text), StrToInt (Edit3.Text)); MessageDlg (Format ("Largest:% d.",), MtInformation,, 0); end; end.

Used literature: Inner World of Borland Delphi 2006. Ivan Hladni.

Due to the rapid development of programming technologies, more and more people are faced with the problem of building the capabilities of their programs. This article is devoted to this very issue, namely - programming DLL in Borland Delphi. In addition, since we will address issues related to the use of DLLs, we will also touch upon importing functions from foreign DLLs (including system ones, i.e. WinAPI).

DLL Applications

So, why are DLLs needed and where are they used? .. We list only a few of their areas of application:

  • Separate librariescontaining useful features for programmers. For example, functions for working with strings, or complex libraries for converting images.
  • Resource storage. In a DLL, you can store not only programs and functions, but also all kinds of resources - icons, pictures, string arrays, menus, etc.
  • Support Libraries. As an example, libraries of such well-known packages as: Directx, ICQAPI   (API for ICQ), Opengl   etc.
  • Program parts. For example, in a DLL you can store program windows (forms), etc.
  • Plugins   (Plugins). - That's where the real scope for the programmer's thoughts! Plugins - add-ons to the program, expanding its capabilities. For example, in this article we will consider the theory of creating a plug-in for our own program.
  • Shared Resource. DLL ( Dynamic link library) can be used by several programs or processes at once (the so-called sharing    - shared resource)

A brief description of the functions and techniques for working with DLL

So, what techniques and functions should be used to work with DLL? Let's analyze two methods of importing functions from a library:

1 way.   Binding a DLL to a program.   This is the easiest and easiest method to use functions imported from a DLL. However (and this should be noted), this method has a very significant drawback - if the library that the program uses is not found, then the program simply will not start, giving an error and indicating that the DLL resource was not found. A library search will be conducted: in the current directory, in the program directory, in the WINDOWS \\ SYSTEM directory, etc.
So, for starters - the general form of this technique:

implementation
...
function   FunctionName (Par1: Par1Type; Par2: Par2Type; ...): ReturnType; stdcall; external   "DLLNAME.DLL" name   "FunctionName" index   FuncIndex;
// or (if not a function, but a procedure):
procedure   ProcedureName (Par1: Par1Type; Par2: Par2Type; ...); stdcall; external   "DLLNAME.DLL" name   "ProcedureName" index   ProcIndex;

Here: Functionname   (or ProcedureName) - the name of the function (or procedure) that will be used in your program;
Par1, Par2, ...   - names of the parameters of the function or procedure;
Par1Type, Par2Type, ...   - parameter types of a function or procedure (e.g. Integer);
Returntype   - type of return value (only for the function);
stdcall   - a directive that must exactly match the one used in the DLL itself;
external "DLLNAME.DLL"   - a directive indicating the name of the external DLL from which this function or procedure will be imported (in this case - DLLNAME.DLL);
name "FunctionName" ("ProcedureName") - a directive indicating the exact name of the function in the DLL itself. This is an optional directive that allows you to use a function in the program that has a name different from the true one (which it has in the library);
index FunctionIndex (ProcedureIndex)   - a directive indicating the sequence number of a function or procedure in a DLL. This is also an optional directive.

2 way.   Dynamic loading of DLL.   This is a much more complex, but also more elegant method. It is free from the disadvantage of the first method. The only thing that’s unpleasant is the amount of code needed to implement this technique, and the difficulty is that the function imported from the DLL is accessible only when this DLL is loaded and is in memory ... An example can be found below, but for now - a short one Description of the WinAPI functions used by this method:

Loadlibrary(LibFileName: Pchar) - loading the specified LibFileName library into memory. On success, the function returns a handle ( Thandle) DLL in memory.
GetProcAddress(Module: Thandle; ProcName: Pchar) - reads the address of the exported library function. On success, the function returns a handle ( TFarProc) functions in the loaded DLL.
Freelibrary(LibModule: Thandle) - invalidates the LibModule and frees the associated memory. It should be noted that after calling this procedure the functions of this library are no longer available.

Practice and examples

Well, now it's time to give a couple of examples of the use of the above methods and techniques:

Now the same thing, but in the second way - with dynamic loading:

(... Here comes the file header and definition of form TForm1 and its instance Form1)

var
   Form1: TForm1;
  GetSimpleText: function(LangRus: Boolean): PChar;
  LibHandle: THandle;

procedure Button1Click (Sender: TObject);
begin
("Clean" the function address from "dirt")
  @GetSimpleText: \u003d nil;
(Trying to load the library)
  LibHandle: \u003d LoadLibrary ("MYDLL.DLL");
(If everything is OK)
  if LibHandle\u003e \u003d 32 then begin
(... then try to get the address of the function in the library)
  @GetSimpleText: \u003d GetProcAddress (LibHandle, "GetSimpleText");
(If here everything is OK)
  if @GetSimpleText<>   nil then
(... then we call this function and show the result)
  ShowMessage (StrPas (GetSimpleText (True)));
  end;
(And do not forget to free memory and unload DLL)
  FreeLibrary (LibHandle);
end;

NOTE : You should refrain from using the string type in library functions, as when using it there are problems with the "memory sharing". You can read more about this (though in English) in the text of an empty DLL project that creates Delphi (File -\u003e New -\u003e DLL). So it’s better to use PChar, and then convert it to string if necessary with the StrPas function.

Well, now we will analyze the DLL itself:

Placing resources and forms in a DLL

In a DLL, you can place not only functions, but also cursors, pictures, icons, menus, text strings. We will not dwell on this. I only note that to load a resource, you need to load the DLL, and then, having received its descriptor, load the resource itself with the corresponding function (LoadIcon, LoadCursor, etc.). In this section, we only touch on the placement of application windows (i.e., forms in Delphi) in DLLs.

To do this, create a new DLL and add a new form to it (File -\u003e New -\u003e DLL, and then - File -\u003e New Form). Further, if the form is a dialog box (modal form (bsDialog)), then add the following function to the DLL (for example, the form is called Form1, and its class is TForm1):

If you need to place a non-modal form in the DLL, then you need to do two functions - open and close the form. In this case, you need to force the DLL to remember the handle of this form.

Plugin creation

Here we will not consider plugins in detail, because the above examples will help you easily understand the lion's part of DLL programming. Let me just remind you that the plugin is an add-on to the program that expands its capabilities. At the same time, the program itself must necessarily provide for the presence of such additions and allow them to fulfill their mission.

That is, for example, to create a plug-in for a graphic editor that would perform image conversion, you need to provide at least two functions in the plug-in (and, accordingly, call these functions in the program) - a function that would return the name of the plug-in (and / or its type) to add this plugin to the menu (or to the toolbar), plus the main function - transmitting and receiving images. Those. first, the program searches for plugins, then for each found it calls its identification function with a strictly defined name (for example, GetPluginName) and adds the desired item to the menu, then, if the user selects this item, it calls the second function to which the input image (or file name, containing this image), and this function, in turn, processes the image and returns it in a new form (or the name of the file with the new image). That's the whole essence of the plugin ... :-)

Epilogue

This article highlights the main points of using and creating DLLs in Borland Delphi. If you have questions, drop them to me at E-mail: [email protected], or even better, write to the conference on this site so that other users can see your question and try to answer it!

Karih Nikolay. Moscow region, Zhukovsky

Abbreviation Dll   means "dynamic link library". Dll in Delphi   This is a file containing the procedures and functions necessary for the operation of a computer program with which the program is connected at the execution stage.

It would seem that all the necessary routines can be described in the body of the program, why do we need to create additional dll file   and connect with it at runtime? This is done for greater flexibility of the program being created. Indeed, over time, some data processing algorithms may change. If the processing procedures are contained in the body of the program, it will have to be recompiled, and a sufficiently large file will be transferred again to customers. Transferring a small dll file containing only a few procedures is much easier, and even in automatic mode.

In addition, the work of the dll library is completely independent of the programming language in which it will be created. Therefore, we can instruct third-party developers to create a dll for our program without thinking about the programming languages \u200b\u200bthat they know. All this, of course, greatly speeds up the creation and transfer to customers of a finished project

Creating a DLL

Creating a dll in Delphi no more complicated than creating an additional module. Run the command File -\u003e New -\u003e -\u003e Other ... In the dialog that appears, select the Wisard DLL icon. As a result, Delphi will create a draft DLL library project:

library   Project1;

(Important note about DLL memory management: ShareMem must be the
   first unit in your library "s USES clause AND your project" s (select
   Project-View Source) USES clause if your DLL exports any procedures or
   functions that pass strings as parameters or function results. This
   applies to all strings passed to and from your DLL - even those that
   are nested in records and classes. ShareMem is the interface unit to
   the BORLNDMM.DLL shared memory manager, which must be deployed along
   with your dll. To avoid using BORLNDMM.DLL, pass string information
   using PChar or ShortString parameters. )

uses
   Sysutils
   Classes

($ R * .res)

begin
  end
.

Choose a name for the new dll library and save to a separate folder by running the command File -> Save As ...   4 files will appear in the folder, among which the actual dll file will not be. Naturally, these are just text files containing a description of the project. To create the final dll library file, you must compile the project. Run the command Project -> Compile project. As a result, the actual dll file will appear in our folder, with which the main program will connect.

This is currently an empty library.

... the text is currently being edited ...

Devices