当作为函数参数从Delphi传递到C#时,空字符串变为null
我有一个本地Delphi exe,它通过COM互操作调用C#dll。下面是演示此问题的最简单案例: 德尔菲:当作为函数参数从Delphi传递到C#时,空字符串变为null,c#,delphi,com-interop,C#,Delphi,Com Interop,我有一个本地Delphi exe,它通过COM互操作调用C#dll。下面是演示此问题的最简单案例: 德尔菲: IClass1 = interface(IDispatch) ['{B29BAF13-E9E4-33D7-9C92-FE28416C662D}'] function Test(const aStr: WideString): WideString; safecall; end; var obj: IClass1; s: string; begin obj := Co
IClass1 = interface(IDispatch)
['{B29BAF13-E9E4-33D7-9C92-FE28416C662D}']
function Test(const aStr: WideString): WideString; safecall;
end;
var
obj: IClass1;
s: string;
begin
obj := CoClass1.Create as IClass1;
s := obj.Test(''); // Returns '[null]'
end;
C#:
当我在Delphi中使用空字符串调用方法Test时,C#部分接收null作为参数值。为什么呢?它不应该也是空字符串吗?在Delphi中,null(即nil
)和空字符串被视为等价的。因此,传递字符串的'
(或WideString
)参数在内部传递nil
-
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
procedure Foo(const S: WideString);
begin
WriteLn(Pointer(S) = nil);
end;
begin
Foo('Something'); //FALSE
Foo(''); //TRUE
ReadLn;
end.
空字符串和空字符串的等式实际上是从COM。。。因此,COM库并不是真正坚持两者之间C风格区别的地方。在Delphi中,
AnsiString
,UnicodeString
,和WideString
值在为空时由nil
指针表示。COM对字符串使用BSTR
。Delphi将BSTR
包装为WideString
。因此,无法将“空”非零字符串传递给以WideString
作为参数的COM方法,而是nil
。为什么将'
传递给WideString
参数会导致另一方接收null
?这就是Delphi表示空COMBSTR
的方式。如果确实需要传递空字符串,则需要将Delphi代码中的IClass1
更改为传递TBStr
,而不是WideString
,并使用SysAllocString
或SysAllocStringLen
创建空的TBStr
将Delphi代码中函数的声明更改为:
function Test(const aStr: TBStr): WideString; safecall;
并在需要传递空字符串时传递SysAllocStringLen(“”,0)
下面是一个完整的演示:
C#
Delphi
uses
Ole2;
type
IClass1 = interface(System.IDispatch)
function Test(const aStr: TBStr): WideString; safecall;
end;
var
EmptyBStr: TBStr;
procedure Foo(const intf: IClass1); stdcall;
begin
Writeln(intf.Test(nil));
Writeln(intf.Test(EmptyBStr));
Writeln(intf.Test(SysAllocString('foo')));
end;
exports
Foo;
begin
EmptyBStr := SysAllocStringLen('', 0);
end.
输出
[null]
[empty]
Not empty: foo
[零]
[空]
不是空的:foo
为了避免空指针的错误,您可以发送一个带有Chr(#0)或AnsiChar(#0)的空字符,而不是返回空指针的“”。
BSTR
可以为NULL,也可以为0长度的非NULL。这是Delphi,它没有区别。@ ReMyLeBeAu-当然,它可以在技术上被赋予许多COM约定,而不在(C++)中获得编译器支持。然而,代码应该(或至少应该)将null和零长度BSTR
视为等价物(请参见)是的,但正如我在回答中指出的,您并没有被迫使用WideString。我已经用接口声明更新了我的问题。我没有首先添加它,因为它是从类型库自动生成的。@Max谢谢。我的最新更新向您展示了如何传递空字符串。
uses
Ole2;
type
IClass1 = interface(System.IDispatch)
function Test(const aStr: TBStr): WideString; safecall;
end;
var
EmptyBStr: TBStr;
procedure Foo(const intf: IClass1); stdcall;
begin
Writeln(intf.Test(nil));
Writeln(intf.Test(EmptyBStr));
Writeln(intf.Test(SysAllocString('foo')));
end;
exports
Foo;
begin
EmptyBStr := SysAllocStringLen('', 0);
end.
[null]
[empty]
Not empty: foo