gpt4 book ai didi

c# - 将字符串从 Delphi 传递到 C# 返回 null。但是,当我从 Delphi 调用 Delphi 库时,它工作正常。如何从Delphi接收字符串

转载 作者:行者123 更新时间:2023-11-30 19:35:37 26 4
gpt4 key购买 nike

我是 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com