1
\$\begingroup\$

I am trying to write a generic function for loading a function from a DLL library. I am in no way an expert on DLLs, that is why I ask.

We have discussed it first in my Stack Overflow question to discover the most obvious errors, and there were some crucial ones.


Current version of my code follows:

function LoadFunctionFromLibrary(const LibraryName, FunctionName: string; out FunctionPointer: Pointer): Boolean;

var
  LibraryHandle: THandle;

begin
  Result := False;
  FunctionPointer := nil;

  LibraryHandle := Winapi.Windows.LoadLibrary(PChar(LibraryName));
  if LibraryHandle = 0 then Exit;

  FunctionPointer := Winapi.Windows.GetProcAddress(LibraryHandle, PChar(FunctionName));

  if Assigned(FunctionPointer) then
    Result := True;
end;

This version of the function has been successfully tested on my EnableInput function:

function EnableInput(const Enable: Boolean): Boolean;

var
  BlockInput: function(Block: BOOL): BOOL; stdcall;

begin
  Result := LoadFunctionFromLibrary('User32.dll', 'BlockInput', @BlockInput) and
            BlockInput(not Enable);
end;
\$\endgroup\$
2
\$\begingroup\$

Just like Dangph, I wonder why you need this. There are other better approaches suggested in the previous comments.

Even if this is useful, Your solution is not great: 1. You repeatedly load the library and the function. 2. There is no way for you to free the loaded libraries.

Here is a better way to do it:

type
  TFunctionLoader = class
  private
    FLibraries: TStrings;   // This stores the library handles and names
    FFunctions: TStrings;   // This stores the function pointers and names
  public
    constructor Create;
    destructor Destroy; override;
    function LoadFunction(const LibraryName, FunctionName: string; 
                          out FunctionPointer: Pointer): Boolean;
  end;

{ TFunctionLoader }

constructor TFunctionLoader.Create;
begin
  FLibraries := TStringList.Create;
  FFunctions := TStringList.Create;
end;

destructor TFunctionLoader.Destroy;
var
  i: Integer;
begin
  for i := 0 to FLibraries.Count - 1 do     // free all opened libraries
    Windows.FreeLibrary(THandle(FLibraries.Objects[i]));
  FLibraries.Free;                          // free other objects
  FFunctions.Free;
end;

function TFunctionLoader.LoadFunction(const LibraryName, FunctionName: string;
  out FunctionPointer: Pointer): Boolean;
var
  i: Integer;
  LibraryHandle: THandle;
begin
  i := FFunctions.IndexOf(FunctionName);    // Is the function already loaded?
  if i >= 0 then
  begin                                     // Yes, just return the stored pointer
    FunctionPointer := Pointer(FFunctions.Objects[i]);
    Exit(True);
  end;

  i := FLibraries.IndexOf(LibraryName);     // No, test if the library is already loaded
  if i < 0 then
  begin                                     // No, load it and store in FLibraries
    LibraryHandle := Windows.LoadLibrary(PChar(LibraryName));
    if LibraryHandle = 0 then Exit(False);  // Failed, quit
    i := FLibraries.AddObject(LibraryName, TObject(LibraryHandle));
  end;

  // Load the function from the library
  FunctionPointer := Windows.GetProcAddress(THandle(FLibraries.Objects[i]),
                                            PChar(FunctionName));
  Result := Assigned(FunctionPointer);      // succeeded?
  if Result then                            // Add the function to FFunctions
    FFunctions.AddObject(FunctionName, TObject(FunctionPointer));
end;

With above you can define var FunctionLoader: TFunctionLoader; somewhere and add this to the end of the unit

initialization
  FunctionLoader := TFunctionLoader.Create;
finalization
  FunctionLoader.Free;
end.

Use it as

Result := FunctionLoader.LoadFunction('User32.dll', 'BlockInput', @BlockInput)
          and BlockInput(not Enable);

All functions and libraries will be loaded only once and will be automatically freed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.