I am completely new to Delphi and have been trying to make a few DLLs for .NET.
What I want to achieve is to send and receive txt output from my DLLs.
Here's what I've done so far:
Delphi Library function:
function DBConnet(inputStr: PChar; connStr: PChar): PAnsiChar; stdcall; export;
var
conStr: string;
s: string;
begin
inputStr := PChar('Hello from Delphi! How are you ' + inputStr + connStr);
try
Result := PAnsiChar(inputStr);
except
on e: Exception do
begin
Result := 'exception';
end;
end;
end;
Exports
DBConnet;
end.
Here's my caller function in Delphi:
function DBConnet(inputStr: PChar; connStr: PChar): PChar; stdcall; external 'NewLib.dll';
procedure TUseDLLForm.functionxClick(Sender: TObject);
var
a: string;
conStr: string;
i: integer;
begin
a := 'firstname';
conStr := 'lastname';
ShowMessage(DBConnet(pchar(a), pchar(conStr)));
end;
This works fine with Delphi to Delphi. But when I try to call it from C#, the output received is null.
Here's my C# code block:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
public static extern void DBConnet(string inputString, string
connectionString, [MarshalAs(UnmanagedType.BStr)] out string dbStrObj);
And then in Main I call it this way:
DBConnet(inputString, connectionString, out dbStrObj);
The DLL code you have shown is NOT compatible with your C# code.
Your C# code is relying on default
string
marshaling behavior that your DLL is not conforming to.A
string
is passed to a DLL as aPWideChar
pointer by default (if you are using Delphi 2009+,PChar
maps toPWideChar
, otherwise it maps toPAnsiChar
instead).Also, your DLL function is returning a
PAnsiChar
, but the marshaller is expecting aPWideChar
by default, since you did not apply a[return: MarshalAs(UnmanagedType.LPStr)]
attribute on the DLL function declaration on the C# side.But more importantly, when a DLL returns a pointer to memory that the marshaller then takes ownership of, the memory MUST be allocated with
CoTaskMemAlloc()
or equivalent, as the marshaller frees the memory withCoTaskMemFree()
by default (see Memory management with the interop marshaler).You are returning a pointer to dynamically allocated memory, however that memory is not allocated with
CoTaskMemAlloc()
. In fact, the memory is actually managed by the Delphi compiler and gets freed automatically when the function exits. So, you are actually returning an invalid pointer to C#.In fact, you are not even returning the pointer to C#! On the C# side, you have declared the DLL as having an
out
parameter, but there is no such parameter on the DLL side!With all of that said, try something more like this instead:
DLL:
Delphi app:
C#:
Or, using an
out
parameter instead:DLL:
Delphi app:
C#:
Alternatively, you can allocate the returned memory as a
BSTR
string instead of usingCoTaskMemAlloc()
, just be sure to marshal it as aBSTR
on the C# side:DLL:
Delphi app:
C#:
Or, using an
out
parameter:DLL:
Delphi app:
C#: