views:

353

answers:

2

We try to pass a string from a native Delphi program to a Delphi Prism DLL. We have no problem passing integers, but strings are mismatched in the DLL. We saw Robert Love's code snippet in response to another question, but there is no code for the native Delphi program.

How can we pass strings from Delphi to a Delphi Prism DLL?

+1  A: 

Strings in Delphi Win32 are managed differently from strings in .Net, so you can not pass a .Net string to Delphi Win32 or vice versa.

To exchange strings values you'd better use PChar type which is supported by both compilers. That is the same way you send string values to Windows API functions.

Regards

P.S. I am NOT Robert ;-)

vcldeveloper
Sorry, this should be an message to the author of the code snippet mentioned above. Clicked wrong Button.But anyway, how does it work to use PChar. Delphi prism does not have a PChar type. if i use pchar in native delphi and string in prism, i get the first char right. But only one char.How to fix this?
Markus Steinhilber
Don't worry, Marcus. You don't have enough reputation points yet, so you wouldn't have been able to post a commend at someone else's question anyway. It's a legitimate question. I've edited it for you so it doesn't look like you're trying to send a direct message, which Stack Overflow doesn't support.
Rob Kennedy
PChar is simply a pointer to a character, to send a string like that you need to first point to the first character, and second, specify the length of string data, so that the other end can read data from the start point up to the length of string.If your DLL function is returning any string value, then the other end should provide a memory space, and send its starting address and its length to your function so that your function can write the output data into that memory space.
vcldeveloper
How do i read from a pointer position to a specified length in prism? I dont know any method to do this. And what datatype do i use in prism. When using Pointer class and want to get the value, its always shown as pointer to void.
Markus Steinhilber
+6  A: 

The best way would be to use WideString.

For several reasons.

  • It is Unicode and works before D2009
  • It's memory is managed in ole32.dll, so no dependency on either Delphi's memory manager or the CLR GC.
  • You do not have to directly deal with pointers

In Oxygene, you could write it like so:

type
  Sample = static class
  private
    [UnmanagedExport]
    method StringTest([MarshalAs(UnmanagedType.BStr)]input : String;
                      [MarshalAs(UnmanagedType.BStr)]out output : String);
  end;

implementation

method Sample.StringTest(input : String; out output : String);
begin
  output := input + "ä ~ î 暗";
end;

"MarshalAs" tells the CLR how to marshal strings back and forth. Without it, strings are passed as Ansi (PAnsiChar), which is probably NOT what you would want to do.

This is how to use it from Delphi:

procedure StringTest(const input : WideString; out output : WideString);
  stdcall; external 'OxygeneLib';

var
  input, output : WideString;
begin
  input := 'A b c';
  StringTest(input, output);
  Writeln(output);
end.

Also, never ever use types, that are not clearly defined, for external interfaces. You must not use PChar for DLL imports or exports. Because if you do, you will run into exceptions when you compile it with D7 or D2009 (depending on what the original dev system was)

Robert Giesecke