You have already used existing DLLs in examples in this book, when calling Windows API functions. As you might remember, all the API functions are declared in the system Windows unit. Functions are declared in the interface portion of the unit, as shown here:
function PlayMetaFile(DC: HDC; MF: HMETAFILE): BOOL; stdcall; function PaintRgn(DC: HDC; RGN: HRGN): BOOL; stdcall; function PolyPolygon(DC: HDC; var Points; var nPoints; p4: Integer): BOOL; stdcall; function PtInRegion(RGN: HRGN; p2, p3: Integer): BOOL; stdcall;
Then, in the implementation portion, instead of providing each function's code, the unit refers to the external definition in a DLL:
const gdi32 = 'gdi32.dll'; function PlayMetaFile; external gdi32 name 'PlayMetaFile'; function PaintRgn; external gdi32 name 'PaintRgn'; function PolyPolygon; external gdi32 name 'PolyPolygon'; function PtInRegion; external gdi32 name 'PtInRegion';
The external definition of these functions refers to the name of the DLL they use. The name of the DLL must include the .DLL extension, or the program will not work under Windows NT/2000/XP (although it will work under Windows 9x). The other element is the name of the DLL function. The name directive is not necessary if the Delphi function (or procedure) name matches the DLL function name (which is case sensitive).
To call a function that resides in a DLL, you can provide its declaration in the interface section of a unit and external definition in the implementation section, as shown earlier, or you can merge the two in a single declaration in the implementation section of a unit. Once the function is properly defined, you can call it in your Delphi application code just like any other function.
As an example, I've written a DLL in C++ with some trivial functions, just to show you how to call DLLs from a Delphi application. I won't explain the C++ code in detail (it's basically C code) but will focus instead on the calls between the Delphi application and the C++ DLL. In Delphi programming, it is common to use DLLs written in C or C++.
Suppose you are given a DLL built in C or C++. You'll generally have in your hands a .DLL file (the compiled library), an .H file (the declaration of the functions inside the library), and a .LIB file (another version of the list of exported functions for the C/C++ linker). This LIB file is useless in Delphi; the DLL file is used as-is, and the H file must be translated into a Delphi unit with the corresponding declarations.
In the following listing, you can see the declaration of the C++ functions I've used to build the CppDll library example. The complete source code and the compiled version of the C++ DLL and the source code of the Delphi application using it are in the CppDll directory. You should be able to compile this code with any C++ compiler; I've tested it only with Borland C++Builder. Here are the C++ declarations of the functions:
extern "C" __declspec(dllexport) int WINAPI Double (int n); extern "C" __declspec(dllexport) int WINAPI Triple (int n); __declspec(dllexport) int WINAPI Add (int a, int b);
The three functions perform some basic calculations on the parameters and return the result. Notice that all the functions are defined with the WINAPI modifier, which sets the proper parameter-calling convention; they are preceded by the __declspec(dllexport) declaration, which makes the functions available to the outside world.
Two of these C++ functions also use the C naming convention (indicated by the extern "C" statement), but the third one, Add, doesn't. This difference affects the way you call these functions in Delphi. The internal names of the first two functions correspond to their names in the C++ source code file. But because I didn't use the extern "C" clause for the Add function, the C++ compiler uses name mangling. This technique is used to include information about the number and type of parameters in the function name, which the C++ language requires in order to implement function overloading. The result when using the Borland C++ compiler is a funny function name: @Add$qqsii. You must use this name in the Delphi code to call the Add DLL function (which explains why you'll generally avoid C++ name mangling in exported functions and declare them all as extern "C"). The following are the declarations of the three functions in the Delphi CallCpp example:
function Add (A, B: Integer): Integer; stdcall; external 'CPPDLL.DLL' name '@Add$qqsii'; function Double (N: Integer): Integer; stdcall; external 'CPPDLL.DLL' name 'Double'; function Triple (N: Integer): Integer; stdcall; external 'CPPDLL.DLL';
As you can see, you can either provide or omit an alias for an external function. I've provided one for the first function (there was no alternative, because the exported DLL function name @Add$qqsii is not a valid Delphi identifier) and for the second, although in the second case it was unnecessary. If the two names match, you can omit the name directive, as I did for the third function. If you are not sure of the actual names of the functions exported by the DLL, you can use Borland's TDump command-line program, available in the Delphi BIN folder, using the -ee command-line switch.
Remember to add the stdcall directive to each definition, so that the caller module (the application) and the module being called (the DLL) use the same parameter-passing convention. If you fail to do so, you will get unpredictable values passed as parameters, a bug that is very hard to trace.
To use this C++ DLL, I've built a Delphi example named CallCpp. Its form has only the buttons used to call the functions of the DLL and some visual components for input and output parameters (see Figure 10.1). Notice that to run this application, you should have the DLL in the same directory as the project, in one of the directories on the path, or in the Windows main folder (\Windows, \WinNT…) or the Windows' system folder (\Windows\System, \WinNT\System32…). If you move the executable file to a new directory and try to run it, you'll get a run-time error indicating that the DLL is missing:
|Copyright © 2004-2021 "Delphi Sources" by BrokenByte Software. Delphi Programming Guide||