0

std :: runtime_errorを継承するwindows_errorという自己記述の例外クラスを使用しています。これは、WindowsAPI関数からの予期しないエラーを適切に処理するために使用します。

コールスタックの一番下、WinMain関数の最後で、まだ処理されていないすべてのwindows_error例外をキャッチします。プログラムが終了する直前にエラーメッセージを表示して、次のように処理するつもりです。

int WINAPI wWinMain(HINSTANCE inst, HINSTANCE prev, wchar_t *cmdline, int winshow)
{
    // Initialize result to EXIT_FAILURE in case the program terminates due to
    // an exception.
    int result = EXIT_FAILURE;

    try {
        result = sIRC()();
    }
    catch (windows_error &e) {
        e.basicHandler();
    }

    return result;
}

basicHandlerメンバー関数は次のようになります。

void windows_error::basicHandler() const
{
    std::wostringstream ss;

    ss << L"An unexpected error has occurred in a Windows function.\n\n" \
          L"Function " << m_api << L" was called by " << m_caller << L" in " << m_srcFile << L" at line " << m_srcLine << L". " \
          L"It returned error " << m_error << L":\n\n" << m_errorMessage;

#ifdef _CONSOLE
    std::wcout << L"\n" << ss.str();
#else
    auto result = MessageBox(HWND_DESKTOP, ss.str().c_str(), L"Windows error!", MB_ICONERROR);
    result = result; // I added this line so I can put a breakpoint in the debugger
#endif // _CONSOLE
}

私が取り組んでいるプログラムを始めたとき、これは見事に機能しました。しかし今、プログラムは成長し始めています。新しいコードを試していると、プログラムが予期せず終了したように見えることに気づきました。Visual C ++ 2010デバッガーで実行すると、windows_error例外がスローされていることに気付きました。basicHandler関数をステップ実行すると、MessageBox関数が実際にメッセージボックスを表示せずに1(IDOK)を返すことがわかりました...

この動作の原因は何ですか?

説明が少し曖昧であることは知っていますが、他に何を追加すればよいかわかりません...この動作が可能であることを示唆するMSDNには何も見つかりませんでした。スタックの巻き戻し中にすべて破棄されるため、MessageBoxに渡すことができる親ウィンドウハンドルはありません。また、ウィンドウプロシージャやその他のWindowsコールバックによってスタックが巻き戻されないことも確信しています。

どんなヒントでもいただければ幸いです。

4

1 に答える 1

0

Raymond は、私の質問に対するコメントで、必要なヒントを提供してくれました。スタックの巻き戻し中に、user_interface クラスのデストラクタがウィンドウ ハンドルで DestroyWindow を呼び出します。これは、その時点でまだ有効であるためです。私が知らなかったのは、MessageBox が結果の WM_QUIT メッセージを解釈してそれ自体を閉じるということでした。メッセージ ボックスには独自の内部メッセージ キューがあると思いましたか?

user_interface クラスのデストラクタを変更することで問題を解決できました。

そうだった:

if (_wnd)
    DestroyWindow(_wnd);

私はそれを次のように変更しました:

if (_wnd) {
    DestroyWindow(_wnd);

    MSG msg = MSG();
    while (msg.message != WM_QUIT) {
        GetMessage(&msg, 0, 0, 0);
    }
}

これは機能しますが、少し醜いようです。これを改善するための提案はありますか?

于 2012-11-05T02:03:24.597 に答える