-3

So lets take about dll.

If you want to pass a string to a dll call, you must make the procedure input PChar. Else you get data curroption.

so we say that our dll has

  procedure LookPchar(pfff:Pchar);stdCall;External 'OutDll.dll';

which is nice. Now lets look what we declare in the dll dpr:

  procedure LookPchar(pfff:Pchar);
  begin
    with TForm1.Create(nil) do
    try
      show;
      FireDacConnection.ConnectionName := (Copy(pfff,1,100));
    finally
      free;
    end;

  end;
  exports LookPchar;

well, in the Dll we have a Form, with a FireDacConnection in it, but any component or object in it will do the work.

the problem is that this PChar is released twice and cause memory leaks. i can't find a way to pass the PChar without cause memory leaks.

you may use fastmm, i use eurukalog, which writes

|+Leak #2: Type=UnicodeString: Ref count - 1, Content: "\r\n"; Total size=18; Count=1 |

Why is the Unicode String gets Ref count of -1? how to prevent it? how to pass the Unicode string correctly?

What I tried: pass it as const. copy it (as in example and with strpcopy and strcopy) use local variable to hold the copy of PChar.

edit: adding the calling code :

var
  ConnectionName:WideString;
begin
  ConnectionName := 'This Is My String';
  LookPChar(PChar(ConnectionName));
end;

adding leak log dump

