从delphi应用程序调用.net4.0 com服务器后出现错误异常

时间:2011-02-23 13:25:47

标签: delphi com .net-4.0

我们正在将我们的代码库从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:我已经扩展了恢复浮点配置的示例。

2 个答案:

答案 0 :(得分:2)

看起来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 :(得分:1)

我似乎无法对原始问题发表评论,请原谅这个答案,这是一系列问题。你有没有找到一个可接受的解决问题的工作?您是否使用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 Framework中运行良好,但现在我得到了大量的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