1

これが状況です。MS Visual Strio 2005 と Excel 2007 を使用しています。関数を含む dll を作成します。

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 のビルド元のプロジェクトには、mydll.cpp、mydll.def、cSomeClass.cpp、および cSomeClass.h の 4 つのファイルが含まれています。

cSomeClass私の他のライブラリからコードを呼び出すかなり複雑なクラスです。しかし、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;
}

の初期バージョンにMyFunc()は最初の 3 行 ( をいじっているもの) がなく、VBA_controlfp()で発生していました。"Runtime Error 6, Overflow"次に、このエラーが FPU レジスタに関連している可能性があるのではないかと疑い始めました (それらについてはほとんど知りません)。_controlfp()これらの 3 行を追加すると、 - を呼び出すと例外がスローされました"0xC0000090: Floating-point invalid operation."。コードを上に示したままにしておくと、例外によってスタックが巻き戻され (行に到達しません) 、Excel にVARIANT res;ウィンドウが表示されます。"runtime error 6. Overflow."まとめると、これらの 3 行を追加すると、浮動小数点例外が先にスローされます。3 行目でスローされた例外を (__except節で) キャッチし、それを ( callng で_clearfp()) 無視すると、Excel でエラーは報告されません。

厄介な詳細: ファイルを削除cSomeClass.cppcSomeClass.h、Visual Studio プロジェクトからエラーが再現されません。cSomeClass.hには含まれていませんが、プロジェクトからファイルmydll.cppを削除cSomeClass.*すると、dll のサイズが大幅に縮小されます。

この時点での私の最善の推測は、これによって参照される LIB-s にいくつかの静的オブジェクトがあるcSineClass.cppということです。おそらく、これらのオブジェクトは、dll がロードされているときに初期化 (構築) され (私の実験によると、前にDllMain)、これによりエラーフラグ"0xC0000090: Floating-point invalid operation."が設定されます。dll から Visual Basic に戻ると、somethis は_controlfp浮動小数点例外を呼び出して有効にします (С++ では無効になっています) 。発生が Excel で見られるものに"0xC0000090: Floating-point invalid operation."何らかの形で変換されます。"Runtime Error 6. Overflow."これは単なる推測です。これまでのところ、これを実行できる静的オブジェクトは見つかりませんでした。

残念ながら、このエラーを再現する小さな例を作成できませんでした。これcSomeFile.*は、プロジェクトの一部としてのみ表示されるためです。そして、それらのファイルにはすべてのライブラリが必要です...

誰かがそのような行動の原因を知っている場合、または私の調査を進める方法について提案がある場合は、大歓迎です.

4

2 に答える 2

2

そのため、さまざまな時点で Excel で同様のランダムな問題が発生しました。あなたは私のヒーローです。

を呼び出すと_clearfp()、エラーが解消され、適切に値が返されることがわかりました。_HUGEこの問題は、無効なフロートを示すためにあらゆる場所で値を使用しているという事実から生じると思います。これにより、フラグが設定され、Excel (および Excel のみ) が barf になります。他のプログラムで実行時例外の問題に遭遇したことはありません。

于 2014-12-06T21:03:42.300 に答える
1

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 :: neuro_limits :: signalling_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 );

これにより、ランタイムエラーが発生します。

于 2012-07-30T11:28:32.173 に答える