Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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;
like image 721
himself Avatar asked Jul 05 '10 10:07

himself


2 Answers

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.

like image 106
Mason Wheeler Avatar answered Sep 24 '22 01:09

Mason Wheeler


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;
like image 21
gabr Avatar answered Sep 23 '22 01:09

gabr