.NET(WinXP, .NET 3.5で発生)のSerialPortクラスで、USB-Serial変換ケーブルを使用している際に起こる問題。このケーブルに紐づくCOMポートをOpen()後、Close()前にケーブルを抜くと例外が発生する。
原因は.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の変更で直る可能性有り。