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

Delphi通过JCL向C#传接口抛异常,捕获后显示0x8000FFFF求助

Delphi通过JCL传递接口给C#时异常返回0x8000FFFF的问题排查

我希望捕获Delphi端通过JCL以接口形式传递给C#库的异常。目前异常虽能被捕获,但返回错误码0x8000FFFF(E_UNEXPECTED),请问哪里操作有误?

Delphi代码

unit TestClass;

interface

uses
  SysUtils,
  JcLDotNet;

type
  ITestService = interface['{7B07D16A-72AE-4DD3-8959-B1EC6C6241B7}']
    procedure Call(); safecall;
  end;

  TTestService = class(TInterfacedObject, ITestService)
    procedure Call(); safecall;
  end;

  TSimpleClass = class
    FHost : TJclClrHost;
    FCSharp: OleVariant;
    constructor Create();
    procedure Call();
  end;

implementation


procedure TSimpleClass.Call;
begin
  FCSharp.Call;
end;

constructor TSimpleClass.Create();
var
  testService : TTestService;
begin
  FHost := TJclClrHost.Create('v4.0.30319');
  FHost.Start;
  FCSharp := FHost.DefaultAppDomain.CreateInstance('CSharpLibrary','CSharpLibrary.TestClass').Unwrap;
  //
  testService := TTestService.Create();
  FCSharp.SetService(ITestService(IUnknown(testService)));
end;

procedure TTestService.Call();
begin
  raise Exception.Create('throw exception');
end;

end.

C#代码

using System;
using System.Runtime.InteropServices;

namespace CSharpLibrary
{
    [ComVisible(true)]
    [Guid("7B07D16A-72AE-4DD3-8959-B1EC6C6241B7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ITestService
    {
        void Call();
    }

    public class TestClass
    {
        private ITestService _testService;

        public void SetService(ITestService testService)
        {
            _testService = testService;
        }

        void Call()
        {
            try
            {
                _testService.Call();
            }
            catch(Exception e)
            {
                // error: 0x8000FFFF E_UNEXPECTED
                Console.WriteLine(e.Message);  
                throw;
            }
        }
    }
}

问题原因及修复方案

核心问题点

  1. 调用约定不匹配:Delphi接口方法用safecall(对应COM的HRESULT返回机制),但C#接口未配置对应的异常映射规则,导致.NET无法解析Delphi抛出的异常,返回通用的E_UNEXPECTED。
  2. 方法访问权限错误:C#中Call方法为私有,Delphi通过OleVariant无法调用私有方法,触发隐式错误干扰异常传递。

具体修改步骤

Delphi端:实现COM错误信息支持接口

引入ActiveX单元,让TTestService实现ISupportErrorInfo接口,确保异常详情能正确传递给C#:

uses
  SysUtils,
  JcLDotNet,
  ActiveX; // 添加ActiveX引用

type
  ITestService = interface['{7B07D16A-72AE-4DD3-8959-B1EC6C6241B7}']
    procedure Call(); safecall;
  end;

  TTestService = class(TInterfacedObject, ITestService, ISupportErrorInfo)
    procedure Call(); safecall;
    function InterfaceSupportsErrorInfo(const riid: TGUID): HResult; stdcall;
  end;

// 实现ISupportErrorInfo方法
function TTestService.InterfaceSupportsErrorInfo(const riid: TGUID): HResult;
begin
  if IsEqualGUID(riid, ITestService) then
    Result := S_OK
  else
    Result := S_FALSE;
end;

procedure TTestService.Call();
var
  E: Exception;
begin
  E := Exception.Create('throw exception');
  E.ErrorCode := $80004005; // 指定标准错误码E_FAIL,可选但推荐
  raise E;
end;

C#端:匹配调用约定并修正权限

  • 给接口方法加[PreserveSig(false)],让.NET自动将COM HRESULT转换为.NET异常
  • 将Call方法改为public,确保Delphi能正常调用
using System;
using System.Runtime.InteropServices;

namespace CSharpLibrary
{
    [ComVisible(true)]
    [Guid("7B07D16A-72AE-4DD3-8959-B1EC6C6241B7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ITestService
    {
        [PreserveSig(false)] // 关键:启用HRESULT到.NET异常的自动转换
        void Call();
    }

    public class TestClass
    {
        private ITestService _testService;

        public void SetService(ITestService testService)
        {
            _testService = testService;
        }

        public void Call() // 修改为public
        {
            try
            {
                _testService.Call();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);  
                throw;
            }
        }
    }
}

总结

  • safecall与PreserveSig(false)是跨COM传递异常的关键配对,确保Delphi异常能被.NET正确解析
  • 实现ISupportErrorInfo是COM跨语言传递异常详情的标准做法,避免返回通用错误码
  • 跨语言调用的方法必须是公开权限,否则会触发未预期的访问错误

内容的提问来源于stack exchange,提问作者Paweł Kępiński

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:44:52