- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 Delphi 的新手,一直在尝试为 .NET 制作一些 DLL。
我想要实现的是从我的 DLL 发送和接收 txt 输出。
这是我到目前为止所做的:
Delphi 库函数:
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.
这是我在 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;
这适用于 Delphi to Delphi。但是当我尝试从 C# 调用它时,收到的输出为空。
这是我的 C# 代码块:
[DllImport("NewLib.dll",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode)]
public static extern void DBConnet(string inputString, string
connectionString, [MarshalAs(UnmanagedType.BStr)] out string dbStrObj);
然后在 Main 中我这样调用它:
DBConnet(inputString, connectionString, out dbStrObj);
最佳答案
您显示的 DLL 代码与您的 C# 代码不兼容。
您的 C# 代码依赖于 default string
marshaling behavior你的 DLL 不符合。
string
默认作为 PWideChar
指针传递给 DLL(如果您使用的是 Delphi 2009+,PChar
映射到 PWideChar
,否则它映射到 PAnsiChar
。
此外,您的 DLL 函数正在返回一个 PAnsiChar
,但编码器默认需要一个 PWideChar
,因为您没有应用 [return: MarshalAs (UnmanagedType.LPStr)]
C# 端 DLL 函数声明的属性。
但更重要的是,当 DLL 返回指向内存的指针时,编码器随后会获得所有权,必须使用 CoTaskMemAlloc()
或等价物分配内存,因为编码器使用 CoTaskMemFree()
默认情况下(参见 Memory management with the interop marshaler )。
您正在返回指向动态分配内存的指针,但是该内存不是使用 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
字符串而不是使用 CoTaskMemAlloc()
,只需确保将其编码为 BSTR
在 C# 端:
动态链接库:
// 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);
关于c# - 将字符串从 Delphi 传递到 C# 返回 null。但是,当我从 Delphi 调用 Delphi 库时,它工作正常。如何从Delphi接收字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53529623/
我是一名优秀的程序员,十分优秀!