Recent

Author Topic: DLL returns pChar OK, but my app receive a strange value  (Read 1141 times)

hamacker

  • Jr. Member
  • **
  • Posts: 50
DLL returns pChar OK, but my app receive a strange value
« on: December 13, 2022, 10:26:12 pm »
Hi ALL,

I Create a DLL as:
Code: Pascal  [Select][+][-]
  1. function DLL_Proc(var pParamList:PChar): PChar; cdecl;
  2. var
  3.   sParamListAsString: String;
  4.   sResultado:String;
  5. begin
  6.   sResultado:='RESULT=FAIL'+sLineBreak;
  7.   Result:=pChar(sResultado);
  8.   sParamListAsString:=Trim(pParamList);
  9.   sResultado:=Relatorio_Run(sParamListAsString);
  10.   Result:=Pchar(sResultado);
  11.   Application.MessageBox(Result, pChar('Testing Returning values:')); // it´s OK here
  12. end;

But my code code bellow receive a strange value:
Code: Pascal  [Select][+][-]
  1. function DLL_Proc(
  2.   ADLL_Filename:String;
  3.   ADLL_Param1:String;
  4.   out ADLL_ResultAsString:String):String;
  5. type
  6.   TDLL_Proc= function (var pParamList:pChar): pChar; cdecl;
  7. var
  8.   myDLL_Proc: TDLL_Proc;
  9.   myLibHandle : THandle;
  10.   ADLL_Param1_AsPchar:pChar;
  11.   ADLL_Result_AsPchar:pChar;
  12. begin
  13.   Result:=emptyStr;
  14.   ADLL_ResultAsString:='';
  15.   ADLL_Filename:=Trim(ADLL_Filename);
  16.   ADLL_Param1_AsPchar:=pChar(ADLL_Param1);
  17.   if not FileExists(ADLL_Filename) then
  18.     Result:='Arquivo não existe: '+ADLL_Filename;
  19.  
  20.   if Result=emptyStr then
  21.   begin
  22.     myLibHandle := SafeLoadLibrary(PChar(ADLL_Filename));
  23.     // Verifica se o carregamento da DLL foi bem-sucedido
  24.     if myLibHandle <> 0 then
  25.     begin
  26.       // Atribui o endereço da chamada da sub-rotina à variável myDLL_Proc
  27.       // 'myDLL_Proc' da DLL DLL_Servidor.dll
  28.       try
  29.         Pointer(myDLL_Proc) := GetProcAddress(myLibHandle, 'DLL_Proc');
  30.  
  31.         // Verifica se um endereço válido foi retornado
  32.         if @myDLL_Proc <> nil then
  33.         begin
  34.           ADLL_Result_AsPchar := myDLL_Proc(ADLL_Param1_AsPchar);   // bug
  35.           Application.MessageBox(ADLL_Result_AsPchar,pChar('Retornou o valor:'));  // show wrong(noise) string
  36.           // retornando como string
  37.           ADLL_ResultAsString:=String(ADLL_Result_AsPchar);
  38.         end;
  39.  
  40.       except
  41.         on e:exception do Result:=e.message;
  42.       end;
  43.     end;
  44.  
  45.     // liberar memoria
  46.     myDLL_Proc := nil;
  47.     if myLibHandle <> 0 then
  48.       FreeLibrary(myLibHandle);
  49.   end;
  50. end;

What´s is wrong?
I debug all day without find any error inside DLL and there is OK. but my app receive a diferente Value from pchar.  I try cdecl and stdcall with the same (wrong) results.

bytebites

  • Hero Member
  • *****
  • Posts: 642
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #1 on: December 13, 2022, 11:07:35 pm »
Your sResultado string is freed, when the function exits.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #2 on: December 14, 2022, 12:55:06 am »
What´s is wrong?
I debug all day without find any error inside DLL and there is OK. but my app receive a diferente Value from pchar.  I try cdecl and stdcall with the same (wrong) results.

The Result of the DLL function is pointing at the internal data of the local sResultado variable, which is freed when the DLL function exits, thus leaving the Result pointing at invalid memory.  There is no data for the caller to access safely.

Use SysUtils.StrAlloc() to return a dynamically allocated string for the caller to use.  The caller can then pass it back into the DLL when done using it, so it can be freed properly with SysUtil.StrDispose().  For example:

