× CodeTyphon MS Windows (XP, Vista, Win7, Win8.x and Win10) OS Development, discussions and problems

Question LoadLibrary / GetProcedureAddress

  • Robert Jenkins
  • Topic Author
  • Offline
  • New Member
  • New Member
More
3 weeks 3 hours ago #17101 by Robert Jenkins
LoadLibrary / GetProcedureAddress was created by Robert Jenkins
Using CT 7.8 x64 On Windows 11 x64 with all updates applied. 
Also tested using CT 7.8 x64 on Windows 10 x64 with all updates applied. 
Using x64 code with x64 DLLs. 
I am am uploading a zip file of the project and I tried to leave all the stuff out that you don't need to test such as backup files, etc... 

Okay, I am attempting to write a unit to use shared library on Windows (DLL)  What I believe is referred to as Early Binding works, but I wanted to try what I believe is referred to Late Binding using LoadLibrary and GetProcedureAddrss and I can't get that to work.

Here is my example code.

Unit uDynamicLoad;

{$mode objFPC}{$H+}

{$DEFINE LOAD_DYNAMIC} // when this is defined the code doesn't work.

Interface

Uses
  Classes,
  SysUtils;

Const
  TESSERACT_LIBRARY = 'tesseract41.dll';
  LAME_LIBRARY = 'libmp3lame.dll';
  INVALID_HANDLE_VALUE = THANDLE(-1);


{$IFDEF LOAD_DYNAMIC}
Type
  TFnTessVersion    = Function: PChar; Cdecl;
  TFnGetLameVersion = Function: PChar; Cdecl;
  TFnGetLameUrl     = Function: PChar; Cdecl;

Var
  TessVersion       : TFnTessVersion;
  get_lame_version  : TFnGetLameVersion;
  get_lame_Url      : TFnGetLameUrl;
  {$ELSE}
    ///  This works just fine... 
    Function TessVersion       : pChar; cdecl; external TESSERACT_LIBRARY name 'TessVersion';
    function get_lame_version  : pChar; cdecl; external LAME_LIBRARY name 'get_lame_version';
    function get_lame_url      : pChar; cdecl; external LAME_LIBRARY name 'get_lame_url';
  {$ENDIF}

Implementation


{$IFDEF LOAD_DYNAMIC}
Var
  hTesseract : TLibHandle;
  hLame      : TLibHandle;


Function IsValidHandle(Const AHandle: THandle): Boolean;
Begin
  Result := (AHandle <> 0) And (AHandle <> INVALID_HANDLE_VALUE);
End;

Procedure LoadTesseract;
Begin
  TessVersion := Nil;
  hTesseract := LoadLibrary(TESSERACT_LIBRARY);
  If IsValidHandle(hTesseract) Then
  Begin
    ///  the variable for TessVersion doesn't appear to be assigned the value correctly or I am not assigning the value correctly as this doesn't work 
    TessVersion := TFnTessVersion(GetProcedureAddress(hTesseract, 'TessVersion'));
    // Pointer(TessVersion) := GetProcedureAddress(hTesseract, 'TessVersion');
  End;
End;

Procedure UnLoadTesseract;
Begin
  If IsValidHandle(hTesseract) Then
  Begin
    UnLoadLibrary(hTesseract);
  End;
End;

Procedure LoadLame;
Begin
  get_lame_version := Nil;
  get_lame_url := Nil;
  hLame := LoadLibrary(LAME_LIBRARY);
  If IsValidHandle(hLame) Then
  Begin
     ///  Same here.  These don't work. 
    get_lame_version := TFnGetLameVersion(GetProcedureAddress(hLame, 'get_lame_version'));
    get_lame_url := TFnGetLameUrl(GetProcedureAddress(hLame, 'get_lame_url'));
  End;
End;

Procedure UnLoadLame;
Begin
  If IsValidHandle(hLame) Then
  Begin
    UnLoadLibrary(hLame);
  End;
End;



Initialization
  LoadTesseract;
  LoadLame;

Finalization
  UnLoadLame;
  UnLoadTesseract;

{$ENDIF}

End.


in my main using I try something like: 
  memo1.Lines.Add('Tesseract Version: %s', [ String( TessVersion )]);
  memo1.Lines.Add('Lame Version: %s',      [ String( get_lame_version) ]);
  memo1.Lines.Add('Lame URL: %s',          [ String( get_lame_url) ]);


Thanks

Robert

ps.  I used vcpkg, which is on git hub, to download and build the DLLs. 

 

Please Log in or Create an account to join the conversation.

