- Posts: 13
- Thank you received: 0
×
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
-
Less
More
2 weeks 4 days 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.
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.
Attachments:
Please Log in or Create an account to join the conversation.
- Matis A.
-
- Offline
- Moderator
-
2 weeks 3 days ago - 2 weeks 3 days ago #17102
by Matis A.
PilotLogic Core Programmer
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
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 3 days ago by Matis A..
Please Log in or Create an account to join the conversation.
- Robert Jenkins
- Topic Author
- Offline
- New Member
-
Less
More
- Posts: 13
- Thank you received: 0
2 weeks 3 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.
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.
- Matis A.
-
- Offline
- Moderator
-
2 weeks 3 days ago - 2 weeks 3 days ago #17104
by Matis A.
PilotLogic Core Programmer
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
pl_ACS pkg
file codetyphon\typhon\components\packages_pl\pl_ACS\source\bs_lame.pas
PilotLogic Core Programmer
Last edit: 2 weeks 3 days ago by Matis A..
Please Log in or Create an account to join the conversation.
- Robert Jenkins
- Topic Author
- Offline
- New Member
-
Less
More
- Posts: 13
- Thank you received: 0
2 weeks 9 hours 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
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.
- Matis A.
-
- Offline
- Moderator
-
2 weeks 1 hour ago #17106
by Matis A.
PilotLogic Core Programmer
Replied by Matis A. on topic LoadLibrary / GetProcedureAddress
Thanks
have fun.
have fun.
PilotLogic Core Programmer
Please Log in or Create an account to join the conversation.