• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

DelphiDLL制作和加载Static,Dynamic,Delayed以及Shared-MemoryManager

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一 Dll的制作一般分为以下几步:
1 在一个DLL工程里写一个过程或函数
2 写一个Exports关键字,在其下写过程的名称。不用写参数和调用后缀。
二 参数传递
1 参数类型最好与window C++的参数类型一致。不要用DELPHI的数据类型。
2 最好有返回值[即使是一个过程],来报出调用成功或失败,或状态。成功或失败的返回值最好为1[成功]或0[失败].一句话,与windows c++兼容。
3 用stdcall声明后缀。
4 最好大小写敏感。
5 无须用far调用后缀,那只是为了与windows 16位程序兼容。

三 DLL的初始化和退出清理[如果需要初始化和退出清理]
1 DLLProc[SysUtils单元的一个Pointer]是DLL的入口。在此你可用你的函数替换了它的入口。但你的函数必须符合以下要求[其实就是一个回调函数]。如下:
procedure DllEnterPoint(dwReason: DWORD);far;stdcall;
dwReason参数有四种类型:
DLL_PROCESS_ATTACH:进程进入时
DLL_PROCESS_DETACH进程退出时
DLL_THREAD_ATTACH 线程进入时
DLL_THREAD_DETACH 线程退出时
在初始化部分写:
DLLProc := @DLLEnterPoint;
DllEnterPoint(DLL_PROCESS_ATTACH);
2 如Form上有TdcomConnection组件,就Uses Activex,在初始化时写一句CoInitialize (nil);
3 在退出时一定保证DcomConnection.Connected := False,并且数据集已关闭。否则报地址错。

四 全局变量的使用
在widnows 32位程序中,两个应用程序的地址空间是相互没有联系的。虽然DLL在内存中是一份,但变量是在各进程的地址空间中,因此你不能借助dll的全局变量来达到两个应用程序间的数据传递,除非你用内存映像文件。

五 调用静态载入
1 客户端函数声名:
1)大小写敏感。
2)与DLL中的声明一样。
如: showform(form:Tform);Far;external'yproject_dll.dll';
3)调用时传过去的参数类型最好也与windows c++一样。
4)调用时DLL必须在windows搜索路径中,顺序是:当前目录;Path路径;windows;widows\system;windows\ssystem32;

六 调用动态载入
1 建立一种过程类型[如果你对过程类型的变量只是一个指针的本质清楚的话,你就知道是怎么回事了]。如:
type
mypointer=procedure(form:Tform);Far;external;
var
Hinst:Thandle;
showform:mypointer;
begin
Hinst:=loadlibrary('yproject_dll');//Load一个Dll,按文件名找。
showform:=getprocaddress(Hinst,'showform');//按函数名找,大小写敏感。如果你知道自动化对象的本质就清楚了。
showform(application.mainform);//找到函数入口指针就调用。
Freelibrary(Hinst);
end;

七 在DLL建立一个TForM
1 把你的Form Uses到Dll中,你的Form用到的关联的单元也要Uses进来[这是最麻烦的一点,因为你的Form或许Uses了许多特殊的单元或函数]
2 传递一个Application参数,用它建立Form.

八 在DLL中建立一个TMDIChildForM
1 Dll中的MDIForm.FormStyle不用为fmMDIChild.
2 在CreateForm后写以下两句:


function ShowForm(mainForm:TForm):integer;stdcall
var
Form1: TForm1;
ptr:PLongInt;
begin
ptr:=@(Application.MainForm);//先把dll的MainForm句柄保存起来,也无须释放,只不过是替换一下

ptr^:=LongInt(mainForm);//用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源.

//为什么不直接Application.MainForm := mainForm,因为Application.MainForm是只读属性

Form1:=TForm1.Create(mainForm);//用参数建立
end;


备注:参数是主调程序的Application.MainForm

九 示例:
DLL源代码:

library Project2;

uses
SysUtils,
Classes,
Dialogs,
Forms,
Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}
var
ccc: Pchar;

