You clearly have a mismatch between the p/invoke code and the Delphi code. You have not shown the Delphi code but the C# code is enough to know what the Delphi code should look like.
Your DllImport
attribute uses default values for calling convention and character set. This means that the calling convention is stdcall
and the character set is ANSI. You have not specified any marshalling attributes so default marshalling must be used.
Therefore your Delphi code must look like this:
function MyMethod(someStringParam: PChar): PChar; stdcall;
begin
Result := ??;
end;
And now here's the problem. The p/invoke marshaller treats a string
return value in a very special way. It assumes that it is the responsibility of the p/invoke marshaller to deallocate the return value's memory. And it has to use the same allocator as the native code. The assumption made by the marshaller is that the shared COM allocator will be used.
So the rule is that the native code must allocate the memory with the COM allocator by calling CoTaskMemAlloc
. My bet is that your code does not do that and that will certainly result in errors.
Here is an example of how you could make a native Delphi function that works with the C# signature in your code.
function MyMethod(someStringParam: PChar): PChar; stdcall;
var
Size: Integer;
begin
Size := SizeOf(Char)*(StrLen(someStringParam)+1);//+1 for zero-terminator
Result := CoTaskMemAlloc(Size);
Move(someStringParam^, Result^, Size);
end;
Whilst you could adopt this approach I recommend an alternative. Marshal all your strings as BSTR
on the C# side and WideString
on the Delphi side. These are matching types which are also allocated by the COM allocator. Both parties know exactly what to do with these types and will make your life easier.
Unfortunately, you cannot return a WideString
from a Delphi function across an interop boundary because Delphi uses a different ABI for function return values. More details of this issue can be found in my question Why can a WideString not be used as a function return value for interop?
So to work around that, we can declare the return type from the Delphi code to be TBStr
. Your code would then look like this:
C#
[DllImport(@"MyDll.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string MyMethod(
[MarshalAs(UnmanagedType.BStr)]
string someStringParam
);
Delphi
function MyMethod(someStringParam: WideString): TBStr; stdcall;
begin
Result := SysAllocString(POleStr(someStringParam));
end;