A interesting problem that i ran into today.
I am loading a dll under windows. When this code is executed directly under the main program, it runs correctly.
When executed under a thread, it fails just as it leaves the CallDll with a segfault.
Yet, i can see in the DLL loading routine, that it correctly performs the function call and gets the "Hello World".
So i assumed its a ownership issue with the variable passing. Replacing the return with a temporary value. Still crash.
Disable the function call but still load / unload the library. No issue / no crash.
Now, if i chance the stdcall/cdecl to "pascal" and replace the PChar to String everywhere, it does not fail anymore ( what is strange as technically pascal is supposed to be a stdcall ). But the string content is simply garbled junk.
The question becomes more or less, is it not possible to run the same function call from a library in multiple threads. Been driving me up the wall...
library dll_hello;
{$mode objfpc}{$H+}
function Process(Num1: Integer): PChar; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
begin
Result:= 'Hello World';
end;
exports
Process;
begin
end.
unit xLoader;
{$mode objfpc}
interface
function CallDll (LibraryName : String) : String;
type
TMyFunc=function (Num1: Integer): PChar; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; // The called function parameters ... cdecl; for linux??
implementation
uses DynLibs;
//////////////////////////////////////////////////
// CallDll Function
//////////////////////////////////////////////////
function CallDll (LibraryName : String) : String;
var
MyFunc: TMyFunc;
LibHandle: TLibHandle = dynlibs.NilHandle;
FuncResult: PChar; // The called function return type
begin
LibHandle := LoadLibrary(LibraryName + '.dll');// + SharedSuffix);
if LibHandle = dynlibs.NilHandle then
begin
Writeln('DLL was not loaded successfully');
Exit;
end;
if LibHandle = 0 then
begin
Writeln('DLL was not loaded successfully2');
Exit;
end;
Writeln('DLL was loaded successfully');
Pointer(MyFunc) := TMyFunc(GetProcedureAddress(LibHandle, 'Process')); // Call the function "Process"
if @MyFunc = nil then
Writeln('GetProcedureAddress called and failed');
Writeln('GetProcedureAddress called');
FuncResult := MyFunc (1); //Executes the function. The reason for the crash actually.
Writeln('Function called');
Writeln(FuncResult); // Gets correct result here
Writeln('Got results back');
Writeln('Before unload');
MyFunc := nil;
if LibHandle <> DynLibs.NilHandle then
if FreeLibrary(LibHandle) then LibHandle:= DynLibs.NilHandle; //Unload the lib, if already loaded
Writeln('After unload');
Result := FuncResult; // Does not return the correct result to the main unit. Pascal usage = garbled. Other like stdcall / PChar = crash...
// Crash Point ...
end;
end.
// Inside Thread = Crash. Same code in main unit body = works perfectly.
responseString := CallDll('dll_hello');