procedure OpenForm(mainForm:TForm);stdcall;
var
Form1: TForm1;
ptr:PLongInt;
begin
ptr:=@(Application.MainForm);
ptr^:=LongInt(mainForm);
Form1:=TForm1.Create(mainForm);
end;

procedure InputCCC(Text: Pchar);stdcall;
begin
ccc := Text;
end;

procedure ShowCCC;stdcall;
begin
ShowMessage(String(ccc));
end;

exports
OpenForm;
InputCCC,
ShowCCC;
begin
end.

 调用方源代码:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
procedure OpenForm(mainForm:TForm);stdcall;External'project2.dll';
procedure ShowCCC;stdcall;External'project2.dll';
procedure InputCCC(Text: Pchar);stdcall;External'project2.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
Text: Pchar;
begin
Text := Pchar(Edit1.Text);
// OpenForm(Application.MainForm);//为了调MDICHILD
InputCCC(Text);//为了实验DLL中的全局变量是否在各个应用程序间共享
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ShowCCC;//这里表明WINDOWS 32位应用程序DLL中的全局变量也是在应用程序地址空间中,16位应用程序或许不同,没有做实验。
end;

How to create DLL s using Delphi

Introduction

DLL means Dynamic Link Libraries.

As the name implies , dll is a collection of functions and procedures in a place which can be used in other applications.

Basic idea of creating DLLs is to share functions and procedures across languages.

DLL files will have an extension of .dll.

How to create a dll using Delphi 

It's not so hard to create a dll as you heard.

Using Delphi it's very easy.

Select the menu File -> New -> Other... from Delphi IDE.

This will open a dialog box.

From there select the "DLL Wizard" icon .

A new project will be opened with a new unit.

This unit file will be little bit different from the normal unit files.

In the normal units , the first line will contain a keyword unit and the respective unitname.

But the unit created in dll , the first keyword will be library instead of unit as given below.

library DLLProject;

uses
SysUtils,
Classes;

{$R *.RES}

begin
end.

Now you can add as many functions and procedures under the uses clause.

The functions and procedures that are required to be called from other applications

should be exported using the clause Exports.

The name used along with the library clause will become the name of the dll. In this case our dll will be DLLProject.dll

Suppose you have 3 functions as shown below.

Function SubFunc():Integer;
begin
...
end;

Procedure SubProc();
begin
...
end;

Function MainFunc():Integer;
begin
...
SubFunc;
SubProc;
...
end;

Exports
MainFunc;

begin
end;

Here we have 2 functions and one procedure .

The MainFunc is the main function which calls other 2 functions and here we are exporting MainFunc only.

That means MainFunc is the only function which can be called from outside.

If you need to export any other function or procedure , you have to include it under the Exports clause.

Dll loading

Now we can see how these dll [exported] functions can be called from other applications.

The dll function/procedure has to be declared in the global section [before implementation section]

of the unit file where the it has to be called. The syntax should be

var
procedure MainFunc ():Integer; external 'DLLProject.dll';

Implementation.

end;

This kind of loading a dll is called static loading.

Because compiler try to load the dll when it loads the application itself.

So if the dll is missing in the search path , you'll get an erroro message while starting your application itself.

Now we'll see another kind of dll loading named Dynamic loading.

This kind of loading require extra commands to load dll , call your dll function and release the dll from memory.

The dll will be loaded in the memory whenever you call the LoadLibrary function.

It won't be loaded when your application starts.

So if the dll is missing in your search path, you won't get any error message during the start up of your application.

The dll should be loaded using the command LoadLibrary which returns the handle to the dll once it's loaded to the memory.

If there is any problem in loading, the handle will return 0.

Once dll is loaded properly in to the memory, we have to gather the address of the function\procedure to be called.

This can be done using the function GetProcAddress which returns the address of the dll function.

To receive the return value , you have to have a variable of type function or procedure [TDllAddr = function : Integer; ].

Have a look at the example shown below.

