Delphi DLL制作和加载 Static, Dynamic, Delayed 以及 Shared-Memory Manager
2020-12-13 14:02
标签:des style blog http io color os ar 使用 一 Dll的制作一般分为以下几步: ptr^:=LongInt(mainForm);//用主调程序的mainForm替换DLL的MainForm。MainForm是特殊的WINDOW,它专门管理Application中的Forms资源. //为什么不直接Application.MainForm := mainForm,因为Application.MainForm是只读属性 Form1:=TForm1.Create(mainForm);//用参数建立 调用方源代码: Introduction 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. 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. 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 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. 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 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. 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. 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; ]. Finally, the memory allocated for the dll has to be explicitly released using the FreeLibrary function. 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 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: 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: 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. 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. A 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, When you export an overloaded function or procedure from a dynamically loadable library, For example: 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. 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: 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 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. 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: 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. 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. 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. A 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. 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: 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. The simplest way to import a procedure or function is to declare it using the external directive: 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. 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: 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. Let‘s now compare static and dynamic DLL loading to see what are advantages and disadvantages of both. Static loading PROS: Static loading CONS: Dynamic loading PROS: Dynamic loading CONS: 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. 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. 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. The simplest way to import a procedure or function is to declare it using the external directive. For example: 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. 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: 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. 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: 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. 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. The following table lists the cases in which the registered hook is called by the delay load helper. dliNoteStartProcessing Sent to a delayed-load notification hook when a delayed-load session is starting. Called before the library containing the delay loaded external procedure is processed. Used to bypass or notify helper only. dliNotePreLoadLibrary Sent before LoadLibrary is called, allowing a new HMODULE to be returned. Called before the library containing the delay loaded external procedure is loaded. Can override with the new HMODULE return value. dliNotePreGetProcAddress Sent before GetProcAddress, allowing for a new procedure address to be returned if desired. Called before the address of the delay loaded procedure is found. Can override with new HMODULE return value. dliNoteEndProcessing Sent to a delayed-load notification hook when all delayed-load processing completes. Cannot be bypassed except for raise or RaiseException. dliFailLoadLibrary Sent to a delayed-load failure hook when LoadLibrary fails; allows you to specify a different valid HMODULE handle. dliFailGetProcAddress Sent to a delay-load failure hook when GetProcAddress fails; allows you to replace the procedure address with the address of a valid procedure.
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句柄保存起来,也无须释放,只不过是替换一下
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
DLL means Dynamic Link Libraries.
How to create a dll using Delphi
It‘s not so hard to create a dll as you heard. library DLLProject;
uses
SysUtils,
Classes;
{$R *.RES}
begin
end.
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;
Dll loading
Now we can see how these dll [exported] functions can be called from other applications. var
procedure MainFunc ():Integer; external ‘DLLProject.dll‘;
Implementation.
end;
Now we‘ll see another kind of dll loading named Dynamic loading.
The dll should be loaded using the command LoadLibrary which returns the handle to the dll once it‘s loaded to the memory.
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;
Note : Writing Dynamically Loaded Libraries
Using Export Clause in Libraries
library MinMax;
function Min(X, Y: Integer): Integer; stdcall;
begin
if X 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.
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.
A routine is exported when it is listed in an exports clause, which has the form:exports entry1, ..., entryn;
Note: Use of index specifiers, which are supported for backward compatibility only,
is discouraged and may cause problems for other development tools.
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‘;
you must specify its parameter list in the exports clause. exports
Divide(X, Y: Integer) name ‘Divide_Ints‘,
Divide(X, Y: Real) name ‘Divide_Reals‘;
Library Initialization Code
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.Global Variables in a Library
Libraries and System Variables
procedure DLLHandler(Reason: Integer);
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
Static vs. Dynamic Dynamic Link Library Loading - A Comparison
Static or Dynamic Loading?
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.Static Loading
function CircleArea(const radius : double) : double; external ‘circle.dll‘;
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;
Static or Dynamic
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.
is the foundation of a plug-in system that allow a developer to add extra functionality to programs.
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.
Libraries and Packages (Delphi)
Calling Dynamically Loadable Libraries
Static Loading
procedure DoSomething; external ‘MYLIB.DLL‘;
Dynamic Loading (Windows-only)
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;
Delayed Loading
function GetSomething: Integer; external ‘somelibrary.dll‘ delayed;
Also see the code example at Delayed Loading (Delphi).
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 "‘, pdli.szDll, ‘" DLL‘);
end;
{ Call the old hooks if they are not nil }
{ This is recommended to do in case the old hook do further processing }
if dliNotify in [dliFailLoadLibrary, dliFailGetProcAddress] then
begin
if Assigned(LOldNotifyHook) then
LOldFailureHook(dliNotify, pdli);
end else
begin
if Assigned(LOldNotifyHook) then
LOldNotifyHook(dliNotify, pdli);
end;
Result := nil;
end;
begin
{ Install new delayed loading hooks }
LOldNotifyHook := SetDliNotifyHook2(MyDelayedLoadHook);
LOldFailureHook := SetDliFailureHook2(MyDelayedLoadHook);
{ Calling an existing delayed external routine }
GetDesktopWindow;
try
{ Calling an unexisting delayed external routine in an existing library }
GetFooBar;
except
end;
try
{ Calling an unexisting delayed external routine in an unexisting library }
GetFooBarBar;
except
end;
{ Reset the hooks }
SetDliNotifyHook2(LOldNotifyHook);
SetDliFailureHook2(LOldFailureHook);
Readln;
end.
SysInit.dliNotification
Value of dliNotifyparameter
Description
上一篇:Java中的反射该如何使用?
下一篇:kmp算法
文章标题:Delphi DLL制作和加载 Static, Dynamic, Delayed 以及 Shared-Memory Manager
文章链接:http://soscw.com/essay/33651.html