COM 服务器发送空字符串,该字符串被转换为 NULL 指针
COM Server sends empty string which is converted to a NULL pointer
我在 C# 中为 COM 服务器定义了这个接口:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("58C77969-0E7D-3778-9999-B7716E4E1111")]
public interface IMyInterface
{
string MyName { get; }
}
此接口是在Delphi XE5 程序中导入和实现的。
导入看起来像这样:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName (out pRetVal: WideString): HResult; stdcall;
end;
这样的实现:
type
TMyImpl = class(TInterfacedObject, IMyInterface)
public
function Get_MyName (out pRetVal: WideString): HResult; stdcall;
end;
function TMyImpl.Get_MyName (out pRetVal: WideString): HResult;
var
s: string;
begin
s:=''; // empty!
pRetVal:=s;
result:=S_OK;
end;
当我像这样从 c# 调用该服务器时:
var server = new Server();
string s = server.MyName;
那么 s 是 NULL 而不是例外的空字符串。
我如何强制将空字符串作为空字符串在 COM 中传输,而不是通过编组为 NULL 来替换?
Delphi 将空字符串实现为 nil 指针(参见 System._NewUnicodeString
)。您可以手动分配一个空 COM-compatible 字符串:
function TMyImpl.Get_MyName(out pRetVal: WideString): HResult;
var
BStr: TBstr;
begin
BStr := SysAllocString('');
if Assigned(BStr) then
begin
Pointer(pRetVal) := BStr;
Result := S_OK;
end
else
Result := E_FAIL;
end;
或者您可以创建一个辅助函数:
function EmptyWideString: WideString;
begin
Pointer(Result) := SysAllocString('');
end;
在 Delphi 端试试这个:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName (out pRetVal: BSTR): HResult; stdcall;
end;
function TMyImpl.Get_MyName (out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := S_OK;
end;
如果你想处理 SysAllocString
失败的情况,那么你可以这样写:
function TMyImpl.Get_MyName (out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := IfThen(Assigned(pRetVal), S_OK, E_FAIL);
end;
尽管我个人认为在检查调用 SysAllocString('')
时划清界线是合理的。
我的猜测是 Delphi 将空的 WideString
编组为 nil 指针而不是空的 BSTR
。我认为这是一个缺陷。
我在 C# 中为 COM 服务器定义了这个接口:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("58C77969-0E7D-3778-9999-B7716E4E1111")]
public interface IMyInterface
{
string MyName { get; }
}
此接口是在Delphi XE5 程序中导入和实现的。
导入看起来像这样:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName (out pRetVal: WideString): HResult; stdcall;
end;
这样的实现:
type
TMyImpl = class(TInterfacedObject, IMyInterface)
public
function Get_MyName (out pRetVal: WideString): HResult; stdcall;
end;
function TMyImpl.Get_MyName (out pRetVal: WideString): HResult;
var
s: string;
begin
s:=''; // empty!
pRetVal:=s;
result:=S_OK;
end;
当我像这样从 c# 调用该服务器时:
var server = new Server();
string s = server.MyName;
那么 s 是 NULL 而不是例外的空字符串。
我如何强制将空字符串作为空字符串在 COM 中传输,而不是通过编组为 NULL 来替换?
Delphi 将空字符串实现为 nil 指针(参见 System._NewUnicodeString
)。您可以手动分配一个空 COM-compatible 字符串:
function TMyImpl.Get_MyName(out pRetVal: WideString): HResult;
var
BStr: TBstr;
begin
BStr := SysAllocString('');
if Assigned(BStr) then
begin
Pointer(pRetVal) := BStr;
Result := S_OK;
end
else
Result := E_FAIL;
end;
或者您可以创建一个辅助函数:
function EmptyWideString: WideString;
begin
Pointer(Result) := SysAllocString('');
end;
在 Delphi 端试试这个:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName (out pRetVal: BSTR): HResult; stdcall;
end;
function TMyImpl.Get_MyName (out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := S_OK;
end;
如果你想处理 SysAllocString
失败的情况,那么你可以这样写:
function TMyImpl.Get_MyName (out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := IfThen(Assigned(pRetVal), S_OK, E_FAIL);
end;
尽管我个人认为在检查调用 SysAllocString('')
时划清界线是合理的。
我的猜测是 Delphi 将空的 WideString
编组为 nil 指针而不是空的 BSTR
。我认为这是一个缺陷。