[fpc-devel] Missing DLLProc

Pavel V. Ozerski pavel at insect.mail.iephb.ru
Fri Jan 13 11:23:06 CET 2006


Hello all,

in freepascal.ru forum a problem has been discussed. FPC 2.1 does not
understand DllProc predefined variable presenting in Delphi RTL:

> Unit
>
> System
>
> Category
>
> miscellaneous routines
>
> var DLLProc: Pointer;
>
> Description
>
> DLLProc is used to specify a procedure that is invoked every time a DLL's entry point is called. A procedure assigned to DLLProc must take one parameter of type Integerint. For example,
>
> procedure LibraryProc(Reason: Integer);
>
> When the procedure is invoked, this single parameter contains a value between 0 and 3 as defined by the following group of constants in the Windows unit:
>
> const
>
>   DLL_PROCESS_DETACH = 0;
>   DLL_PROCESS_ATTACH = 1;
>   DLL_THREAD_ATTACH  = 2;
>   DLL_THREAD_DETACH  = 3;
>
> For further details on the meaning of these constants, refer to the description of the DllEntryPoint function in the Win32 API online help.
>
> Note:      DLL_PROCESS_ATTACH is passed to the procedure only if the DLL’s initialization code calls the procedure and specifies DLL_PROCESS_ATTACH as a parameter.

I think, for some platforms this problem could be easily solved. Note:
although in Delphi Help this variable is described as a pointer,
actually it is declared in 7.0 RTL as
> type
>   TDLLProc = procedure (Reason: Integer);
>   // TDLLProcEx provides the reserved param returned by WinNT
>   TDLLProcEx = procedure (Reason: Integer; Reserved: Integer);
...
>   DllProc: TDLLProc;            { Called whenever DLL entry point is called }
>   { DllProcEx passes the Reserved param provided by WinNT on DLL load & exit }
>   DllProcEx: TDLLProcEx absolute DllProc;

I think, these declarations could be easily added into systemh.inc. To
avoid Borland copyright, they could be declared a bit else :) (and
there extst also some reasons for multi-platform RTL where may be
different default calling conventions etc):

type
  TDLLProc = procedure (Reason: integer);
  TDLLProcEx = procedure (Reason, Reserved: integer);
var
  DllProc_Ptr: pointer = nil;
  DllProc: TDLLProc absolute DllProc_Ptr;

  DllProcEx_Ptr: pointer = nil;
  DllProcEx: TDLLProcEx absolute DllProcEx_Ptr;

The next step should be a modification of Dll_entry function in
system.pp.

for win32, win64 and winCe:

function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
var
  res : longbool;
  procedure CallDllProc;
  begin
    if Assigned(DllProcEx_Ptr) then
      DllProcEx(DLLreason, DLLparam);
    if Assigned(DllProc_Ptr) then
      DllProc(DLLreason);
  end;
  begin
     IsLibrary:=true;
     Dll_entry:=false;
     case DLLreason of
       DLL_PROCESS_ATTACH :
         begin
           If SetJmp(DLLBuf) = 0 then
             begin
               if assigned(Dll_Process_Attach_Hook) then
                 begin
                   res:=Dll_Process_Attach_Hook(DllParam);
                   if not res then
                     exit(false);
                 end;
               PASCALMAIN;
               Dll_entry:=true;
             end
           else
             Dll_entry:=DLLExitOK;
         end;
       DLL_THREAD_ATTACH :
         begin
           inc(Thread_count);
{$warning Allocate Threadvars !}
           if assigned(Dll_Thread_Attach_Hook) then
             Dll_Thread_Attach_Hook(DllParam);
           CallDllProc;
           Dll_entry:=true; { return value is ignored }
         end;
       DLL_THREAD_DETACH :
         begin
           dec(Thread_count);
           if assigned(Dll_Thread_Detach_Hook) then
             Dll_Thread_Detach_Hook(DllParam);
           CallDllProc;
{$warning Release Threadvars !}
           Dll_entry:=true; { return value is ignored }
         end;
       DLL_PROCESS_DETACH :
         begin
           Dll_entry:=true; { return value is ignored }
           If SetJmp(DLLBuf) = 0 then
             begin
               FPC_DO_EXIT;
             end;
           if assigned(Dll_Process_Detach_Hook) then
             Dll_Process_Detach_Hook(DllParam);
           CallDllProc;
         end;
     end;
  end;

for netwlibc:

function _DLLMain (hInstDLL:pointer; fdwReason:dword; DLLParam:longint):longbool; cdecl;
[public, alias : '_FPC_DLL_Entry'];
var res : longbool;
  procedure CallDllProc;
  begin
    if Assigned(DllProcEx_Ptr) then
      DllProcEx(fdwreason, DLLparam);
    if Assigned(DllProc_Ptr) then
      DllProc(fdwreason);
  end;
begin
  {$ifdef DEBUG_MT}
  _ConsolePrintf ('_FPC_DLL_Entry called');
  {$endif}
  _DLLMain := false;
  isLibrary := true;
  case fdwReason of
    DLL_ACTUAL_DLLMAIN  : _DLLMain := true;
    DLL_NLM_STARTUP     : begin
                            //_ConsolePrintf ('DLL_NLM_STARTUP');
                            if assigned(Dll_Process_Attach_Hook) then
                            begin
                              res:=Dll_Process_Attach_Hook(DllParam);
                              if not res then
                                exit(false);
                            end;
                            PASCALMAIN;
                            _DLLMain := true;
                          end;
    DLL_NLM_SHUTDOWN    : begin
                            //_ConsolePrintf ('DLL_NLM_SHUTDOWN');
                            TermSigHandler(0);
                            _DLLMain := true;
                          end;
     { standard DllMain() messages...  }
    DLL_THREAD_ATTACH,
    DLL_PROCESS_ATTACH  : begin
                            //__ConsolePrintf ('DLL_PROCESS/THREAD_ATTACH');
                            if assigned(AllocateThreadVars) then
                              AllocateThreadVars;
                            if assigned(Dll_Thread_Attach_Hook) then
                              Dll_Thread_Attach_Hook(DllParam);
                            CallDllProc;
                            _DLLMain := true;
                          end;
    DLL_THREAD_DETACH,
    DLL_PROCESS_DETACH  : begin
                            //__ConsolePrintf ('DLL_PROCESS/THREAD_DETACH');
                            if assigned(Dll_Thread_Detach_Hook) then
                              Dll_Thread_Detach_Hook(DllParam);
                            CallDllProc;
                            if assigned(ReleaseThreadVars) then
                              ReleaseThreadVars;
                            _DLLMain := true;
                          end;
  end;
end;


An important difference between Delphi and this FPC patch behaviour
exists: if we shall assign a value to DllProc and then to DllProcEx,
in Delphi DllProc value will be lost, but in this FPC patch both
handlers will work. But I think, this Borland solution seems to be an
ugly hack which will work only until default calling conventions are
REGISTER or CDECL, otherwise using DllProcEx instead DllProc will
corrupt stack.

--
Best regards,
 Pavel                            mailto:pavel at insect.mail.iephb.ru





More information about the fpc-devel mailing list