Code: Pascal  [Select][+][-]
  1. function DLL_Proc(var pParamList: PChar): PChar; cdecl;
  2. var
  3.   ...
  4.   sResultado: String;
  5. begin
  6.   ...
  7.   sResultado := ...;
  8.   Result := StrAlloc(Length(sResultado)+1);
  9.   StrPCopy(Result, sResultado);
  10.   ...
  11. end;
  12.  
  13. procedure DLL_FreeProc(pParam: PChar); cdecl;
  14. begin
  15.   StrDispose(pParam);
  16. end;
  17.  

Code: Pascal  [Select][+][-]
  1. var
  2.   ...
  3.   ADLL_Result_AsPchar: PChar;
  4. begin
  5.   ...
  6.   ADLL_Result_AsPchar := myDLL_Proc(...);
  7.   try
  8.     // use ADLL_Result_AsPchar as needed...
  9.   finally
  10.     myDLL_FreeProc(ADLL_Result_AsPchar);
  11.   end;
  12.   ...
  13. end;
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

cai

  • New Member
  • *
  • Posts: 41
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #3 on: December 14, 2022, 07:33:45 am »
you should learn some pointer & memory manage knownology first,
the pChar is ref to string sResultado, it is auto alloc-free in dll proc.

normally, you should do like this:
----------------------------------
pCharS := AllocMem(LEN);
CALL_DLL_PROC(pCharS, LEN);  --> code in dll: Move(sResultado[1], pCharS^, LEN);
FreeMem(pCharS);

Thaddy

  • Hero Member
  • *****
  • Posts: 14382
  • Sensorship about opinions does not belong here.
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #4 on: December 14, 2022, 09:56:51 am »
Another option is to use sharemem in both executable and the dll.
Sharemem must be the first unit, since it is a memory manager.
If you do it like that you don't need to fiddle with PChars /move/copy at all as long as both the dll and the executable are written in FreePascal/Lazarus. You can just use strings.

Caveat: the dll is not usable with other languages.
« Last Edit: December 14, 2022, 10:03:20 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Zvoni

  • Hero Member
  • *****
  • Posts: 2330
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #5 on: December 14, 2022, 01:55:51 pm »
Another option is to use sharemem in both executable and the dll.
Sharemem must be the first unit, since it is a memory manager.
If you do it like that you don't need to fiddle with PChars /move/copy at all as long as both the dll and the executable are written in FreePascal/Lazarus. You can just use strings.

Caveat: the dll is not usable with other languages.
Wasn’t there a second caveat with ShareMem under windows that you have to compile some fpcmem-something-DLL and place it in your exe-folder?

EDIT Yep!
https://www.freepascal.org/docs-html/rtl/sharemem/index.html
« Last Edit: December 14, 2022, 02:00:31 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

hamacker

  • Jr. Member
  • **
  • Posts: 50
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #6 on: December 14, 2022, 02:42:55 pm »
Yes, I need to practice more.
Can you help me to understand and others like me patching this little sample:
https://github.com/gladiston/lazdemos_gsl/tree/main/lazdemo_dll
There is two projects DLL: Client and Provisor with returning string value.

After, this correction will help another guys.
This repo in github is used to put several samples that I intent to help another guys.


you should learn some pointer & memory manage knownology first,
the pChar is ref to string sResultado, it is auto alloc-free in dll proc.

normally, you should do like this:
----------------------------------
pCharS := AllocMem(LEN);
CALL_DLL_PROC(pCharS, LEN);  --> code in dll: Move(sResultado[1], pCharS^, LEN);
FreeMem(pCharS);

hamacker

  • Jr. Member
  • **
  • Posts: 50
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #7 on: December 14, 2022, 07:25:20 pm »
I fix my code, anyone can check:
https://github.com/gladiston/lazdemos_gsl/tree/main/lazdemo_dll

This repo in github is used to put several samples that I intent to help another guys.
PS: I consume this DLL in Lazarus app perfectly, but in delphi application FAIL. I think that´s impossible, is it?

cai

  • New Member
  • *
  • Posts: 41
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #8 on: December 16, 2022, 06:56:54 am »
Yes, I need to practice more.
Can you help me to understand and others like me patching this little sample:
https://github.com/gladiston/lazdemos_gsl/tree/main/lazdemo_dll
There is two projects DLL: Client and Provisor with returning string value.

After, this correction will help another guys.
This repo in github is used to put several samples that I intent to help another guys.


you should learn some pointer & memory manage knownology first,
the pChar is ref to string sResultado, it is auto alloc-free in dll proc.

normally, you should do like this:
----------------------------------
pCharS := AllocMem(LEN);
CALL_DLL_PROC(pCharS, LEN);  --> code in dll: Move(sResultado[1], pCharS^, LEN);
FreeMem(pCharS);

