3

I have searched a lot about this issue, and there is no clear answer about how to pass a string from delphi dll to .NET Next code is based on msdn help files: http://msdn.microsoft.com/en-us/library/4zey12w5.aspx

//Delphi code

function myDelphiFunc(var Buffer: PChar): Integer; export; stdcall;
  Buffer:='this is a test';
  Return:=0;
end;

//vb.NET code

<DllImport(path)> _
Public Function myDelphiFunc(ByVal buffer As String) As Integer

Public Sub myNETFunc()
  Dim buffer_size As integer = 25
  Dim buffer As String = New String(CChar(" "), buffer_size )
  Call myDelphiFunc(buffer)
  MsgBox(Strings.Left(buffer, InStr(buffer, Chr(0)) - 1))
End Sub

I receive an empty string in "buffer" variable when calling myDelphiFunc. What am I doing wrong?

Thanks in advance

1
  • It´s strange to me that you have a var parameter for the string you´r trying to return. I know nothing about VB, but it seems to me that you already have the buffer allocated, so no need to return a new char pointer from your Delphi DLL. However, I decided to not question your design and posted an answer compatible with you current Delphi code. Commented Jul 22, 2013 at 13:51

2 Answers 2

10

There's lots wrong with your code. The main faults are:

  • The Delphi function receives a pointer by reference, but the VB code passes it by value.
  • The Delphi code would need to copy the string into the buffer provided.
  • The Delphi code should use PAnsiChar to match the VB. Or PWideChar and CharSet.Unicode on the p/invoke.
  • The VB code needs to use StringBuilder rather than String in order for the string to be marshalled back to the caller.
  • The function would need to accept a length parameter in order to avoid buffer overruns.

However, I'm not sure it's worth trying to understand it in too much depth. The simplest way to do this is to use a BSTR which is allocated on the shared COM heap. This makes the function much easier to use and hides all the memory allocation complexity.

Delphi

procedure TestFunc(out str: WideString); stdcall;
begin
  str := 'foo';
end;

VB

<DllImport(path)> _ 
Public Sub TestFunc(<MarshalAs(UnmanagedType.BStr)> ByRef str As String)
Sign up to request clarification or add additional context in comments.

4 Comments

+1 better yet, if your .NET application needs to interact with the dll a lot implement your dll as a com server and take advantage of the extensive interop support both Delphi and .NET provide.
This is great information. I have a set of Delphi code that I want to make available to .NET. Any hints what to read first?
+1 Thanks David Heffernan. My application is now working perfectly. I hope this simple code could help other programmers.
@LeonardoHerrera You can start here for Delphi and here for .NET.
0

Your code should be replaced by

function myDelphiFunc(var Buffer: PChar): Integer; export; stdcall;
const
  tmp = 'this is a test';
begin
  Buffer := StrAlloc(Lenght(tmp)+1);
  StrPCopy(Buffer, PChar(tmp));
  Return:=0;
end;

4 Comments

Nope. That won't work. Need to remove var in Delphi. Need to use PAnsiChar. Need to use StringBuilder on .net side. And on the Delphi side you'd need to copy into the provided buffer. The use of export is needless on Delphi side.
@DavidHeffernan why AnsiChar when CLR is UTF-16 based ? and how should CLR pass to Delphi buffer len if using P*Char ?
@Arioch Default marshalling for p/invoke is ANSI. Use CharSet.Unicode for UTF16. Buffer length would need an extra param. As per GetWindowText for example. Look that up on pinvoke.net.
Thanks AlexSC, finally I used the solution of David Hofferman.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.