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 DLL
The 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

    // Code placed here executes the first time 
    // the DLL is called by any exe.
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);
    case Reason of
        MessageBox(DLLHandle, 'Process Attach', 'Info', mb_Ok);
        MessageBox(DLLHandle, 'Thread Attach', 'Info', mb_Ok);
        MessageBox(DLLHandle, 'Thread Detach', 'Info', mb_Ok);
        MessageBox(DLLHandle, 'Process Detach', 'Info', mb_Ok);
    end;                                          // case

  // Exported functions implemented here
  // exports clause here

  begin                                           // initialization code
    if DllProc = nil then begin
      DllProc := @DLLEntryPoint;
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:
  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.

Written by: Jim Karabatsos
Feb 1996