type

TDllAddr = function : Integer;

var
DllAddr : TDllAddr;

begin

DllHandle := LoadLibrary("DLLProject.dll");
if DllHandle <> 0 then
begin
@DllAddr := GetProcAddress(DllHandle , 'MainProc');
DllAddr(); // Calling dll function
end;

end;

Finally, the memory allocated for the dll has to be explicitly released using the FreeLibrary function.

Note :

The dll function parameters should be windows types.

If you have any String type parameter in dll function/procedure ,

then you have include ShareMem unit in the dll.

Not only that, Sharemem unit should be the first unit in the uses clause.

 

Note: Libraries are significantly more limited than packages in what they can export.

Libraries cannot export constants, types, and normal variables.

That is, class types defined in a library will not be seen in a program using that library.

To export items other than simple procedures and functions, 

packages are the recommended alternative.

Libraries should only be considered when interoperability with other programming is a requirement.

The following topics describe elements of writing dynamically loadable libraries, including

  • The exports clause.
  • Library initialization code.
  • Global variables.
  • Libraries and system variables.

Using Export Clause in Libraries

The main source for a dynamically loadable library is identical to that of a program, except that it begins with the reserved word library (instead of program).

Only routines that a library explicitly exports are available for importing by other libraries or programs. The following example shows a library with two exported functions, Min and Max:

library MinMax;
function Min(X, Y: Integer): Integer; stdcall;
begin
  if X < Y then Min := X else Min := Y;
end;
function Max(X, Y: Integer): Integer; stdcall;
begin
  if X > Y then Max := X else Max := Y;
end;
exports
  Min,
  Max;
  begin
 end.

 

If you want your library to be available to applications written in other languages,

it's safest to specify stdcall in the declarations of exported functions.

Other languages may not support Delphi's default register calling convention.

Libraries can be built from multiple units.

In this case, the library source file is frequently reduced to a uses clause, an exports clause, and the initialization code.

For example:

library Editors;
uses
EdInit, EdInOut, EdFormat, EdPrint;
exports InitEditors, DoneEditors name Done, InsertText name Insert, DeleteSelection name Delete, FormatSelection, PrintSelection name Print, . . . SetErrorHandler;
begin InitLibrary; end.

 

 

 

You can put exports clauses in the interface or implementation section of a unit.

Any library that includes such a unit in its uses clause

automatically exports the routines listed the unit's exports clauses

without the need for an exports clause of its own.

 


A routine is exported when it is listed in an exports clause, which has the form:

exports entry1, ..., entryn;

where each entry consists of the name of a procedure, function,

or variable (which must be declared prior to the exports clause),

followed by a parameter list (only if exporting a routine that is overloaded),

and an optional name specifier.

You can qualify the procedure or function name with the name of a unit.

(Entries can also include the directive resident, which is maintained for backward compatibility and is ignored by the compiler.)

On the Win32 platform, an index specifier consists of the directive index followed by a numeric constant between 1 and 2,147,483,647.

(For more efficient programs, use low index values.)

If an entry has no index specifier, the routine is automatically assigned a number in the export table.

Note: Use of index specifiers, which are supported for backward compatibility only,
is discouraged and may cause problems for other development tools.

name specifier consists of the directive name followed by a string constant.

If an entry has no name specifier, the routine is exported under its original declared name,
with the same spelling and case. Use a name clause when you want to export a routine under a different name.
For example:

exports
DoSomethingABC name 'DoSomething';

When you export an overloaded function or procedure from a dynamically loadable library,
you must specify its parameter list in the exports clause.

For example:

exports
Divide(X, Y: Integer) name 'Divide_Ints',
Divide(X, Y: Real) name 'Divide_Reals';

 

On Win32, do not include index specifiers in entries for overloaded routines.

An exports clause can appear anywhere and any number of times in the declaration part of a program or library,

or in the interface or implementation section of a unit.

Programs seldom contain an exports clause.

Library Initialization Code

The statements in a library's block constitute the library's initialization code.

