【问题标题】:Wrong exception after calling .net4.0 com server from delphi application从delphi应用程序调用.net4.0 com服务器后出现错误异常
【发布时间】:2011-07-02 18:24:54
【问题描述】:

我们正在将我们的代码库从 BDS2006 迁移到 Rad Studio XE,我们发现了一些非常奇怪的行为:如果我们在从 .Net4.0 中实现的 COM 服务器创建一些对象后进行无效的浮点运算(即除零) ,我们没有得到正常的异常(即 EDivisionByZero),而是 EStackOverflow。

我们设法准备了非常简单的例子:ComErrorExample

有一个 .net 4.0 程序集,带有 com 接口(一个函数返回字符串)和简单的 delphi 应用程序:

var
  a, b: Double;
  Stored8087CW: Word;

begin
  CoInitialize(nil);

  try
    b := 0;
    a := 1 / b;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message, ' (Expected type of exception)');
  end;

  Stored8087CW := Get8087CW;
  Writeln('Code from .NET COM: ', CoExampleOfCOM.Create.DoSomething);
  Set8087CW(Stored8087CW); //it's only to show that 8087 control word doesn't change

  try
    b := 0;
    a := 1 / b;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message, ' (Unexpected type of exception! Why stack overflow?)');
  end;

  Readln;

  CoUninitialize;

end.

如您所见,我们将两个除以零 - 第一个在创建 com 对象之前抛出 EDivisionByZero,第二个抛出 EStackOverflow。

我们在 win7 x64 和 winXP x32 上对此进行了测试 - 没有区别。但是当我们将 com 服务器从 .net4.0 切换到 .net3.5 时,一切正常。

问题:我们做错了吗?我们能做点什么来解决这个问题吗?

切换到 .net3.5,或者放弃 Delphi 对我们来说不是一个选择。

更新: 我们之前检查了浮点配置( Set8087CW() ),但没有任何运气。 UPDATE2:我已经扩展了恢复浮点配置的示例。

【问题讨论】:

  • 可能是 FPU 堆栈溢出,原因是 .net 或 MS 编译器中的浮点模型发生了一些变化 - 只是猜测。
  • FPU 堆栈溢出类似于 EInvalidOp IIRC
  • 遇到类似问题。你找到解决方案了吗?

标签: delphi com .net-4.0


【解决方案1】:

COM DLL 中的某些内容似乎正在更改浮点处理器配置。请参阅 Delphi 帮助中的 Default8087CW 和 Set8087CW。

您可以在对 COM DLL 进行任何操作之前保存它,然后再恢复它。

var
  Saved8087CW: Word;
begin
  Saved8087CW := Default8087CW;
  // If you want, disable all fpu exceptions 
  // with the next line.
  Set8087CW($133F);
  DoYourComOperationHere;
  Set8087CW(Saved8087CW);
end;

【讨论】:

  • 我们之前检查过这个,但没有运气。
  • +1 最佳做法是在进入 DLL 时将 8087CW 保存,并在您再次离开时恢复它。不幸的是,由于许多 DLL 不这样做,您通常还必须在调用后将其恢复到您想要的状态!这是一种正确的皇家痛苦。
【解决方案2】:

我似乎无法对原始问题发表评论,因此请原谅这个更像是一组问题的答案。你有没有找到一个可以接受的解决这个问题的方法?您是否使用 Quality Central 记录了 Delphi 问题,如果有,您是否有事件编号?

我看到了我认为相关的问题,在 Delphi 方面我将 FPU CW 设置为 $133f,然后在 C# 方面我有

    try
    {
        Double.IsNaN(Double.NaN);
    }
    catch (ArithmeticException)
    {
        /* Intentionally empty. .NET will initialise the FPU at this point. */
    }

以前在 2.0 框架中运行良好,但现在我收到大量 0xC0000092:浮点堆栈检查。然后是 StackOverflow 异常。

将上述代码添加到 COM 公开的方法中会导致调用堆栈

clr.dll!CLRVectoredExceptionHandlerShim()  + 0xa3 bytes 
ntdll.dll!_RtlpCallVectoredHandlers@12()  - 0xef1c bytes    
ntdll.dll!_RtlCallVectoredExceptionHandlers@8()  + 0x12 bytes   
ntdll.dll!_RtlDispatchException@8()  + 0x19 bytes   
ntdll.dll!_KiUserExceptionDispatcher@8()  + 0xf bytes   
clr.dll!CLRVectoredExceptionHandler()  + 0x9a bytes 
clr.dll!CLRVectoredExceptionHandlerShim()  + 0xa3 bytes 

【讨论】:

    猜你喜欢
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    • 2021-12-12
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    相关资源
    最近更新 更多