从VBA调用dll函数时出现浮点错误
情况是这样的。我正在使用MS Visual Sturio 2005和Excel 2007。我创建了一个包含函数的dll从VBA调用dll函数时出现浮点错误,vba,dll,overflow,fpu,Vba,Dll,Overflow,Fpu,情况是这样的。我正在使用MS Visual Sturio 2005和Excel 2007。我创建了一个包含函数的dll extern "C" VARIANT WINAPI MyFunc() { VARIANT res; memset(&res, 0, sizeof(VARIANT)); ::VariantInit(&res); return res; } 这是从Excel VBA调用的。此功能似乎工作正常。 但有一个问题:当VBA从我的函数返回并尝试执行
extern "C" VARIANT WINAPI MyFunc()
{
VARIANT res;
memset(&res, 0, sizeof(VARIANT));
::VariantInit(&res);
return res;
}
这是从Excel VBA调用的。此功能似乎工作正常。
但有一个问题:当VBA从我的函数返回并尝试执行下一条浮点指令时,我看到一个窗口:
运行时错误6。溢出
这个错误很奇怪。过去几天我一直在调查此事,以下是我收集的“事实”:
1) 该错误仅在第一次调用dll后显示。对该函数的所有后续调用都不会导致此错误
2) 在控件从dll返回后,VBA代码中的第一条(看似无害)浮点指令会触发此错误:
Dim dMinValue As Double
dMinValue = 10000000#
3) 构建dll的项目包含4个文件:mydll.cpp、mydll.def、cSomeClass.cpp和cSomeClass.h
cSomeClass
是一个相当复杂的类,它从我的其他lib调用代码。但是mydll.cpp
不以任何方式使用cSomeClass
。这是mydll.cpp的代码:
#include <OAIdl.h>
#include <float.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
extern "C" VARIANT WINAPI MyFunc()
{
unsigned int u;
u = _controlfp(0, 0);
_controlfp(u & ~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT), _MCW_EM);
VARIANT res;
memset(&res, 0, sizeof(VARIANT));
::VariantInit(&res);
return res;
}
#包括
#包括
BOOL APIENTRY DllMain(句柄模块、DWORD ul_原因、LPVOID LPREFERED)
{
返回TRUE;
}
外部“C”变量WINAPI MyFunc()
{
无符号整数u;
u=_-controlfp(0,0);
_控制FP(u&~(_EM_无效| u EM_非规范| u EM_零除| u EM_溢出| u EM_下溢| u EM_不精确),_MCW_EM);
变体res;
memset(&res,0,sizeof(VARIANT));
::VariantInit(&res);
返回res;
}
MyFunc()
的初始版本没有前3行(与\u controlfp()
冲突的那3行),这导致了VBA中的“运行时错误6,溢出”
。然后我开始怀疑这个错误可能与FPU寄存器有关(我对这些寄存器知之甚少)。当我添加这3行代码时,调用\u controlfp()
-“0xC0000090:浮点无效操作”时引发异常。
。如果我保留上面显示的代码,异常会导致堆栈展开(我们没有进入VARIANT res;
行),Excel中会显示一个窗口,显示“运行时错误6.溢出”。。总而言之,添加这3行代码会导致先前抛出浮点异常。如果我们捕捉到在第三行抛出的异常(使用\uuuException
子句)并忽略它(通过调用\uClearFP()
),则Excel中不会报告任何错误
一个令人讨厌的细节:如果我从VisualStudio项目中删除文件cSomeClass.cpp
和cSomeClass.h
,则不会再现错误cSomeClass.h
不包括在mydll.cpp
中,但如果我从项目中删除cSomeClass.*
文件,则dll大小会显著减小
我在这一点上的最佳猜测是,cSineClass.cpp
引用的LIB-s中有一些静态对象导致了这种情况。可能在加载dll时(根据我的实验,在加载到DllMain
之前)初始化(构造)了这些对象,这不知何故导致设置了的错误标志“0xC0000090:浮点无效操作”。
。当我们从dll返回Visual Basic时,somethis调用\u controlfp
,并在引发“0xC0000090:浮点无效操作。”
时启用浮点异常(它们在С++中被关闭)。该异常以某种方式转换为我在Excel中看到的“运行时错误6.溢出”。
。这只是一个猜测。到目前为止,我还没有发现任何静态对象可以这样做
不幸的是,我无法创建一个复制此错误的小示例,因为它仅在我将cSomeFile.*
作为项目的一部分时才会显示。那些文件需要我所有的库
如果有人知道这种行为的原因或对如何推进我的调查提出建议,我们将不胜感激。1)显然,当我从VBA进入DLL代码时,FPU异常被关闭,就像有人调用
u = _controlfp( 0, 0 );
_controlfp( u & ((_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT )), _MCW_EM );
在将控制传递给我的dll代码之前
2) 在任意点调用std::numeric_limits::signaling_NaN()会导致在浮点状态字中设置_EM_INVALID标志(可以通过调用_statusfp()看到)
3) 当控件从DLL返回时,FPU异常似乎已打开。好像有人打电话来:
u = _controlfp( 0, 0 );
_controlfp( u & (~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | EM_UNDERFLOW | _EM_INEXACT )), _MCW_EM );
这会导致运行时错误。因此,我在不同的时候都遇到了类似的Excel随机问题,而你是我的英雄
我发现通过调用
\u clearfp()
,它将消除错误并正确返回值。我认为这个问题是因为我使用了大量的值来表示无效的浮动。设置标志,并导致Excel(仅Excel)呕吐。我以前从未在任何其他程序中遇到过运行时异常问题。OK。我已经缩小了范围。它是由一个静态常量双变量在_CRT_INIT()中用numeric_limits::infinity()初始化引起的,该函数在DllMain之前调用。有人能解释一下这里发生了什么吗?谢谢很抱歉,这似乎是由另一个变量用numeric_limits::signaling_NaN()初始化引起的。您知道如何解决此问题吗?我有完全相同的问题。