複数のAppDomainを持つアプリケーションでのMicrosoft.Win32.SystemEventsの機能

昔々、appdomainを作成し、その中のTopshelfに基づくサービスを起動するコンソールアプリケーションがありました。 しかし、一度バグが発生すると、Ctrl-Cを押しても作業は終了しませんでしたが、シャットダウンコマンドを受信し、この状態でフリーズしたと報告しました。 簡単な分析では、ドメインのアンロードでハングすることが示されましたが、奇妙なことに、 CannotUnloadAppDomainException例外はスローされませんでした。

さらに、特定のタスクを実行した後にのみアプリケーションを閉じるとアプリケーションがフリーズし、ドメインをアンロードする前にいくつかの「余分な」スレッドが存在することに注意しました。 名前から推測できるように、 SystemEventsことがSystemEventsSystem.Drawing.SolidBrushを使用すると、ハンドラーがSystemEvents.UserPreferenceChangingに追加されSystemEvents.UserPreferenceChangingが、これは別個のappdomainであるため、タイプは再度初期化され、「。NET SystemEvents」という名前で別のスレッドが作成されます。
アプリケーションを閉じると、 SystemEvents.Dispose()が呼び出され、コンソールハンドラーUnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 0)アプリケーションがフリーズします。 コンソールハンドラーの削除に関する問題についていくつか言及しましたが、すべての解決策SystemEvents.Shutdown()をReflection経由で呼び出すことになりましたが、それは役に立たず、役に立たないはずなので、Dispose()を呼び出します。
次に、2番目のSystemEventsストリームの作成を何らかの方法で回避する必要があると判断し、 SystemEvents.EnsureSystemEvents(bool requireHandle, bool throwOnRefusal)メソッドSystemEvents.EnsureSystemEvents(bool requireHandle, bool throwOnRefusal)抜け穴が見つかりました。

 if (Thread.GetDomain().GetData(".appDomain") != null) { if (throwOnRefusal) { throw new InvalidOperationException(SR.GetString(SR.ErrorSystemEventsNotSupported)); } return; } //   SystemEvents 

私の場合、このメソッドはthrowOnRefusal = falseで呼び出されたため、 domain.SetData(".appDomain", new object())を追加すると、別のSystemEventsスレッドの作成を回避し、コンソールハンドラーが削除されるとフリーズし、アプリケーションは正常に動作を終了します。
「.appDomain」プロパティの確認に依存するコードの場合、副作用が発生する可能性があります。アプリケーションがasp.netとしてカウントされる場合があります))この設定が引き起こす問題を誰かが知っている場合、または問題に対するより安全で適切な解決策を知っている場合、共有してください。


Source: https://habr.com/ru/post/J238333/


All Articles