Home Is it safe to pass Delphi const string params across memory manager boundaries?
Reply: 4

Is it safe to pass Delphi const string params across memory manager boundaries?

himself
1#
himself Published in 2010-07-05 10:47:50Z

Subj. I'd like to use strings instead of PChar because that spares me much casting, but if I just do

procedure SomeExternalProc(s: string); external SOMEDLL_DLL;

and then implement it in some other project with non-shared memory manager:

library SeparateDll;
procedure SomeExternalProc(s: string);
begin
  //a bla bla bla
  //code here code here
end;

I have (formally) no guarantee Delphi does not decide for whatever reason to alter the string, modify its reference counter, duplicate or unique it, or whatever else. For example

var InternalString: string;

procedure SomeExternalProc(s: string);
begin
  InternalString := s;
end;

Delphi increments refcounter and copies a pointer, that's it. I'd like Delphi to copy the data. Does declaring the parameter as "const" make it safe for that reason? If not, is there a way to do it? Declaring parameter as PChar doesn't seem to be a solution because you need to cast it every time:

procedure SomeExternalProc(s: Pchar); forward;
procedure LocalProc;
var local_s: string;
begin
  SomeExternalProc(local_s); //<<--- incompatible types: 'string' and 'PAnsiChar'
end;
Mason Wheeler
2#
Mason Wheeler Reply to 2010-07-05 12:25:43Z

That would probably work, as long as you only ever use your DLL from code compiled in the same version of Delphi. The internal format of string has been known to change between releases, and you have no formal guarantee that it won't change again.

If you want to avoid having to cast everywhere you use it, try wrapping the function, like this:

procedure SomeExternalProc(s: Pchar); external dllname;
procedure MyExternalProc(s: string); inline;
begin
  SomeExternalProc(PChar(local_s));
end;

Then in your code, you call MyExternalProc instead of SomeExternalProc, and everyone's happy.

Community
3#
Community Reply to 2017-05-23 12:30:55Z

If both the app and the DLL are written in the same Delphi release, just use shared memory manager (more details here).

If one side is written in a different language than there's no other way but to use PChar or WideString (WideStrings are managed by the COM memory manager).

Or you can write a wrapper function:

procedure MyExternalProc(const s: string);
begin
  SomeExternalProc(PChar(s));
end;
Andrew
4#
Andrew Reply to 2010-07-05 12:42:53Z

I recommend to use an alternative memory manager such as RecyclerMM or FastMM. They doesn't require any external shared MM dll's and allows you to pass strings to the dlls safely. As a bonus, you may get a nice performance improvement in whole application.

FastMM is used as a default memory manager in Delphi 2006 and above. Also it's a good tool to search the memory-leaks.

dummzeuch
5#
dummzeuch Reply to 2010-07-06 09:56:08Z

Just to add a single fact:

Delphi allows you to simply assign PChar to a string so on the DLL side you don't need any typecast:

function MyDllFunction(_s: PChar): integer;
var
  s: string;
begin
  s := _s; // implicit conversion to string

  // now work with s instead of the _s parameter
end;

This also applies for passing PChar as a parameter to a function that expects a (by value) string.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.341718 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO