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

戏子无情 提交于 2019-12-19 02:47:07

问题


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;

回答1:


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.




回答2:


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;



回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/3178868/is-it-safe-to-pass-delphi-const-string-params-across-memory-manager-boundaries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!