您显示的 DLL 代码与您的 C# 代码不兼容。
您的 C# 代码依赖于您的 DLL 不符合的默认string
封送处理行为。
默认情况下, Astring
作为PWideChar
指针传递给 DLL(如果您使用的是 Delphi 2009+,则PChar
映射到PWideChar
,否则它会映射到PAnsiChar
)。
此外,您的 DLL 函数返回 a PAnsiChar
,但编组器PWideChar
默认期望 a ,因为您没有[return: MarshalAs(UnmanagedType.LPStr)]
在 C# 端的 DLL 函数声明上应用属性。
但更重要的是,当 DLL 返回指向内存的指针时,编组器将拥有该内存的所有权,内存必须分配CoTaskMemAlloc()
或等效,因为编组器默认释放内存CoTaskMemFree()
(请参阅使用互操作编组器进行内存管理)。
您正在返回一个指向动态分配内存的指针,但是该内存不是用CoTaskMemAlloc()
. 事实上,内存实际上由 Delphi 编译器管理,并在函数退出时自动释放。因此,您实际上是在返回一个指向 C# 的无效指针。
事实上,您甚至没有返回指向 C# 的指针!在 C# 端,您已将 DLL 声明为具有out
参数,但在 DLL 端没有这样的参数!
综上所述,尝试更多类似的东西:
动态链接库:
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
function UnicodeStringToCoTaskMemStr(const s: UnicodeString): PWideChar;
var
Size: Integer;
begin
Size := (Length(s) + 1) * SizeOf(WideChar);
Result := PWideChar(CoTaskMemAlloc(Size));
if Result <> nil then
Move(PWideChar(s)^, Result^, Size);
end;
function DBConnet(inputStr: PWideChar; connStr: PWideChar): PWideChar; stdcall; export;
var
sInput: UnicodeString;
sConn: UnicodeString;
begin
try
sInput := inputStr;
sConn := connStr;
Result := UnicodeStringToCoTaskMemStr('Hello from Delphi! How are you ' + sInput + sConn);
except
Result := UnicodeStringToCoTaskMemStr('exception');
end;
end;
德尔福应用程序:
function DBConnet(inputStr: PWideChar; connStr: PWideChar): PWideChar; stdcall; external 'NewLib.dll';
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
procedure TUseDLLForm.functionxClick(Sender: TObject);
var
a: UnicodeString;
conStr: UnicodeString;
ret: PWideChar;
begin
a := 'firstname';
conStr := 'lastname';
ret := DBConnet(PWideChar(a), PWideChar(conStr));
if ret <> nil then
begin
try
ShowMessage(ret);
finally
CoTaskMemFree(ret);
end;
end else
ShowMessage('nil');
end;
C#:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string DBConnet(string inputString, string connectionString);
或者,改为使用out
参数:
动态链接库:
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
function UnicodeStringToCoTaskMemStr(const s: UnicodeString): PWideChar;
var
Size: Integer;
begin
Size := (Length(s) + 1) * SizeOf(WideChar);
Result := PWideChar(CoTaskMemAlloc(Size));
if Result <> nil then
Move(PWideChar(s)^, Result^, Size);
end;
function DBConnet(inputStr: PWideChar; connStr: PWideChar; out outputStr: PWideChar): boolean; stdcall; export;
var
sInput: UnicodeString;
sConn: UnicodeString;
begin
Result := False;
try
sInput := inputStr;
sConn := connStr;
outputStr := UnicodeStringToCoTaskMemStr('Hello from Delphi! How are you ' + sInput + sConn);
Result := outputStr <> nil;
except
end;
end;
德尔福应用程序:
function DBConnet(inputStr: PWideChar; connStr: PWideChar, out outputStr: PWideChar): boolean; stdcall; external 'NewLib.dll';
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
procedure TUseDLLForm.functionxClick(Sender: TObject);
var
a: UnicodeString;
conStr: UnicodeString;
ret: PWideChar;
begin
a := 'firstname';
conStr := 'lastname';
if DBConnet(PWideChar(a), PWideChar(conStr), ret) then
begin
try
ShowMessage(ret);
finally
CoTaskMemFree(ret);
end;
end else
ShowMessage('fail');
end;
C#:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool DBConnet(string inputString, string connectionString,
[MarshalAs(UnmanagedType.LPWStr)] out outputString string);
或者,您可以将返回的内存分配为BSTR
字符串而不是 using ,只需确保在 C# 端CoTaskMemAlloc()
将其编组为 a :BSTR
动态链接库:
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
function DBConnet(inputStr: PWideChar; connStr: PWideChar): PWideChar; stdcall; export;
var
sInput: UnicodeString;
sConn: UnicodeString;
begin
try
sInput := inputStr;
sConn := connStr;
// the RTL's StringToOleStr() function returns a BSTR...
Result := StringToOleStr('Hello from Delphi! How are you ' + sInput + sConn);
except
Result := StringToOleStr('exception');
end;
end;
德尔福应用程序:
function DBConnet(inputStr: PWideChar; connStr: PWideChar): PWideChar; stdcall; external 'NewLib.dll';
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
procedure TUseDLLForm.functionxClick(Sender: TObject);
var
a: UnicodeString;
conStr: UnicodeString;
ret: WideString; // NOT UnicodeString!
begin
a := 'firstname';
conStr := 'lastname';
Pointer(ret) := DBConnet(PWideChar(a), PWideChar(conStr));
if ret <> '' then
ShowMessage(ret)
else
ShowMessage('nil');
end;
C#:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string DBConnet(string inputString, string connectionString);
或者,使用out
参数:
动态链接库:
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
function DBConnet(inputStr: PWideChar; connStr: PWideChar; out outputStr: WideString): boolean; stdcall; export;
var
sInput: UnicodeString;
sConn: UnicodeString;
begin
Result := False;
try
sInput := inputStr;
sConn := connStr;
outputStr := 'Hello from Delphi! How are you ' + sInput + sConn;
Result := True;
except
end;
end;
德尔福应用程序:
function DBConnet(inputStr: PWideChar; connStr: PWideChar; out outputStr: WideString): boolean; stdcall; external 'NewLib.dll';
// uncomment this if you are NOT using D2009+ ...
{
type
UnicodeString = WideString;
}
procedure TUseDLLForm.functionxClick(Sender: TObject);
var
a: UnicodeString;
conStr: UnicodeString;
ret: WideString;
begin
a := 'firstname';
conStr := 'lastname';
if DBConnet(PWideChar(a), PWideChar(conStr), ret) then
ShowMessage(ret)
else
ShowMessage('fail');
end;
C#:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool DBConnet(string inputString, string connectionString,
[MarshalAs(UnmanagedType.BStr)] out string outputStr);