These statements are executed once every time the library is loaded.

They typically perform tasks like registering window classes and initializing variables.

Library initialization code can also install an entry point procedure using the DllProc variable.

The DllProc variable is similar to an exit procedure, which is described in Exit procedures;

the entry point procedure executes when the library is loaded or unloaded.

Library initialization code can signal an error by setting the ExitCode variable to a nonzero value.

ExitCode is declared in the System unit and defaults to zero, indicating successful initialization.

If a library's initialization code sets ExitCode to another value,

the library is unloaded and the calling application is notified of the failure.

Similarly, if an unhandled exception occurs during execution of the initialization code,

the calling application is notified of a failure to load the library.

Here is an example of a library with initialization code and an entry point procedure:

library Test;
var
  SaveDllProc: Pointer;
procedure LibExit(Reason: Integer); begin if Reason = DLL_PROCESS_DETACH then begin . . // library exit code . end; SaveDllProc(Reason); // call saved entry point procedure end;
begin . . // library initialization code . SaveDllProc := DllProc; // save exit procedure chain DllProc := @LibExit; // install LibExit exit procedure end.

 

 

 

DllProc is called when the library is first loaded into memory,

when a thread starts or stops,

or when the library is unloaded.

The initialization parts of all units used by a library are executed before the library's initialization code,

and the finalization parts of those units are executed after the library's entry point procedure.

 

Global Variables in a Library

 

Global variables declared in a shared library cannot be imported by a Delphi application.

 

A library can be used by several applications at once,

but each application has a copy of the library in its own process space with its own set of global variables.

For multiple libraries - or multiple instances of a library - to share memory,

they must use memory-mapped files.

Refer to the your system documentation for further information.

 

Libraries and System Variables

 

Several variables declared in the System unit are of special interest to those programming libraries.

Use IsLibrary to determine whether code is executing in an application or in a library;

IsLibrary is always False in an application and True in a library.

During a library's lifetime, HInstance contains its instance handle. 

CmdLine is always nil in a library.

 

The DLLProc variable allows a library to monitor calls that the operating system makes to the library entry point.

This feature is normally used only by libraries that support multithreading.

DLLProc is used in multithreading applications.

You should use finalization sections, rather than exit procedures, for all exit behavior.

 

To monitor operating-system calls, create a callback procedure that takes a single integer parameter, for example:

procedure DLLHandler(Reason: Integer);

 

and assign the address of the procedure to the DLLProc variable.

When the procedure is called, it passes to it one of the following values.

DLL_PROCESS_DETACH

Indicates that the library is detaching from the address space of the calling process as a result of a clean exit or a call to FreeLibrary.

DLL_PROCESS_ATTACH

Indicates that the library is attaching to the address space of the calling process as the result of a call to LoadLibrary.

DLL_THREAD_ATTACH

Indicates that the current process is creating a new thread.

DLL_THREAD_DETACH

Indicates that a thread is exiting cleanly.


In the body of the procedure, you can specify actions to take depending on which parameter is passed to the procedure.

Exceptions and Runtime Errors in Libraries

When an exception is raised but not handled in a dynamically loadable library,

it propagates out of the library to the caller.

If the calling application or library is itself written in Delphi,

the exception can be handled through a normal try...except statement.

On Win32, if the calling application or library is written in another language,

the exception can be handled as an operating-system exception with the exception code $0EEDFADE.

The first entry in the ExceptionInformation array of the operating-system exception record

contains the exception address, and the second entry contains a reference to the Delphi exception object.

Generally, you should not let exceptions escape from your library.

Delphi exceptions map to the OS exception model.

If a library does not use the SysUtils unit, exception support is disabled.

In this case, when a runtime error occurs in the library, the calling application terminates.

Because the library has no way of knowing whether it was called from a Delphi program,

it cannot invoke the application's exit procedures;

the application is simply aborted and removed from memory.

Shared-Memory Manager

On Win32, if a DLL exports routines that pass long strings or dynamic arrays as parameters or function results

