メッセージ

2011年12月27日の記事

2011/12/27(火).NETのSerialPortでケーブルを抜くと例外

.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の変更で直る可能性有り。
OK キャンセル 確認 その他