I read your code in github
myDLL_FreeProc should be free the pchar pointer, not API pointer.

Code: Pascal  [Select][+][-]
  1. try
  2.         Pointer(myDLL_Proc) := GetProcAddress(myLibHandle, 'DLL_Proc');
  3.         // Verifica se um endereço válido foi retornado
  4.         if @myDLL_Proc <> nil then
  5.         begin
  6.           ADLL_Result_AsPChar := myDLL_Proc(ADLL_Param1_AsPChar);
  7.           // retornando como string
  8.           ADLL_ResultAsString:=String(ADLL_Result_AsPChar);
  9.           // Liberando memória que esta na DLL, neste caso, passo o ponteiro
  10.           //   a se eliminado com StrDispose(dentro da DLL). Se não fizer isso
  11.           //   haverá vazamento de memória
  12.           try
  13.             Pointer(myDLL_FreeProc) := GetProcAddress(myLibHandle, 'DLL_FreeProc');
  14.             if @myDLL_FreeProc <> nil then
  15.             begin
  16.               // edited by cai
  17.               //myDLL_FreeProc(@myDLL_Proc);
  18.               if ADLL_Result_AsPChar <>nil then
  19.                 myDLL_FreeProc(ADLL_Result_AsPChar); // --> StrDispose(ADLL_Result_AsPChar);
  20.             end;
  21.           except
  22.             on e:exception do Result:=e.message;
  23.           end;
  24.         end;
  25.  
  26.       except
  27.         on e:exception do Result:=e.message;
  28.       end;
  29.  


there is no StrAlloc in myDLL_Echo , the result is ref to parameter, so do not call myDLL_FreeProc.
« Last Edit: December 16, 2022, 07:03:56 am by cai »

hamacker

  • Jr. Member
  • **
  • Posts: 50
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #9 on: December 16, 2022, 06:04:18 pm »
Thank you so much.
Now my sample is done as can you see:
https://github.com/gladiston/lazdemos_gsl/tree/main/lazdemo_dll

Is it possible to consume DLL in Delphi Apps?
My attach files shows that values get in Delphi is complete wrong.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2088
  • Fifty shades of code.
    • Delphi & FreePascal
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #10 on: December 16, 2022, 06:36:00 pm »
A Simple Dll made with Delphi Alexandria can look like this:
Code: Pascal  [Select][+][-]
  1. library TheDLL;
  2.  
  3. uses
  4.   Winapi.Windows,
  5.   System.SysUtils,
  6.   System.Classes;
  7.  
  8. procedure TestProc(const a: integer); stdcall; export;
  9. begin
  10.   Winapi.Windows.MessageBox(0, PChar('Hello World (' + IntToStr(a) + ')'), PChar('Caption'), MB_OK);
  11. end;
  12.  
  13. exports
  14.   TestProc;
  15.  
  16. begin
  17. end.
The Test application can look like:
Code: Pascal  [Select][+][-]
  1. unit uMain;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  7.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
  8.  
  9. type
  10.   TForm5 = class(TForm)
  11.     Button1: TButton;
  12.     procedure Button1Click(Sender: TObject);
  13.   private
  14.     { Private declarations }
  15.   public
  16.     { Public declarations }
  17.   end;
  18.  
  19. var
  20.   Form5: TForm5;
  21.  
  22. procedure TestProc(const a: Integer); stdcall; external 'TheDLL.dll' name 'TestProc';
  23.  
  24. implementation
  25.  
  26. {$R *.dfm}
  27.  
  28. procedure TForm5.Button1Click(Sender: TObject);
  29. begin
  30.   TestProc(666);
  31. end;
  32.  
  33. end.
I hope you understand what I do there.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Thaddy

  • Hero Member
  • *****
  • Posts: 14382
  • Sensorship about opinions does not belong here.
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #11 on: December 16, 2022, 06:39:16 pm »
As long the dll is well written there is no reason it should not work in other languages.
That means: refer from reference counted types in the dll and use getmem/freemem to allocate Pchar instead of string, which is a managed type. The original question was bad coding to begin with. That may confuse other people.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

hamacker

  • Jr. Member
  • **
  • Posts: 50
Re: DLL returns pChar OK, but my app receive a strange value
« Reply #12 on: December 17, 2022, 04:17:53 am »
Eureka! I did!
Need to change pchar to PWideChar and String to WideString.
Now it´s OK.
As you can see in attachment, just a little hints that I need to study more and understand why.

Thank you again.

 

TinyPortal © 2005-2018