(whether directly or nested in records or objects), then the DLL and its client applications (or DLLs) must all use the ShareMem unit.

The same is true if one application or DLL allocates memory with New or GetMem which

is deallocated by a call to Dispose or FreeMem in another module. 

ShareMem should always be the first unit listed in any program or library uses clause where it occurs.

ShareMem is the interface unit for the BORLANDMM.DLL memory manager,

which allows modules to share dynamically allocated memory. 

BORLANDMM.DLL must be deployed with applications and DLLs that use ShareMem.

When an application or DLL uses ShareMem,

its memory manager is replaced by the memory manager in BORLANDMM.DLL.

 

Static vs. Dynamic Dynamic Link Library Loading - A Comparison

DLL or a dynamic link library acts as a shared library of function, that can be called by applications and by other DLLs.

Using Delphi, you can create and use our own DLLs, you can call functions in DLLs developed with other programming languages / by other developers.

If you are new to working with DLLs, make sure you read Introduction to DLLs.

Static or Dynamic Loading?

When you want to call a function exported by a DLL, one question comes up: should you use static or dynamic DLL loading? .

Before you can call routines defined in DLL, you must import them. Functions exported from a DLL can be imported in two ways:

by declaring an external procedure or function (static),

or by direct calls to DLL specific API functions (dynamic).

Let's create a simple DLL. Here's the code to the "circle.dll"

exporting one function "CircleArea" which calculates the area of a circle using the given radius:

library circle;  

uses SysUtils, Classes, Math;

{$R *.res}

function CircleArea(const radius : double) : double; stdcall;
begin
result := radius * radius * PI;
end;

exports CircleArea;

begin
end.

 

Note: if you need help with creating a DLL using Delphi, read the How to create (and use) a DLL in Delphi .

Once you have the circle.dll you can use the exported "CircleArea" function from your application.

Static Loading

The simplest way to import a procedure or function is to declare it using the external directive:

function CircleArea(const radius : double) : double; external 'circle.dll';

 

 If you include this declaration in the interface part of a unit,

circle.dll is loaded once, when the program starts.

Throughout execution of the program, the function CircleArea is available

to all units that use the unit where the above declaration is.

Dynamic Loading

You can access routines in a library through direct calls to Win32 APIs,

including LoadLibrary , FreeLibrary , andGetProcAddress .

These functions are declared in Windows.pas.

Here's how to call the CircleArea function using dynamic loading:

type   
  TCircleAreaFunc = function (const radius: double) : double; stdcall; 
var   
  dllHandle : cardinal;   
  circleAreaFunc : TCircleAreaFunc; 
begin   
  dllHandle := LoadLibrary('circle.dll') ;   
  if dllHandle <> 0 then   
  begin     
    @circleAreaFunc := GetProcAddress(dllHandle, 'CircleArea') ;     
    if Assigned (circleAreaFunc) then       
       circleAreaFunc(15) //call the function     
    else       
       ShowMessage('"CircleArea" function not found') ;     
    FreeLibrary(dllHandle) ;   
  end   else   begin     
    ShowMessage('circle.dll not found / not loaded') ;   
  end; 
end;

  

When you import using dynamic loading, the DLL is not loaded until the call to LoadLibrary.

The library is unloaded by the call to FreeLibrary.

With static loading the DLL will be loaded and its initialization sections will execute

before the calling application's initialization sections are executed.

With dynamic loading, this is reversed.

Static or Dynamic

Let's now compare static and dynamic DLL loading to see what are advantages and disadvantages of both.

Static loading PROS:

  • More easy for a beginner developer, no "ugly" API calls.
  • DLLs loaded once, when the program starts.

