2011/12/27(火).NETのSerialPortでケーブルを抜くと例外
2011/12/27 13:40
原因は.NET側のバグ。ケーブルの挿抜というかCOMポートが消えることを考慮していない。
発生する例外は把握している限りで2種(UnauthorizedAccessException, ObjectDisposedException)。前者は、Dispose()中に発生する。後者は、SerialPort内部で動いてるThreadが出してくる。
UnauthorizedAccessExceptionはラッパークラスを作って、Dispose()をオーバーライドしtry~catchで囲ってやることで対処可能。以下を参照。簡単なのでコードは書かない。
街角のリブロガー: C# SerialPortのエラー「UnauthorizedAccessException」対策
ObjectDisposedExceptionの方はちょっと難しい。発生箇所は.NET内部の別スレッドのようで、捕まえられる場所を思いつかない(存在しない?)しタイミングも不定。Thread.GetDomain().UnhandledExceptionで発生タイミングはとらえられるが、ここではキャンセルできない。古い.NET、おそらく1.1以下だとこの手の例外は処理継続となるのだが、.NET 2.0以降はアプリが落ちてしまう(WinXP/Win7, .NET 3.5で確認)。
ということで、どうもコードでの容易な対処方法がないようだ。アプリケーション構成ファイルでの回避策があるらしいので以下を参照。
SerialPort Crashes after disconnect of USB COM port | Microsoft Connect
こんな感じでよい。
program.cs
[STAThread] static void Main() { ... //メインスレッド以外の非ハンドル例外処理 Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Application_UnhandledException); ... } public static void Application_UnhandledException( object sender, UnhandledExceptionEventArgs e ){ if( e.ExceptionObject != null && e.ExceptionObject.GetType() == typeof(ObjectDisposedException)) { //.NET3.5のSerialPortのバグで、ケーブル挿抜後にハンドル不能の //ObjectDisposedExceptionが返ることがある。このため、未ハンドル例外処理にて //ObjectDisposedExceptionについてのみ無視する。 //何もしない } else { //何かメッセージを出力 Application.Exit(); } }以下のアプリケーション構成ファイルをアプリケーションと同じディレクトリに置く(hoge.exeが実行ファイルなら、hoge.exe.configとなる)。
hoge.exe.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <legacyUnhandledExceptionPolicy enabled="1"/> </runtime> </configuration>構成ファイルを上記のように書くと、非ハンドル例外に関しては処理継続となる。釈然としないが、どうもこれが楽な方法らしい。
その他の非ハンドル例外を無視して良ければ、program.cs側の記述は不要。
.NETのバージョン変更、OSの変更で直る可能性有り。