首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从VBA调用dll函数时出现的浮点错误

从VBA调用dll函数时出现的浮点错误
EN

Stack Overflow用户
提问于 2012-07-27 09:52:59
回答 2查看 1.3K关注 0票数 1

情况就是这样。我正在使用2005和Excel 2007。我创建一个包含函数的dll。

代码语言:javascript
运行
复制
extern "C" VARIANT WINAPI MyFunc()
{
  VARIANT res;
  memset(&res, 0, sizeof(VARIANT));
  ::VariantInit(&res);    
  return res;
}

从Excel调用。此功能似乎工作正常。但是有一个问题:当VBA从函数返回并尝试执行下一个浮点指令时,我会看到一个窗口:

运行时错误6.溢出。

这个错误很奇怪。我在过去几天一直在调查这件事,以下是我收集到的“事实”:

1)错误仅在第一次调用dll之后才会显示。对此函数的所有连续调用都不会导致此错误。

2)错误由控件从dll返回后VBA代码中的第一个浮点指令触发:

代码语言:javascript
运行
复制
Dim dMinValue As Double
dMinValue = 10000000#

3)构建dll的项目包含4个文件: mydll.cpp、mydll.def、cSomeClass.cpp和cSomeClass.h。

cSomeClass是一个相当复杂的类,它从我的其他库调用代码。但是mydll.cpp不以任何方式使用cSomeClass。这是mydll.cpp的代码

代码语言:javascript
运行
复制
#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;
}

最初版本的MyFunc()没有前3行(那些扰乱_controlfp()),它在VBA中导致了"Runtime Error 6, Overflow"。然后,我开始怀疑这个错误可能与FPU寄存器有关(我对这些知之甚少)。当我添加这3行时,当我调用_controlfp() - "0xC0000090: Floating-point invalid operation."时会抛出一个异常。如果我将代码保留在上面的代码中,异常将导致堆栈展开(我们不能进入VARIANT res;行),并在"runtime error 6. Overflow."中显示一个窗口。总之,添加这3行将导致更早地抛出浮点异常。如果我们捕获第3行抛出的异常(带有__except子句)并忽略它(通过调用_clearfp()),那么在Excel中不会报告错误。

一个令人讨厌的细节:如果我从Visual项目中删除文件cSomeClass.cppcSomeClass.h,则错误不会被再现。cSomeClass.h并不包含在mydll.cpp中,但是如果我从项目中删除cSomeClass.*文件,dll的大小就会大大减小。

在这一点上,我最好的猜测是,cSineClass.cpp引用的LIB中有一些静态对象导致了这种情况。这些对象可能是在加载dll时初始化(构造)的(根据我的实验,在加载到DllMain之前),这会以某种方式导致设置"0xC0000090: Floating-point invalid operation."的错误标志。当我们从dll返回到Visual时,它调用_controlfp并启用浮点异常(它们在С++中被关闭),当引发"0xC0000090: Floating-point invalid operation."时,这些异常以某种方式被转换为С++中看到的"Runtime Error 6. Overflow."。这只是猜测而已。现在我还没有发现任何静态的物体可以这样做。

不幸的是,我无法创建一个复制此错误的小示例,因为只有当我将cSomeFile.*作为项目的一部分时,它才会出现。那些文件需要我所有的孩子..。

如果有人知道造成这种行为的原因,或对如何推进我的调查提出建议,我们将不胜感激。

EN

回答 2

Stack Overflow用户

发布于 2014-12-06 21:03:42

因此,我在不同的地方都有类似的随机问题与Excel,你是我的英雄。

我发现,通过调用_clearfp(),它将消除错误并正确返回值。我认为问题产生于这样一个事实:我在各地使用_HUGE值来表示无效的浮点数。它设置标志,并导致Excel (只有excel)显示。在其他程序中,我从来没有遇到过运行时异常的问题。

票数 2
EN

Stack Overflow用户

发布于 2012-07-30 11:28:32

1)显然,当我从VBA进入DLL代码时,FPU异常就会被关闭,就像有人调用

代码语言:javascript
运行
复制
  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异常。好像有人打电话给:

代码语言:javascript
运行
复制
  u = _controlfp( 0, 0 );
  _controlfp( u & (~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | EM_UNDERFLOW | _EM_INEXACT )), _MCW_EM );

这将导致运行时错误。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11685441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档