COM服务器发送空字符串,该字符串被转换为NULL指针

本文关键字:字符串 转换 指针 NULL 服务器 COM | 更新日期: 2023-09-27 18:29:40

我在C#中为COM服务器定义了这个接口:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("58C77969-0E7D-3778-9999-B7716E4E1111")]
public interface IMyInterface    
{
    string MyName { get; }
}

该接口在DelphiXE5程序中导入并实现。

导入看起来像这样:

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来替换?

COM服务器发送空字符串,该字符串被转换为NULL指针

Delphi将空字符串实现为零指针(请参阅System._NewUnicodeString)。您可以手动分配一个空的COM兼容字符串:

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封送为零指针,而不是一个空BSTR。在我看来,这是一个缺陷。