You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# COM客户端从Delphi COM服务器读取值异常问题排查

问题原因及解决方案

核心问题根源

1. Double返回NaN的原因

Delphi的safecall调用约定会自动将带返回值的函数转换为COM标准签名:返回HRESULT错误码,原返回值作为最后一个[out, retval]参数传递。但如果直接声明safecall函数返回Double,会出现调用约定冲突:safecall要求用EAX寄存器返回HRESULT(整数类型),而浮点返回值本应放在FPU栈,这种冲突导致.NET客户端读取到错误的浮点值(NaN)。

2. String调用崩溃的原因

同样是safecall调用约定的冲突:直接返回String违反了COM方法需返回HRESULT的标准。此外,Delphi的String虽与COM的BSTR兼容,但如果未通过[out, retval]参数传递,会导致.NET客户端读取无效内存,直接触发崩溃(无异常提示,返回非0退出码)。

修复步骤

1. 调整Delphi COM服务器的方法签名

将所有带返回值的方法改为遵循COM标准:返回HRESULT,原返回值作为[out, retval]参数传递。示例代码如下:

// 接口声明
type
  ITest = interface(IDispatch)
    ['{你的接口GUID}']
    function EchoInt(Value: Integer; out Result: Integer): HResult; safecall;
    function EchoDouble(Value: Double; out Result: Double): HResult; safecall;
    function EchoString(const Value: WideString; out Result: WideString): HResult; safecall;
  end;

// 类实现
TTest = class(TAutoObject, ITest)
public
  function EchoInt(Value: Integer; out Result: Integer): HResult; safecall;
  function EchoDouble(Value: Double; out Result: Double): HResult; safecall;
  function EchoString(const Value: WideString; out Result: WideString): HResult; safecall;
end;

// 方法实现
function TTest.EchoInt(Value: Integer; out Result: Integer): HResult;
begin
  Writeln('EchoInt received: ', Value);
  Result := Value;
  Result := S_OK;
end;

function TTest.EchoDouble(Value: Double; out Result: Double): HResult;
begin
  Writeln('EchoDouble received: ', Value);
  Result := Value;
  Result := S_OK;
end;

function TTest.EchoString(const Value: WideString; out Result: WideString): HResult;
begin
  Writeln('EchoString received: ', Value);
  Result := Value;
  Result := S_OK;
end;

2. 更新.NET客户端引用

  • 重新编译Delphi ActiveX库,生成新的类型库(TLB文件)。
  • 在.NET 6客户端中删除旧的COM引用,重新添加新的TLB引用;或使用tlbimp.exe工具重新生成互操作程序集:
tlbimp.exe YourComServer.tlb /out:Interop.YourComServer.dll

3. 验证字符串内存管理

确保Delphi中使用WideString作为字符串参数和返回值类型,Delphi会自动处理BSTR的内存分配与释放,无需手动调用SysAllocString等API。

补充说明

无论是进程内/进程外COM,还是32位/64位环境,问题本质都是COM方法签名不遵循标准导致的跨语言互操作冲突。调整为标准COM签名后,所有类型的返回值都能被.NET客户端正确解析。

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 23:40:33