Returning a string from delphi dll to C# caller in 64 bit

后端 未结 1 615
耶瑟儿~
耶瑟儿~ 2021-01-02 22:50

I have a C# application which calls native Delphi dll using the following code:

C#

[DllImport(\"NativeDLL.dll\", CharSet = CharSet.U         


        
1条回答
  •  囚心锁ツ
    2021-01-02 23:34

    You cannot pass a string from native managed that way. Your code is wrong in 32 bit also, you just happen to get away with it. The second version of the code is also wrong. It only appears to work.

    You need to either:

    1. Allocate from a shared heap so that that the managed code can deallocate off that heap. The shared heap for p/invoke is the COM heap.
    2. Allocate the memory on the managed side, and copy the contents into that buffer on the native side.

    Option 2 is always preferable. It looks like this:

    [DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int GetString(StringBuilder str, int len);
    

    On the native side you would have

    function GetString(str: PChar; len: Integer): Integer; stdcall;
    begin
      StrLCopy(str, 'abc', len);
      Result := 1; // real code would have real error handling
    end;
    

    Then call this like so:

    StringBuilder str = new StringBuilder(256);
    int retval = GetString(str, str.Capacity);
    

    If you want to try option 1, it looks like this on the managed side:

    [DllImport("NativeDLL.dll", CharSet = CharSet.Unicode)]
    public static extern int GetString(out string str);
    

    and like this native:

    function GetString(out str: PChar): Integer; stdcall;
    begin
      str = CoTaskMemAlloc(SizeOf(Char)*(Length('abc')+1));
      StrCopy(str, 'abc');
      Result := 1; // real code would have real error handling
    end;
    

    When the managed code copies the contents of str to the string value, it then calls CoTaskMemFree on the pointer that you returned.

    And this is trivially easy to call:

    string str;
    int retval = GetString(out str);
    

    0 讨论(0)
提交回复
热议问题