1. ホーム
  2. c#

[解決済み] Environment.Exit()でプログラムが終了しなくなったのはなぜですか?

2022-05-12 23:31:40

質問

これは数日前に発見したことなのですが、私のマシンに限ったことではないことを、以下のサイトから確認しました。 この質問 .

最も簡単な再現方法は、Windows Formsアプリケーションを起動し、ボタンを追加して、このコードを書くことです。

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("yada");
        Environment.Exit(1);         // Kaboom!
    }

プログラムが失敗する の後 Exit() ステートメントが実行された後、プログラムは失敗します。Windows Formsでは、"Error creating window handle"と表示されます。

アンマネージドデバッグを有効にすると、何が起こっているのかがある程度明確になります。そのため COM モーダルループが実行され、WM_PAINT メッセージが配信されるようになりました。これは、破棄されたフォームでは致命的です。

私がこれまでに集めた唯一の事実は

  • デバッガーを使って実行する場合に限ったことではありません。 これはまた、デバッガなしでも失敗します。 むしろ同様に悪いことに、WER クラッシュ ダイアログが表示されます。 2 回 .
  • プロセスのビット数とは関係ありません。wow64 レイヤーはかなり悪名高いですが、AnyCPU ビルドも同じようにクラッシュします。
  • .NET のバージョンとは関係なく、4.5 と 3.5 は同じようにクラッシュします。
  • 終了コードは重要ではありません。
  • Exit()を呼び出す前にThread.Sleep()を呼び出しても直らない。
  • これは Windows 8 の 64 ビット版で発生し、Windows 7 は同じように影響されないようです。
  • これは比較的新しい動作のはずで、以前には見たことがありません。 関連する更新プログラムが Windows アップデート を通じて配信された関連する更新プログラムはありません。ただし、私のマシンでは更新履歴が正確ではなくなっています。
  • これは、著しく破損した動作です。AppDomain.UnhandledException のイベント ハンドラでこのようなコードを書くと、同じようにクラッシュします。

私は特に、このクラッシュを回避するために何ができる可能性があるかに興味があります。 特に AppDomain.UnhandledException のシナリオは私を困惑させます。.NET プログラムを終了させる方法はあまり多くありません。 Application.Exit() または Form.Close() を呼び出すことは、UnhandledException のイベント ハンドラでは有効ではないので、回避策にはならないことに注意してください。


UPDATE: Mehrdad は、ファイナライザースレッドが問題の一部である可能性を指摘しました。 私はこれを確認し、また、CLR がファイナライザー スレッドに実行を終了させるために与える 2 秒間のタイムアウトに関するいくつかの証拠を確認していると思います。

ファイナライザーは NativeWindow.ForceExitMessageLoop() の内部にあります。 そこには IsWindow() Win32 関数があり、32 ビット モードでマシン コードを見たときに、コードの場所、オフセット 0x3c にほぼ対応しています。 IsWindow()はデッドロックしているようです。 しかし、内部のスタック トレースを取得することはできません。 P/Invoke の呼び出しがちょうど返されたと考えています。 これは説明するのが難しいです。 もし、もっと良いスタックトレースがあれば、ぜひ見てみたいものです。 私のです。

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

ForceExitMessageLoop 呼び出しの上には何もなく、アンマネージドデバッガが有効になっています。

どのように解決するのですか?

私はこの問題について Microsoft に連絡し、それが功を奏したようです。 少なくとも、そうであったと思いたいのです。) 解決の確認は得られなかったのですが、Windows グループは直接コンタクトするのが難しく、仲介者を利用する必要がありました。

Windows Update で配信される更新プログラムによって、問題は解決しました。 クラッシュする前の顕著な 2 秒の遅延はもはや存在せず、IsWindow() のデッドロックが解決されたことを強く示唆します。 また、プログラムはクリーンかつ確実にシャットダウンされます。 この更新は、Windows Defender、wdboot.sys、wdfilter.sys、tcpip.sys、rpcrt4.dll、uxtheme.dll、crypt32.dll および wintrust.dll に対するパッチをインストールします。

Uxtheme.dll は奇抜なものです。これは Visual Styles テーマ API を実装しており、このテスト プログラムで使用されています。確証はありませんが、問題の原因はこの 1 つにあると私は考えています。 C:\WINDOWSsystem32 にあるコピーはバージョン番号 6.2.9200.16660 で、私のマシンでは 2013 年 8 月 14 日に作成されました。

一件落着。