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;
1 Answer 1
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.
Explore related questions
See similar questions with these tags.