Static loading CONS:

  • The application will NOT start if any DLLs are missing (cannot be found).
    When you run the program you will see an ugly message: 
    "This application has failed to start because 'missing.dll' was not found. Re-installingn the application may fix this problem". 
    By design the DLL search order with static linking includes:
    the directory from which the application loaded,
    the system directory,
    the Windows directory,
    directories listed in the PATH environment variable. 

    Note also that the search order might be different for various Windows versions. 
    The safest is to always expect to have all the DLLs in the directory where the calling application is.

  • More memory used, as all DLLs are loaded even if you will not use some of the functions.

Dynamic loading PROS:

  • You can run your program even when some of the libraries it uses are not present.
  • Smaller memory consumption - DLLs used when needed.
  • You can specify the full path to the DLL.
  • Use for functionality that is rarely needed by the application.
  • Could be used for modular applications. The application only exposes (loads) modules (dlls) "approved" for the user.
  • The ability to load and unload library dynamically,
    is the foundation of a plug-in system that allow a developer to add extra functionality to programs.
  • Backwards compatibility with older Windows versions,
    in which system dlls may not support the same functions or in the same way.
    Detecting the Windows version first, then dynamic linking based on what your app is running on,
    allows you to support more versions of Windows and provide work arounds for older OSs,
    or at the very least gracefully disabling features you can't support.

Dynamic loading CONS:

  • Requires more code, not trivial for a beginner developer.

I hope differences are clear and that you will know what type of DLL loading to use for your next project ;)

If you think some PROS or CONS are missing, feel free to let me know - I'll add it to the list.

 

Libraries and Packages (Delphi) 

A dynamically loadable library is a dynamic-link library (DLL) on Windows, or a DYLIB on Mac.

It is a collection of routines that can be called by applications and by other DLLs or shared objects.

Like units, dynamically loadable libraries contain sharable code or resources.

But this type of library is a separately compiled executable that is linked, at run time, to the programs that use it.

Delphi programs can call DLLs and assemblies written in other languages,

and applications written in other languages can call DLLs or assemblies written in Delphi.

Calling Dynamically Loadable Libraries

You can call operating system routines directly, but they are not linked to your application until run time.

This means that the library need not be present when you compile your program.

Also, there is no compile-time validation of attempts to import a routine.

Before you can call routines defined in DLL or assembly, you must import them.

This can be done in two ways:

by declaring an external procedure or function, or by direct calls to the operating system.

Whichever method you use, the routines are not linked to your application until run time.

Delphi does not support importing variables from DLLs or assemblies.

Static Loading

The simplest way to import a procedure or function is to declare it using the external directive.

For example:

procedure DoSomething; external 'MYLIB.DLL';

 

 If you include this declaration in a program, MYLIB.DLL is loaded once, when the program starts.

Throughout the execution of the program, the identifier DoSomething always refers to the same entry point in the same shared library.

Declarations of imported routines can be placed directly in the program or unit where they are called.

To simplify maintenance, however, you can collect external declarations into a separate "import unit"

that also contains any constants and types required for interfacing with the library.

Other modules that use the import unit can call any routines declared in it.

Dynamic Loading (Windows-only)

You can access routines in a library through direct calls to Windows APIs,

including LoadLibrary, FreeLibrary, and GetProcAddress.

These functions are declared in Windows.pas.

In this case, use procedural-type variables to reference the imported routines.

For example:

uses Windows, ...;
 
 type
   TTimeRec = record
     Second: Integer;
     Minute: Integer;
     Hour: Integer;
   end;
 
   TGetTime = procedure(var Time: TTimeRec);
   THandle = Integer;
 
   var
     Time: TTimeRec;
     Handle: THandle;
     GetTime: TGetTime;
     .
     .
     .
   begin
     Handle := LoadLibrary('libraryname');
     if Handle <> 0 then
     begin
      @GetTime := GetProcAddress(Handle, 'GetTime');
      if @GetTime <> nil then
       begin
          GetTime(Time);
             with Time do
                Writeln('The time is ', Hour, ':', Minute, ':', Second);
          end;
          FreeLibrary(Handle);
        end;
      end;

When you import routines this way, the library is not loaded

until the code containing the call to LoadLibrary executes.

The library is later unloaded by the call to FreeLibrary.

