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