6

...すこし。この非常に単純な例が示すように、

ここに画像の説明を入力

ごくまれに (これまでに報告されたのは 1 回だけ)、私のアプリケーションの 1 つがこのようにクラッシュすることがあります。不特定の例外が発生したときに通常どおり終了したい。私の戦略は、問題を (低レベルで) ログに記録してから終了することです。アプリケーションはサブシステムの一部であり、問​​題が検出された場合は (再) 起動したいと考えています。C++-Builder 6 で構築され、Windows (XP...7、8 も) で動作します。abort()おそらくエラーメッセージの原因であることがわかりました。アプリケーションには GUI があります。そのため、単に (ブロック解除) 出力をstderr.

そして、メッセージ ボックスがユーザーに受け入れられない限り、私のアプリケーションは明らかに実行を続けます。たとえば、タイマー (上記の例ではライフビートが増加します) やプロセス間メッセージを処理し、問題を完全に認識しません。

C++ プログラムをクラッシュさせる最も簡単な方法は何ですか?に対するいくつかの回答を読んだ後、およびraise(SIGABRT) メソッドと abort() メソッドの違い、次のことを試しました

void mySignalHandler(int sig)
{
    // low-level error reporting here
    exit(-1);
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    signal(SIGABRT, mySignalHandler);
    // some more initialisation here
}

orが呼び出された場合でも、アプリケーションを適切に終了させることができます。(また、Windows が「問題の解決策を検索」しないようにしたいと考えています。)abort()raise(SIGABRT)

これ(中止のシグナルハンドラを登録し、そこで終了を呼び出す)はあなたの観点から信頼できますか?...または少なくとも構築できるものはありますか?

4

4 に答える 4

4

C++Builder のインストール フォルダで、次のファイルを確認します。

  • source\cpprtl\Source\misc\errormsg.c - の実装_ErrorMessage
  • source\cpprtl\Source\procses\abort.c -abortを呼び出すの実装_ErrorMessage
  • source\cpprtl\Source\misc\assert.c -_assertを呼び出すの実装_ErrorMessage

errormsg.c は_messagefunc、既定の動作をオーバーライドするために設定できる、文書化されていない関数ポインターを定義します。これは文書化されておらず、どのヘッダー ファイルでも宣言されていませんが、 として宣言し、externその方法でアクセスできます。使用例:

extern int (_RTLENTRY * _EXPDATA _messagefunc)(char *msg);

static int LogAndDie(char *msg)
{
  LogMessageToSomeFile(msg);
  exit(1);
  return 0;
}

void InitializeErrorHandling()
{
  _messagefunc = LogAndDie;
}
于 2014-08-14T12:57:38.717 に答える
1

いくつかのテストを行うことができましたが、SIGABRT シグナル ハンドラーの登録が単に NOOP であることを確認することしかできませんでした。

VS2008 Express で書かれた非常にシンプルな GUI アプリケーションで試してみました。:

  • フレームワークも .NET もなく、Win API のみ
  • Exit と Fatal を含む 1 つのメニュー
  • WndProc で直接管理されるメニュー
  • 致命的な実行 1/0

結果は次のとおりです。

  • 特別なアクションはありません => Windows は致命的なエラーを示す MessageBox を開きます ...
  • SIGABRT のシグナルハンドラ => 同じ MessageBox
  • C++ try catch(...) => 同じメッセージボックス
  • WndProc の SEH : エラーをインターセプトできます。
  • メッセージ ループの周りの SEH : エラーをインターセプトできます。

ボット SEH ハンドラーを配置すると、最も内部 (WndProc) がキャッチされます。

メッセージ ループを保護するには if で十分であり、すべての WndProc に入る必要はありません。

悪いニュースは、私は C++ ビルダーを知らず、メッセージ ループの場所を特定できないことです。

手がかりとして、WinAPI アプリケーションでメッセージ ループを保護する方法を次に示します。

__try {
while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
    ::MessageBox(NULL, _T("FATAL"), _T("MAIN"), MB_OK | MB_ICONERROR);
}

そうすれば、自分のメッセージ ボックスだけを見ることができます。メッセージ ボックスにコメントを付けると、アプリケーションは黙って終了します。

しかし...あなたが表示するメッセージは元のWindowsのものではないため、C++ビルダーはメッセージループにそのような例外ハンドラーを既に持っていると思われます。

それが役に立てば幸い ...

于 2014-08-14T13:30:43.863 に答える
1

未処理の例外が原因で終了した場合、Windows エラー報告を使用してプロセスのダンプを作成できる場合があります。次に、暇なときにダンプを確認し、親プロセスまたは他のウォッチドッグがプロセスを再起動できるようにします。この戦略を選択した場合、コードの失敗に対処しようとするのではなく、それを許容しようとします。

于 2014-08-14T10:37:20.553 に答える
1

プログラムの終了をキャプチャする場合は、atexit()を確認する必要があります。すべての終了イベントをキャプチャしたい場合はstd::set_terminate()を見てください。予期しない例外をすべてキャプチャしたい場合はstd::set_unexpected()を見てください。キャプチャのみしたい場合は、シグナル値でsignal()abort()を呼び出すことができます。でコードをラップすることもできます。SIGABRT try{your code}catch(...){custom event handler}

于 2014-08-14T11:25:12.543 に答える