This allows you to conserve memory and to run your program

even when some of the libraries it uses are not present.  

Delayed Loading

The delayed directive can be used to decorate an external routine to delay the loading of the library containing the routine.

The actual loading happens when the routine is called for the first time.

The following example demonstrates the use of the delayed directive:

function GetSomething: Integer; external 'somelibrary.dll' delayed;

 

In the example above, the GetSomething routine is imported from the somelibrary.dll library.

The delayed directive ensures thatsomelibrary.dll is not statically linked to the application, but rather dynamically.

The delayed directive is useful in the case where the imported routines do not exist on the target operating system on which the application is run.

Statically imported routines require that the operating system find and load the library when the application is started.

If the routine is not found in the loaded library, or the library does not exist, the Operating System halts the execution of the application.

Using the delayed directive enables you to check, at run time, whether the Operating System supports the required APIs;

only then you can call the imported routines.

Another potential use for the delayed directive is related to the memory footprint of the application:

decorating the less probably to be used routines, as delayed may decrease the memory footprint of the application,

because the libraries are loaded only when required.

The abusive use of delayed can damage the speed performance of the program (as perceived by the end user).

Note: 

Trying to call a delayed routine that cannot be resolved results in a run-time error (or an exception, if the SysUtils unit is loaded).

In order to fine-tune the delay-loading process used by the Delphi Run-time Library,

you can register hook procedures to oversee and change its behavior.

To accomplish this, use SetDliNotifyHook2 and SetDliFailureHook2, declared in the SysInit unit.

Also see the code example at Delayed Loading (Delphi).

This example demonstrates the fine tuning of the delay loading mechanism.

Using the provided functionality, you can hook-up various steps in the delay loading process.

This example defines three cases, one of which is correct, and two incorrect. 

Note: 

At the XE2 release, the delayed loading mechanism for Delphi was

refactored and moved From the System unit into the SysInit unit.

For example, System.dliNotification became SysInit.dliNotification,

and System.DliNotifyHook became SysInit.DliNotifyHook2.

This code example has not yet been revised to use the new delayed loading.

program TestDelayLoad;
 
{$APPTYPE CONSOLE}
 
uses
  Winapi.Windows,
  System.SysUtils;
 
function GetDesktopWindow: HWND; stdcall; external user32 name 'GetDesktopWindow' delayed;
function GetFooBar: Integer; stdcall; external kernel32 name 'GetFooBar' delayed;
function GetFooBarBar: Integer; stdcall; external 'kernel33' name 'GetFooBarBar' delayed;
 
var
  LOldNotifyHook, LOldFailureHook: TDelayedLoadHook; { for storing the old hook pointers }
 
{ Utility function to retrieve the name of the imported routine or its ordinal }
function ImportName(const AProc: TDelayLoadProc): String; inline;
begin
  if AProc.fImportByName then
    Result := AProc.szProcName
  else
    Result := '#' + IntToStr(AProc.dwOrdinal);
end;
 
function MyDelayedLoadHook(dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
begin
  { Write a message for each dli notification }
  case dliNotify of
    dliNoteStartProcessing:
      WriteLn('Started the delayed load session for "', pdli.szDll, '" DLL');
    dliNotePreLoadLibrary:
      WriteLn('Starting to load "', pdli.szDll, '" DLL');
    dliNotePreGetProcAddress:
      WriteLn('Want to get address of "', ImportName(pdli.dlp), '" in "', pdli.szDll, '" DLL');
    dliNoteEndProcessing:
      WriteLn('Ended the delaay load session for "', pdli.szDll, '" DLL');
    dliFailLoadLibrary:
      WriteLn('Failed to load "', pdli.szDll, '" DLL');
    dliFailGetProcAddress:
      WriteLn('Failed to get proc address for "', ImportName(pdli.dlp), '" in " 
                       
                    
                    

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Delphi悬浮窗口、浮动窗口的实现发布时间:2022-07-18
下一篇:
Delphi方法发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap