I am trying to call a method in a Delphi DLL with the following signature:
function SMap4Ovr(const OverFileName : ShortString ;
When writing interop code it is critical that both sides of the interface match in every way. Here are the main issues that you must make agree on both sides:
The first observation is that your calling conventions do not match. You have register
on the Delphi side and stdcall
on the C# side. The Delphi register
convention is private to Delphi and so you should use stdcall
.
Secondly, your string parameter types do not match. The Delphi shortstring
is a data type that became legacy when Delphi 2 was released and should be considered a relic from the previous century. It was never a valid interop type, and there's nothing in the p/invoke framework that can be used to match it. Whilst you could attempt to do the marshalling by hand, this is a lot of work that is simply not needed when there are simple solutions available. You should try to forget all about shortstring
.
You need to use a string type that both sides of the interface can work with. You could use null-terminated C strings, but a better and simpler choice is the COM BSTR
which is WideString
in Delphi.
So, the final result is as follows.
Delphi
function SMap4Ovr(
OverFileName: WideString;
Aclay: Integer;
Acarbon: Double;
out errstr: WideString
): WordBool; stdcall;
C#
[DllImport("SMap.dll")]
public static extern bool SMap4Ovr(
[MarshalAs(UnmanagedType.BStr)]
string OverFileName,
int Aclay,
double Acarbon,
[MarshalAs(UnmanagedType.BStr)]
out string errstr
);
I did not bother specifying the calling convention on the DllImport
since the default is stdcall
. If you prefer you can be explicit about this.
Be careful when using WideString
that you don't attempt to use it as a return value. Because Delphi uses non-standard semantics for return values, you can only use simple types that fit into a register as return values.