10

はじめに-長くて退屈な部分

(質問は最後にあります)

FPU制御ワードを変更し続けるサードパーティのCOMコンポーネントでひどい頭痛がします。

私の開発環境はWindowsとVisualC++ 2008です。通常のFPU制御ワードは、さまざまな条件で例外がスローされないように指定しています。_CW_DEFAULTで見つかったマクロとfloat.h、起動時にデバッガーで制御ワードを確認することで、これを確認しました。

COMオブジェクトを呼び出すたびに、制御ワードは戻り時に変更されます。これは簡単に防御できます。制御ワードをリセットするだけで、すべて問題ありません。問題は、COMコンポーネントがイベントシンクの呼び出しを開始したときです。イベント呼び出しを受信するとすぐに制御ワードをリセットすることでコードを保護できますが、イベント呼び出しから戻るとすぐに何もできません。

このCOMコンポーネントのソースはありませんが、作成者と連絡を取り合っています。私が彼から受けた反応は「え?」でした。彼は私が話していることについて少しも手がかりを持っていないと思うので、私はこれについて自分で何かをしなければならないのではないかと心配しています。彼のランタイム(DLLはすべて大文字のTで始まるシンボル名でいっぱいなので、DelphiまたはBorland C ++のいずれかだと思います)、または彼が使用している他のサードパーティのコードが問題の原因であると思います。彼のコードがFPU制御ワードを明示的に変更しているとは思いません。

それで、なにかお手伝いできますか?ビジネスの観点からは、このサードパーティコンポーネントを使用することが不可欠です。技術的な観点から、私はそれを捨てて、通信のプロトコルを自分で実装することができました。ただし、このプロトコルにはクレジットカード取引の処理が含まれるため、これは非常にコストがかかります。私たちは責任を負いたくありません。

コンポーネントの作成者に渡すことができる、ハックアラウンド、またはBorland製品のFPU設定に関するいくつかの有用な情報がどうしても必要です。

質問

何かできることはありますか?コンポーネントの作成者は、それを修正するために必要なものを持っていないと思います(彼のかなり無知な応答から判断して)。

私は自分の例外ハンドラーをインストールするというアイデアをいじくり回してきました。このハンドラーでは、ハンドラーの制御ワードをリセットし、Windowsに実行を続行するように指示します。でハンドラーをインストールしてみましSetUnhandledExceptionFilter()たが、何らかの理由で例外がキャッチされません。

  1. なぜ例外をキャッチしないのですか?
  2. FPU例外のキャッチに成功し、FPU制御ワードをリセットし、何も起こらなかったので実行を続行させた場合、すべての賭けは無効になりますか?

アップデート

皆様のご提案に感謝申し上げます。私だけでなく、彼のコードの他の多くのクライアントの生活を楽にするために彼が何ができるかについて、著者に指示を送りました。私は彼に、でFPU制御ワードをサンプリングし、DllMain(DLL_PROCESS_ATTACH)後で使用するために制御ワードを保存して、イベントハンドラーを呼び出し、呼び出しから戻る前にFPUCWをリセットできるようにすることを提案しました。

今のところ、誰かが興味を持っているなら、私はハックアラウンドを持っています。彼のコードに何が起こるかわからないので、ハックアラウンドは潜在的に悪いものです。彼がコードで浮動小数点数を使用していないという確認を以前に受け取ったので、FPU例外に依存するサードパーティのコードを除いて、これは安全であるはずです。

アプリに加えた2つの変更:

  1. メッセージポンプをラップする
  2. WH_CALLWNDPROCメッセージポンプがバイパスされるコーナーケースをキャッチするためにウィンドウフック( )を取り付けます

どちらの場合も、FPUCWが変更されているかどうかを確認します。ある場合は、にリセットし_CW_DEFAULTます。

4

2 に答える 2

6

コンポーネントがエンバカデロ製品で書かれているというあなたの診断は本当である可能性が非常に高いと思います。Delphiのランタイムライブラリは、C ++ Builderの場合と同じように、実際に浮動小数点例外を有効にします。

Embarcaderosツールの優れた点の1つは、浮動小数点エラーが言語例外に変換されることです。これにより、数値コーディングがはるかに簡単になります。それはあなたにとって少し慰めになるでしょう!

このエリア全体が巨大なPITAです。FPコントロールワードに関する規則はありません。それは完全に無料です。

MS C ++ランタイムはおそらくすでにこれらの例外をキャッチしているので、未処理の例外をキャッチしても作業が完了しないと思いますが、私はその分野の専門家ではなく、間違っている可能性があります。

唯一の現実的な解決策は、実行がコードに到着するたびにFPUを希望どおりに設定し、実行がコードを離れるときにFPUを復元することだと思います。COMイベントシンクについては、なぜこれを行うのに障害があるのか​​を理解するのに十分な知識がありません。

私の製品にはDelphiで実装されたDLLが含まれており、逆の問題が発生します。ほとんどの場合、呼び出しを行うクライアントには、例外を無効にするFPU制御ワードがあります。私たちが採用する戦略は、入力時に8087CWを記憶し、コードを実行する前に標準のDelphi CWに設定してから、終了ポイントで復元することです。コールバックを作成する前に呼び出し元の8087CWを復元することにより、コールバックも処理するように注意します。これはCOMオブジェクトではなくプレーンDLLであるため、おそらく少し単純です。

COMサプライヤにコードを変更してもらうことにした場合は、Set8087CW()関数を呼び出す必要があります。

ただし、ゲームにはルールがないため、COMオブジェクトベンダーは、コードの変更を拒否し、責任を負わせることが正当化されると思います。

これが100%決定的な答えではない場合は申し訳ありませんが、これらすべての考えをコメントにまとめることはできませんでした。

于 2011-08-03T21:59:34.957 に答える
6

FP制御ワードはスレッドごとですが、新しいスレッドが作成されるとdllmain関数が呼び出されますが、新しいプロセスに進むことでこれを回避できるとは思いません。

新しいプロセスをスピンオフしてCOMを実行し、お気に入りのプロセス間通信方法(Windowsメッセージ、プロセス外COM、名前付きパイプ、ソケットなど)を使用してプロセスとチャットすることをお勧めします。このようにして、COMサーバーは、ホストプロセスをダウンさせることなく、あらゆる種類の損傷(自身のクラッシュを含む)を自由に行うことができます。

もう1つのアイデアは、DllMainでFPUをリセットし、問題のあるDLLの直後にロードすることを唯一の目的とするDLLを作成することです。Windowsは、COMサーバーによって作成されたスレッドを含め、新しいスレッドが作成されたときに、読み込み順序を使用してDllMainを呼び出す可能性があります。これはWindowsの内部動作に依存することに注意してください。また、COMサーバーは、fp例外を有効にするため、実際にはfp例外に依存している場合があります。FP例外を無効にすると、COMサーバーが予期しない動作をする可能性があります。

于 2011-08-03T23:20:26.597 に答える