実現したいこと
winformsで実装されたデスクトップアプリケーション内にて、発生した全ての例外をまとめて拾いたいです。
もちろん個々の機能でも例外処理を実装していますが、想定できていない部分で例外が発生したときに、ユーザに分かりやすいメッセージを表示したいと悩んでいます。
現状は「アプリケーションのコンポーネントで、ハンドルされていない例外が~」のダイアログが表示されてしまうので、使用者にとって分かりにくい(どうすればいいか分からない)状態となっております。
試したこと
以下のサイトを参考に、Program.cs
にてApplication.ThreadException
とThread.GetDomain().UnhandledException
を拾うようにソースを書き換えてみました。
C#
1using System; 2using System.Windows.Forms; 3using System.Threading; 4 5namespace WindowsApplication1 6{ 7 public class Program 8 { 9 [STAThread] 10 static void Main() 11 { 12 // ThreadExceptionイベント・ハンドラを登録する 13 Application.ThreadException += new 14 ThreadExceptionEventHandler(Application_ThreadException); 15 16 // UnhandledExceptionイベント・ハンドラを登録する 17 Thread.GetDomain().UnhandledException += new 18 UnhandledExceptionEventHandler(Application_UnhandledException); 19 20 // メイン・スレッド以外の例外はUnhandledExceptionでハンドル 21 //string buffer = "1"; char error = buffer[2]; 22 23 // ここで実行されるメイン・アプリケーション・スレッドの例外は 24 // Application_ThreadExceptionでハンドルできる 25 Application.Run(new Form1()); 26 } 27 28 // 未処理例外をキャッチするイベント・ハンドラ 29 // (Windowsアプリケーション用) 30 public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) 31 { 32 ShowErrorMessage(e.Exception, "Application_ThreadExceptionによる例外通知です。"); 33 } 34 35 // 未処理例外をキャッチするイベント・ハンドラ 36 // (主にコンソール・アプリケーション用) 37 public static void Application_UnhandledException(object sender, UnhandledExceptionEventArgs e) 38 { 39 Exception ex = e.ExceptionObject as Exception; 40 if (ex != null) 41 { 42 ShowErrorMessage(ex, "Application_UnhandledExceptionによる例外通知です。"); 43 } 44 } 45 46 // ユーザー・フレンドリなダイアログを表示するメソッド 47 public static void ShowErrorMessage(Exception ex, string extraMessage) 48 { 49 MessageBox.Show(extraMessage + " \n――――――――\n\n" + 50 "エラーが発生しました。開発元にお知らせください\n\n" + 51 "【エラー内容】\n" + ex.Message + "\n\n" + 52 "【スタックトレース】\n" + ex.StackTrace); 53 } 54 } 55} 56
発生している問題
上記のソースコードを追加したことで、Visual Studio上でのデバッグ実行(Release構成)からは想定通りのメッセージを出力できました。
しかし、同じビルドで出力された.exeファイルをエクスプローラから直接実行すると、もともとの「アプリケーションのコンポーネントで、ハンドルされていない例外が~」のダイアログが出力されてしまいます。
他の環境で試しても同じ結果でした。
環境など
- Windows 10
- IDE:Visual Studio 2010
- プロジェクトのターゲットプラットフォーム:.Net Framework4.0
該当のプログラムでは、起動後にいくつか別のスレッドを起動(Thread
インスタンスを生成し、Start()
させている)しているのでその辺りが関係しているのかなと思っています。
同じ環境で、スレッドを起動しないプログラムを作ってみたところ、デバッグ実行でも.exeの直接実行でも同じように想定通りの動きをしていました。
情報に不足があれば追加しますのでご指摘ください。どうかよろしくお願いいたします。
実際に問題が発生するコード
以下に実際の問題(自前のMessageBoxが出力したいのに、Windowsの「ハンドルされていない例外が~」が表示されてしまう。)が発生しているソースの簡易版を載せます。
上記の通りですが、Visual Studio上のデバッグでは想定通りの動きをしており、exeを直接実行した場合に問題が発生します。
C#
1using System; 2using System.Threading; 3using System.Windows.Forms; 4 5namespace SandboxForms 6{ 7 static class Program 8 { 9 /// <summary> 10 /// The main entry point for the application. 11 /// </summary> 12 [STAThread] 13 static void Main() 14 { 15 Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException); 16 System.AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Program_UnhandledException); 17 18 Application.EnableVisualStyles(); 19 Application.SetCompatibleTextRenderingDefault(false); 20 Application.Run(new Form1()); 21 } 22 23 static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) 24 { 25 var errorMember = e.Exception.TargetSite; 26 var errorMessage = e.Exception.Message; 27 var message = string.Format("異常が発生しました。システム管理者へ連絡してください。\r\n例外情報:例外が{0}で発生。プログラムを終了します。\r\nメッセージ:{1}", 28 errorMember, errorMessage); 29 MessageBox.Show(message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Stop); 30 } 31 32 static void Program_UnhandledException(object sender, UnhandledExceptionEventArgs e) 33 { 34 var ex = e.ExceptionObject as Exception; 35 if (ex == null) 36 { 37 MessageBox.Show("異常が発生しました。システム管理者へ連絡してください。\r\n例外情報なし"); 38 } 39 40 var errorMember = ex.TargetSite.Name; 41 var errorMessage = ex.Message; 42 var message = string.Format("異常が発生しました。システム管理者へ連絡してください。\r\n例外情報:例外が{0}で発生。プログラムを終了します。\r\nメッセージ:{1}", 43 errorMember, errorMessage); 44 MessageBox.Show(message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Stop); 45 } 46 } 47} 48 49-------------------------------------------------------------------------- 50 51using System; 52using System.Threading; 53using System.Windows.Forms; 54 55namespace SandboxForms 56{ 57 public partial class Form1 : Form 58 { 59 public Form1() 60 { 61 InitializeComponent(); 62 } 63 private void button1_Click(object sender, EventArgs e) 64 { 65 throw new ApplicationException("例外のテスト。"); 66 } 67 68 private void Form1_Load(object sender, EventArgs e) 69 { 70 ThreadStart ts = new ThreadStart(Form2Open); 71 Thread t = new Thread(ts); 72 t.Name = "test"; 73 t.SetApartmentState(ApartmentState.STA); 74 t.Start(); 75 } 76 77 private void Form2Open() 78 { 79 var form = new Form2(); 80 form.ShowDialog(); 81 } 82 } 83} 84 85-------------------------------------------------------------------------- 86 87using System; 88using System.Windows.Forms; 89 90namespace SandboxForms 91{ 92 public partial class Form2 : Form 93 { 94 public Form2() 95 { 96 InitializeComponent(); 97 } 98 99 private void button1_Click(object sender, EventArgs e) 100 { 101 throw new Exception("Form2の例外"); 102 } 103 } 104} 105

回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/10/30 06:03