Delphi XE2 64-bit DLLs
Delphi XE2 can produce 64-bit Windows applications and DLLs.
In the 64-bit Windows world, DLLs have only a single calling convention, and we do not have to specify that in Delphi.
However, if we do specify a calling convention, it will be ignored by the 64-bit compiler (and used by the 32-bit compiled in case we compile for a 32-bit target), so it's still advised to use the calling conventions for backwards compatibility with the 32-bit world.
An example of a library (with calling convention specified) is as follows:
library MyMax;
uses
SysUtils, Classes;
function Max(X: array of Integer): Integer; stdcall; export;
var
NextX: Integer;
begin
Result := 0;
if Length(X) > 0 then
begin
Result := X[0];
for NextX in X do
if NextX > Result then Result := NextX
end
end;
exports
Max;
begin
end.
The implicit import of this 64-bit DLL can be as follows:
function Max(X: array of Integer): Integer; stdcall;
external 'MyMax.dll';
And the call is as follows:
a := Max([2,10,42]);
Note that not all development environments will be able to call the function with the array of integers as argument type.
Another example of a DLL for both 32-bit and 64-bit is as follows:
library eBob42;
function Add(X,Y: Integer): Integer; overload; stdcall;
begin
Result := X + Y
end;
function Add(X,Y: Double): Double; overload; stdcall;
begin
Result := X + Y
end;
exports
Add(X,Y: Integer) name 'Add',
Add(X,Y: Double) name 'AddDouble';
end.
This example was taken from the Delphi XE Development Essentials (the free bonus PDF for developers who purchased my courseware manuals).
As explained in the XE courseware manual, apart from implicit loading the DLL, we can also write some more code and do an explicit load.
The advantage of an explicit load is that the application will continue to run even if the DLL is not available (which in note the case with an implicit import: in that situation, the application will not start if the implicitly imported DLL cannot be found or loaded).
However, a third alternative exists: delay loading of the DLL, which results in less explicit work than the explicit loading option, but more flexibility than the implicit loading option.
The best of both worlds: the application will still load and run (even if the DLL is not present), and you do not have to write explicit LoadLibrary and GetProcAddress functions for each routine exposed from the DLL.
See the Delphi XE Development Essentials for more information on these alternatives.
However, in Delphi XE2, there is a slight change in the delay loading code...
XE2 Delay Loading DLLs
Delphi 2010 introduced the delayed keyword (no syntax highlighting by the way), and I wrote about a feature to hook into the delay failure notifier using the SetDliFailureHook in Delphi 2010, which still works in Delphi XE.
For Delphi XE2, the SetDliFailureHook is gone, and replaced by SetDliFailureHook2. As a result my DelayedHandler unit, for responding to errors when trying to load a DLL or trying to call a method from the DLL, is now implemented as follows:
unit DelayedHandler;
interface
uses
SysUtils;
type
ELoadLibrary = class(Exception);
EGetProcAddress = class(Exception);
implementation
function DelayedHandlerHook(dliNotify: dliNotification;
pdli: PDelayLoadInfo): Pointer; stdcall;
begin
Result := nil;
if dliNotify = dliFailLoadLibrary then
raise ELoadLibrary.Create('Could not load ' + pdli.szDll)
else
if dliNotify = dliFailGetProcAddress then
begin
if pdli.dlp.fImportByName then
raise EGetProcAddress.Create('Could not load ' +
pdli.dlp.szProcName + ' from ' + pdli.szDll)
else
raise EGetProcAddress.Create('Could not load index ' +
IntToStr(pdli.dlp.dwOrdinal) + ' from ' + pdli.szDll)
end
end;
initialization
SetDliFailureHook(DelayedHandlerHook);
SetDliFailureHook2(DelayedHandlerHook);
finalization
SetDliFailureHook(nil);
SetDliFailureHook2(nil);
end.
Feel free to add VER210 support for Delphi 2010 if you still use that version of Delphi.
Note that we may have to modify this code when Delphi XE3 is released (but that will be covered in my Delphi XE3 Development Essentials courseware manual, of course).
The actual import unit for the eBob42 DLL still remains the same (and the delayed keyword still shows no syntax highlighting, unfortunately):
unit eBob42Delayed;
interface
const
DLL = 'eBob42.DLL';
function Add(X,Y: Integer): Integer; overload; stdcall
external DLL delayed;
function Add(X,Y: Double): Double; overload; stdcall
external DLL name 'AddDouble' delayed;
implementation
end.
Summary
In this article, I've shown how to modify the DelayedHandler unit to add user-friendly error message support for delay loading DLLs with Delphi XE2.
The information in this article is also included in my Delphi XE2 Development Essentials courseware manual, included for free for all developers who purchase their Delphi XE2 (or subscription) from me.