More
2 weeks 6 days ago - 2 weeks 6 days ago #17102 by Matis A.
Replied by Matis A. on topic LoadLibrary / GetProcedureAddress
Please use:
Pointer(get_lame_version):=GetProcedureAddress(hLame, 'get_lame_version');
Pointer(get_lame_url) := (GetProcedureAddress(hLame, 'get_lame_url');

Look at :
-pl_OpenCL
-pl_OpenSSL
-pl_USB
-etc

PilotLogic Core Programmer
Last edit: 2 weeks 6 days ago by Matis A..

Please Log in or Create an account to join the conversation.

  • Robert Jenkins
  • Topic Author
  • Offline
  • New Member
  • New Member
More
2 weeks 6 days ago #17103 by Robert Jenkins
Replied by Robert Jenkins on topic LoadLibrary / GetProcedureAddress
I had tried type casting the function using the Pointer(function) approach.  It is even commented out in the the example code for the Tesseract function call example I provided.  But that is not working either...

    Pointer(TessVersion) := GetProcedureAddress(hTesseract, 'TessVersion');
    Pointer(get_lame_version) := GetProcedureAddress(hLame, 'get_lame_version');
    Pointer(get_lame_url) := GetProcedureAddress(hLame, 'get_lame_url');

I have had code not work before and then I used CTC to remove and rebuild everything and the code started working.  I'll try that and see what I get. 
 

Please Log in or Create an account to join the conversation.

More
2 weeks 6 days ago - 2 weeks 6 days ago #17104 by Matis A.
Replied by Matis A. on topic LoadLibrary / GetProcedureAddress
Look and
pl_ACS pkg
file  codetyphon\typhon\components\packages_pl\pl_ACS\source\bs_lame.pas

PilotLogic Core Programmer
Last edit: 2 weeks 6 days ago by Matis A..

Please Log in or Create an account to join the conversation.

  • Robert Jenkins
  • Topic Author
  • Offline
  • New Member
  • New Member
More
2 weeks 3 days ago #17105 by Robert Jenkins
Replied by Robert Jenkins on topic LoadLibrary / GetProcedureAddress
It appears the program must use "{$mode delphi}".  If you are loading the function from a separate unit that unit can be compiled with either {$mode delphi} or {$mode objfpc} but the main program must use {$mode delphi}. 

As additional testing, I attempted to import the function "LockWorkStation" from User32.dll.  When attempting to use {$mode objfpc} in my main program it returns the following error.

     unit1.pas(45,12) Error: Incompatible types: got "<procedure variable type of function:LongBool;StdCall>" expected "LongBool"


However, when using {$mode delphi} in the main program it works correctly  Both dynamic load and static load works this way. 

If anyone wants to test to see what they get I included a simple unit to load "LockWorkStation" for testing. 


Unit uLockWorkstation;

{$mode objFPC}{$H+}

{$DEFINE LOAD_DYNAMIC}

Interface

Uses
  Windows,
  Classes, Sysutils;

Const
  USER32_LIBRARY = 'User32.dll';

{$IFDEF LOAD_DYNAMIC}
Type
  TFnLockWorkStation    = Function : BOOL; StdCall;

Var
  LockWorkStation       : TFnLockWorkStation;
{$ELSE}
    ///  This works just fine...
    Function LockWorkStation       : BOOL; StdCall; external USER32_LIBRARY name 'LockWorkStation';
{$ENDIF}

Implementation

{$IFDEF LOAD_DYNAMIC}


Var
  hUser32 : TLibHandle;


  Function IsValidHandle(Const AHandle: THandle) : Boolean;
  Begin
    Result := (AHandle <> 0) And (AHandle <> INVALID_HANDLE_VALUE);
  End;

  Procedure LoadUser32;
  Begin
    LockWorkStation := Nil;
    hUser32 := LoadLibrary(USER32_LIBRARY);
    If IsValidHandle(hUser32) Then
    Begin
      LockWorkStation := TFnLockWorkStation(GetProcAddress(hUser32, 'LockWorkStation'));
    End;
  End;

  Procedure UnloadUser32;
  Begin
    If IsValidHandle(hUser32) Then
    Begin
      UnloadLibrary(hUser32);
    End;
  End;

Initialization
  LoadUser32;

Finalization
  UnloadUser32;

{$ENDIF}


End.



Thanks

Robert

 

Please Log in or Create an account to join the conversation.

More
2 weeks 2 days ago #17106 by Matis A.
Replied by Matis A. on topic LoadLibrary / GetProcedureAddress
Thanks
have fun.

PilotLogic Core Programmer

Please Log in or Create an account to join the conversation.