首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从Delphi中传递PChar

从Delphi中传递PChar
EN

Stack Overflow用户
提问于 2015-10-30 10:21:23
回答 1查看 2.9K关注 0票数 2

我如何从DLL中传递pchar?dll必须与其他应用程序兼容,而不仅仅是delphi。在“帮助”中,传递指向局部变量的指针是危险的,如果我们将该变量设置为全局变量,则代码将不会是线程安全的。

我们可以安全地传递一个宽字符串,但是在这种情况下,dll将不能与其他(非Delphi)应用程序兼容。

代码语言:javascript
复制
{code in dll}
       function Test:pchar;
        var
          str:string;
        begin
           str:='Some string';
           result:=pchar(str); // wrong way, may be UB. 
        end;


        {code in dll}

        var
          str:string // global variable

        function Test:pchar;
        begin
          str:='Some string';
          result:=pchar(str); // code not threadsafe
        end;

        {code in dll}
        function Test:WideString;
        var
          str:WideString;
        begin
           str:='Some string';
           result:=str; // will works ONLY with Delphi apps :( 
        end;

:(

how do experienced programmers?



var
  Form1: TForm1;
  function Test(out p:pchar):Integer;stdcall; external 'project2';
  procedure FinalizeStr(P:Pointer);stdcall; external 'project2';

implementation

{$R *.dfm}

function StrFromDll:string;
var
  p:pchar;
begin
  try
    setstring(result,P, test(p));
  finally
    finalizestr(cardinal(p));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  showmessage(strfromdll);
end;


{code in dll}


library Project2;

uses
  fastmm4,fastmm4messages,
  SysUtils,
  Classes;

{$R *.res}

function Test(out p:pchar):Integer;stdcall;
var
  str:string;
  len:integer;
begin
  str:='Hello, i am a string from the dll?!#@%!?'+inttostr(hinstance);  // only for example
  len:=length(str);
  p:=allocmem(len+1);
  StrPLCopy(P,str,len);
  result:=len;
end;

procedure FinalizeStr(P:Pointer);stdcall;
begin
  FreeMem(P);
end;

exports Test,FinalizeStr;
end.
EN

回答 1

Stack Overflow用户

发布于 2015-10-30 10:40:16

你有三个主要选择。

让调用方分配被调用方填充的内存。

代码语言:javascript
复制
function GetString(Buffer: PWideChar; BufferLen: Integer): Integer; stdcall;

调用方必须知道要分配多少内存。您可以通过安排函数返回复制的字符数,或者,如果Buffernil,则返回所需的缓冲区大小。因此调用方可以这样调用这个函数:

代码语言:javascript
复制
var
  str: string;
....
SetLength(str, GetString(nil, 0) - 1);
GetString(PChar(str), Length(str) + 1);

-1+1将处理空终止符.

拥有被调用的分配内存,并导出一个释放程序

看起来是这样的:

代码语言:javascript
复制
function GetString: PWideChar; stdcall;
function Free(P: Pointer); stdcall;

被调用者从其内部堆中分配内存。但是被调用者还必须导出一个释放内存的函数。调用序列如下所示:

代码语言:javascript
复制
var
  P: PWideChar;    
  str: string;
....
P := GetString();
str := P;
Free(P);

这方面的一个转折是将共享堆分配出去,例如COM堆。这样,您就不需要导出一个释放程序,因为调用者可以在没有帮助的情况下获得COM堆释放器。

返回COM字符串

COM BSTR是从共享COM堆中分配的,任何Windows开发环境都可以使用这些对象。Delphi将这些包装为WideString。不过,Delphi与其他工具不同,您不能使用WideString作为函数、返回值和与其他工具的互操作。相反,应该使用out参数。

代码语言:javascript
复制
procedure GetString(out str: WideString); stdcall;

这里有更多详细信息:Why can a WideString not be used as a function return value for interop?

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33433669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档