softtouch 9 Posted August 17, 2023 (edited) How must be the prototype of a function inside a bpl in order to return a string to the caller? This is the test bpl code: unit test; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end; function GetPluginName:string; var Form1: TForm1; implementation {$R *.dfm} function GetPluginName:string; begin result:='test'; end; exports GetPluginName; end. And here is the test caller code: unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; GetPluginName:function:string; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var h:nativeuint; s:string; begin h:=LoadPackage('test.bpl'); @GetPluginName:=GetProcAddress(h, 'GetPluginName'); s:=GetPluginName; UnloadPackage(h); end; end. Edited August 18, 2023 by softtouch Share this post Link to post
Attila Kovacs 629 Posted August 17, 2023 what was your first google hit? Share this post Link to post
David Heffernan 2345 Posted August 18, 2023 This will work fine so long as everything is linked correctly. No need even to use stdcall. So probably the linkage is messed up. We can't see the entire picture. Share this post Link to post
softtouch 9 Posted August 18, 2023 42 minutes ago, David Heffernan said: This will work fine so long as everything is linked correctly. No need even to use stdcall. So probably the linkage is messed up. We can't see the entire picture. I updated the first post with the complete test code for bpl and caller. I removed the stdcall. The result is the same, an AV as long the bpl return anything. If I remove the line with the result:=..., no AV and its fine. Share this post Link to post
David Heffernan 2345 Posted August 18, 2023 That's not quite enough. Do the exe and bpl both link to the same runtime packages? Share this post Link to post
Uwe Raabe 2057 Posted August 18, 2023 Can you try assigning the string constant to a variable first and/or calling UniqueString on result after assignment? The string literal may vanish when unloading the package. Share this post Link to post
softtouch 9 Posted August 18, 2023 5 minutes ago, Uwe Raabe said: Can you try assigning the string constant to a variable first and/or calling UniqueString on result after assignment? The string literal may vanish when unloading the package. I tried, but its the same. var s:='Test'; result:=s; UniqueString(result); When I get the string from the caller code with s:=GetPluginName; s contains 'Test', as it should. But when I unload the package, s will be "inaccessible" and I get an AV. Share this post Link to post
Uwe Raabe 2057 Posted August 18, 2023 Perhaps a UniqueString(s) before unloading the package might work then? It looks like the problem comes from the package invalidating the result string memory when unloading. The tricky part now is to find a workaround for this. Share this post Link to post
softtouch 9 Posted August 18, 2023 3 minutes ago, Uwe Raabe said: Perhaps a UniqueString(s) before unloading the package might work then? It looks like the problem comes from the package invalidating the result string memory when unloading. The tricky part now is to find a workaround for this. A workaround would be this I guess: var tmp:=GetPluginName; s:=copy(tmp,1); tmp:=''; "tmp" gets the correct text, so I copy that text to "s", and set "tmp" to nil, and "s" still contains the right text after unloading the bpl. If I dont set "tmp" to nil, it will crash. So its somehow related to the reference count I think. Share this post Link to post
Remy Lebeau 1398 Posted August 19, 2023 On 8/18/2023 at 2:34 AM, softtouch said: A workaround would be this I guess: UniqueString() would have done the same thing with less code, eg: s := GetPluginName; UniqueString(s); To make things easier on the caller, that should be done inside of the package function instead, eg: function GetPluginName: string; begin Result := 'test'; UniqueString(result); end; On 8/18/2023 at 2:34 AM, softtouch said: If I dont set "tmp" to nil, it will crash. That makes sense if you are letting the compiler clear "tmp" AFTER the package has been unloaded, since "tmp" will be pointing at unloaded memory when the RTL tries to access it for cleanup, Calling UniqueString()/Copy() BEFORE the package is unloaded addresses that problem. Of course, you could also solve the problem by simply not returning a string literal from the function in the first place, or by ensuring the caller is completely finished using any data from the package before unloading it from memory. Share this post Link to post