|+Leak #2: Type=UnicodeString: Ref count - 1, Content: "\r\n"; Total size=18; Count=1 | |-----------------------------------------------------------------------------------------------------------------------------------------| |00000002|04 |00000000|01D79D9C|outDll.dll|00009D9C|System
| |_NewUnicodeString |23897[6] | |00000002|04 |00000000|008A11BC|myapp.exe |004A11BC|Caller
|TForm2 |Button4Click |66[2] | |00000002|04 |00000000|00641C13|myapp.exe |00241C13|Vcl.Controls |TControl |Click |7348[9] | |00000002|04 |00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl |WndProc |10038[153] | |00000002|04 |00000000|0065B71C|myapp.exe |0025B71C|Vcl.StdCtrls |TButtonControl|WndProc |5163[13] | |00000002|04 |00000000|006462D7|myapp.exe |002462D7|Vcl.Controls | |DoControlMsg |10107[12] | |00000002|04 |00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl |WndProc |10038[153] | |00000002|04 |00000000|0070B240|myapp.exe |0030B240|Vcl.Forms
|TCustomForm |WndProc |4427[206] | |00000002|04 |00000000|006457AC|myapp.exe |002457AC|Vcl.Controls |TWinControl |MainWndProc |9750[3] | |00000002|04 |00000000|004F7614|myapp.exe |000F7614|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76816DE8|user32.dll |00016DE8|USER32 |
| (possible GetThreadDesktop+389) | | |00000002|03
|00000000|76816E49|user32.dll |00016E49|USER32 |
| (possible GetThreadDesktop+486) | | |00000002|03
|00000000|77420107|ntdll.dll |00010107|ntdll |
|KiUserCallbackDispatcher | | |00000002|03
|00000000|768196D0|user32.dll |000196D0|USER32 |
|SendMessageW | | |00000002|03
|00000000|71AB459B|comctl32.dll |000A459B|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB45FE|comctl32.dll |000A45FE|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|71AB4488|comctl32.dll |000A4488|comctl32 |
|LoadIconMetric | | |00000002|03
|00000000|768162F7|user32.dll |000162F7|USER32 |
| (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|76820D32|user32.dll |00020D32|USER32 |
| (possible GetClientRect+192) | | |00000002|03
|00000000|76820D56|user32.dll |00020D56|USER32 |
|CallWindowProcW | | |00000002|04
|00000000|00646282|myapp.exe |00246282|Vcl.Controls |TWinControl
|DefaultHandler |10079[30] | |00000002|04
|00000000|00646172|myapp.exe |00246172|Vcl.Controls |TWinControl
|WndProc |10038[153] | |00000002|04
|00000000|0065B71C|myapp.exe |0025B71C|Vcl.StdCtrls |TButtonControl|WndProc |5163[13] | |00000002|04 |00000000|004F7614|myapp.exe |000F7614|System.Classes| |StdWndProc
|16600[8] | |00000002|03 |00000000|768162F7|user32.dll
|000162F7|USER32 | | (possible gapfnScSendMessage+815)| | |00000002|03
|00000000|76816D35|user32.dll |00016D35|USER32 |
| (possible GetThreadDesktop+210) | | |00000002|03
|00000000|768177CE|user32.dll |000177CE|USER32 |
| (possible CharPrevW+314) | | |00000002|03
|00000000|76817893|user32.dll |00017893|USER32 |

|DispatchMessageW | |

sorry its unclear, i do not know how to keep tabs in stackoverflow editor.

none
  • 4,669
  • 14
  • 62
  • 102
  • The simplest way to pass strings to/from dll is to use `WideString` parameter type. – kludg Dec 27 '15 at 16:16
  • The parameter holding the string reference goes out of scope before it is accessed in the dll. The call to `Show` is not blocking. You need to make a local copy of the string before calling `Show`. – LU RD Dec 27 '15 at 16:23
  • @user246408 same result, reference count -1 – none Dec 27 '15 at 16:26
  • @LURD is " FireDacConnection.ConnectionName := (Copy(pfff,1,100));" not what you suggested? – none Dec 27 '15 at 16:29
  • Since `Show` is not blocking, you need to copy the string before calling `Show`. – LU RD Dec 27 '15 at 16:31

1 Answers1

1

Copy(pfff,1,100) is rather odd. You can use pfff directly and have the compiler automatically convert from pointer to null terminated character array to string.

FireDacConnection.ConnectionName := pfff;

It would surely make sense to do that before calling Show. It certainly seems pretty weird that you show a form modeless, then set the connection name, and then free the form. Indeed, even showing a form in a DLL looks odd.

That said, this isn't the cause of your problem. The only explanation for a leak in you code is a calling convention mismatch, or an error at the call site. Passing a PChar, and taking a copy, as you do, won't leak.

The calling convention in the implementation appears to be register. The declaration in your DLL should be:

procedure LookPchar(pfff:Pchar); stdcall;

Or did you not show the stdcall in the DLL code?

You might have made a mistake at the call site. Perhaps the leak is there. We cannot see that code.

Looking at your various edits, FastMM is reporting a leak that is not produced by any of the code in the question. You will need to isolate the issue before you can solve it. That's your next step.

Using PChar is fine for input. In the other direction, from callee to caller, there are many options, but you have not asked about that here. And there are many many questions on that topic.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • what stdcall should be in the dll? can you show on the code? or provide the line?(same for register please). – none Dec 27 '15 at 17:10
  • followed this: http://www.tutorialspoint.com/dll/dll_delphi_example.htm and added stdcall; to the procedure in the dll. and added index 1; to the exports. still same error. – none Dec 27 '15 at 17:14
  • You appear to be floundering. Trying stuff at random. Without a clear understanding of anything. Back to basics. Forget about the form and the connection. Try to pass a PChar to a DLL successfully. – David Heffernan Dec 27 '15 at 17:16
  • @david-hefferman Passing just PChar to the dll, and do showmessage, works without memory leak or data corruption. when it is passed to object the reference count kicks in and do damage. – none Dec 27 '15 at 17:26
  • There's no reference counting on a PChar. Your code as presented is basically fine, apart from calling convention and odd use of Copy. The error is somewhere else. – David Heffernan Dec 27 '15 at 17:30
  • The calling code is weird. Why use `WideString` there? I answered the question you originally asked. Perhaps I should have insisted on a [mcve] before devoting time to this. – David Heffernan Dec 27 '15 at 17:47
  • It was my choice, but I think I answered the question you asked. No? – David Heffernan Dec 27 '15 at 19:13