Creating Win32 DLLs with Delphi32
by Jim Karabatsos - GUI Computing
This technical tip is adapted from information published by Borland regarding Delphi32, which should be released by the time you read this. As a true 32-bit development environment, Delphi32 can be used to create all manner of 32-bit programs, including DLLs.
Under Win32, the system entry points to DLLs have changed. If you have ever struggled with the intricacies of programming a WEP function (and in particular coping with all the things you cannot do there) then you will be particularly happy about the changes. Instead of a LibMain and WEP function, 32-bit DLLs need to export a single function called DllEntryPoint, which is called under four conditions -- whenever an executable attaches to or detaches form the DLL and whenever a Thread attaches to or detaches from a DLL. To allow the DLL to respond accordingly, a parameter is passed to the DllEntryPoint to indicate why the function has been called. The values (defined in WINDOWS.PAS) are:
DLL_PROCESS_ATTACH = 1; // Executable attaches to DLL DLL_THREAD_ATTACH = 2; // Thread in exe calls DLL DLL_THREAD_DETACH = 3; // Thread leaves DLL DLL_PROCESS_DETACH = 0; // Exe detaches from DLLThe DllEntryPoint function does not have to be declared in your Delphi DLLs. In fact, many, if not most, Delphi DLLs will work fine without you explicitly declaring a DllEntryPoint. However, you will need to use this function if you want the functionality associated with it to be part of your DLL. It is of particular interest to people who want to safely call into the same DLL from multiple threads in a single program.
When a Delphi DLL gets called the first time from an executable, the initialization section at the bottom of the program gets called. If you load two executables, and each uses the DLL, then the initialization section will get called twice, once for each executable. Here's a minimal Delphi DLL, which will compile as is, but which does nothing of significance:
library MyDll;
// Code here
// exports
begin
// Code placed here executes the first time
// the DLL is called by any exe.
end.
As you can see, there is no traditional DLLEntryPoint here that
corresponds to the DLLEntryPoint found in a standard C/C++ DLL.
Remember that the DLLEntryPoint takes over from the LibMain function
and WEP which appeared in Win16. LibMain and WEP are now obsolete,
and you should use DLLEntryPoint instead.
Also note the new in-line commenting syntax of Delphi32. Anything on a line after a double slash is considered to be a comment.
To set up a DLLEntryPoint in Delphi, use the following skeletal code, which takes advantage of the DLLProc variable declared globally in SYSTEM.PAS as well as the various constants defined in WINDOWS.PAS:
library DllEntry;
procedure DLLEntryPoint(Reason: DWORD);
begin
case Reason of
Dll_Process_Attach:
MessageBox(DLLHandle, 'Process Attach', 'Info', mb_Ok);
Dll_Thread_Attach:
MessageBox(DLLHandle, 'Thread Attach', 'Info', mb_Ok);
Dll_Thread_Detach:
MessageBox(DLLHandle, 'Thread Detach', 'Info', mb_Ok);
Dll_Process_Detach:
MessageBox(DLLHandle, 'Process Detach', 'Info', mb_Ok);
end; // case
end;
// Exported functions implemented here
// exports clause here
begin // initialization code
if DllProc = nil then begin
DllProc := @DLLEntryPoint;
DllEntryPoint(Dll_Process_Attach);
end;
end.
This code assigns the user declared procedure called DLLEntryPoint
(the name is not important here) to the Delphi declared global
variable called DllProc, which is listed as follows in SYSTEM.PAS:
var
...
DllProc: Pointer; { Called whenever DLL entry point is called }
The standard DLLEntryPoint's functionality is simulated by then
calling the locally declared DLLEntryPoint and passing it
Dll_Process_Attach as a variable. In a C/C++ DLL, this variable would
be passed to a user defined function called DllEntryPoint
automatically when the DLL was first accessed by an executable. In
Delphi, the first call to this function is performed manually by the
initialization code, but subsequent calls will occur automatically, so
long as you have first assigned the function to the DllProc
variable. In other words, you have to force the first call to
DllEntryPoint, as shown above, but subsequent calls will be posted
automatically by the system.