SerialPortをCloseする際の'System.IO.IOException' の初回例外について
ymaiyと申します。
Visual Basic 2005にてアプリケーション開発をしようとしています。(これまではVB6)
http://www.microsoft.com/japan/msdn/vbasic/migration/tips/SeriaPort/
上記のページのサンプルをダウンロードし、通信相手に合わせて多少ソースを変更して実行したところ、Closeする際に、
'System.IO.IOException' の初回例外が System.dll で発生しました。
となり、止まってしまいました。Try~Catch処理でエラー処理しようとしましたが、うまくいきませんでした。
「'System.IO.IOException' の初回例外が System.dll で発生しました。」が出た場合の対処方法を教えていただけませんでしょうか。よろしくお願いいたします。
すべての返信
- サンプルでは例外も発生せずに動作しているようなので、
変更した箇所に問題があると思うのですが、どのように変更されたかが
分からない為、対処方法を見出せません。。。通信ログをファイルに出力しているとかかな?
ymaiyです。
早速の返信ありがとうございます。そして、説明不足ですみませんでした。
サンプルソースの変更点は2箇所で
'*****************************************************
'*****************************************************
ではさまれた部分です。Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
SerialPort1.PortName = TextBox1.Text
If SerialPort1.IsOpen = True Then
MessageBox.Show("すでに" & SerialPort1.PortName & "は接続されています。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Call SerialPort1.Open()
'*****************************************************
'通信コマンド送信
SerialPort1.WriteLine(";>PA7")
'*****************************************************
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubPrivate Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If SerialPort1.IsOpen = True Then
Call SerialPort1.Close()
End If
End SubPrivate Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
If TextBox2.Text.Length = 0 Then
MessageBox.Show("送信文字列を入力してください", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
TextBox2.Focus()
Exit Sub
End IfTry
'*****************************************************
'SerialPort1.WriteLine(TextBox2.Text)
SerialPort1.WriteLine("|" & TextBox2.Text & vbCr)
'*****************************************************
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubDelegate Sub AddDataDelegate(ByVal str As String)
Private Sub AddData(ByVal str As String)
TextBox3.Text = TextBox3.Text + str
End SubPrivate Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim strDataReceived As String
Dim add As New AddDataDelegate(AddressOf AddData)
Try
strDataReceived = SerialPort1.ReadLine
Catch ex As Exception
strDataReceived = ex.Message
End Try
TextBox3.Invoke(add, strDataReceived)
End Sub
End Class- 上記のソースをテストしてみましたが、当方の環境ではエラーにはなりませんでした。。。
どうするかな。。。 ymaiyです。返信ありがとうございます。
その後、またサンプルソースを変更し、ステップ実行で動作を確認しました。
変更部分は
'*****************************************************
'*****************************************************
ではさまれた部分です。Call SerialPort1.Close()のところで、SerialPort1_DataReceivedイベントのエラー処理部分に飛び、「スレッドの終了またはアプリケーションの要求によって、I/O処理は中止されました。」というメッセージを表示しました。その後、ポートは閉じられていました。根本的に何かおかしいのでしょうか?通信相手を別のものに変えてテストしてみたいと思います。
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
SerialPort1.PortName = TextBox1.Text
If SerialPort1.IsOpen = True Then
MessageBox.Show("すでに" & SerialPort1.PortName & "は接続されています。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Call SerialPort1.Open()
'*****************************************************
'通信コマンド送信
SerialPort1.WriteLine(";>PA7")
'*****************************************************
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubPrivate Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'*****************************************************
'If SerialPort1.IsOpen = True Then
' Call SerialPort1.Close()
'End If
Try
If SerialPort1.IsOpen = True Then
Call SerialPort1.Close()
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
'*****************************************************
End SubPrivate Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
If TextBox2.Text.Length = 0 Then
MessageBox.Show("送信文字列を入力してください", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
TextBox2.Focus()
Exit Sub
End IfTry
'*****************************************************
'SerialPort1.WriteLine(TextBox2.Text)
SerialPort1.WriteLine("|" & TextBox2.Text & vbCr)
'*****************************************************
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubDelegate Sub AddDataDelegate(ByVal str As String)
Private Sub AddData(ByVal str As String)
TextBox3.Text = TextBox3.Text + str
End SubPrivate Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim strDataReceived As String
Dim add As New AddDataDelegate(AddressOf AddData)Try
strDataReceived = SerialPort1.ReadLine
'*****************************************************
TextBox3.Invoke(add, strDataReceived)
'*****************************************************
Catch ex As Exception
'*****************************************************
'strDataReceived = ex.Message
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
'*****************************************************
End Try
'*****************************************************
'TextBox3.Invoke(add, strDataReceived)
'*****************************************************
End Sub
End Class- DataReceivedイベント内で、ReadLineメソッドで入力バッファを読み込んでいますが、
http://msdn2.microsoft.com/ja-jp/library/system.io.ports.serialport.readline.aspx
に、「入力バッファ内のNewLine値まで読み取ります。」とありますが、ymaiyさんのテスト環境の相手の送信してくるバッファにNewLineが無いのが原因ではないでしょうか?ReadLineメソッドでなく、ReadExistingメソッドを利用してみてはいかがでしょうか?
http://msdn2.microsoft.com/ja-jp/library/system.io.ports.serialport.readexisting.aspx
ymaiyです。返信ありがとうございます。
教えていただいたReadExistingメソッドの利用で半角文字の送受信確認できました。
初心者ですみません。全角文字は化けてしまうのですが、どのようにしたら文字化けしなくなるか教えていただけませんでしょうか?よろしくお願いいたします。
- SerialPort1.Encoding = System.Text.Encoding.UTF8
とか・・・現在、どのようなテスト環境なのかな・・・
以下のような環境で、4つのテスト行ってみました。 PC:WindowsXP
A:PC-コードスキャナ接続
B:PC(COM1)-PC(COM2)接続
Bの接続で、
1.SerialPort1.Encoding = System.Text.Encoding.UTF8
とすると、長い文字列を送ると全部送れませんでした。
ex) 123456789012345678901234567890 →送信→ 4567890
2.SerialPort1.Encoding = System.Text.Encoding.GetEncoding("shift-jis")
とすると、同様に長い文字列が全部送れず、さらに全角文字が文字化けしました。
Aの接続も同様にテストしたところ、
3.SerialPort1.Encoding = System.Text.Encoding.UTF8
とすると、全角文字が文字化けしました。
4.SerialPort1.Encoding = System.Text.Encoding.GetEncoding("shift-jis")
では、特に問題ありませんでした。
結果的には、Aの接続の4でやりたいことは出来そうのなのですが、
Bの接続の1で文字列全てが送信できない点が気になります。BaudRateプロパティを変化させてみましたが、結果は変わりませんでした。何がよくないのでしょうか?
以下ソースです。
Imports System.Text
Public Class Form1
' 接続ボタン
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
If SerialPort1.IsOpen = False Then
SerialPort1.PortName = TextBox1.Text
Call SerialPort1.Open()
'通信コマンド送信
SerialPort1.WriteLine(";>PA7")
'-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
SerialPort1.Encoding = System.Text.Encoding.UTF8
'SerialPort1.Encoding = System.Text.Encoding.GetEncoding("shift-jis")
'-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Else
MessageBox.Show("すでに" & SerialPort1.PortName & "は接続されています。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub' 切断ボタン
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Try
If SerialPort1.IsOpen = True Then
Call SerialPort1.Close()
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub' 送信ボタン
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
If TextBox2.Text.Length = 0 Then
MessageBox.Show("送信文字列を入力してください", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
TextBox2.Focus()
Exit Sub
End IfTry
SerialPort1.WriteLine("|" & TextBox2.Text & vbCr)
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubDelegate Sub AddDataDelegate(ByVal str As String)
Private Sub AddData(ByVal str As String)
TextBox3.Text = TextBox3.Text + str
End Sub' データ受信イベント
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim add As New AddDataDelegate(AddressOf AddData)
Dim iCount As Integer
Dim sTmp As String
Static sComIn As StringTry
sTmp = SerialPort1.ReadExistingiCount = InStr(sTmp, vbCr)
If iCount > 0 Then
sComIn = Mid(sTmp, 1, iCount - 1)
TextBox3.Invoke(add, sComIn)
sComIn = ""
Else
sComIn = sComIn + sTmp
End IfCatch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End SubEnd Class
ソースを参考にさせてもらったおかげで私の問題は解決できました。
お礼に私のソースを公開します。
'受信開始中断キーイベント
Private Sub startstop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles startstop.Click
Dim i As Integer
If SerialPort1.IsOpen = False Then
Try
i = comportcombobox.SelectedIndex + 1
SerialPort1.PortName = "COM" + i.ToString()
i = baudratecombobox.SelectedIndex
If i = 0 Then
i = 38400
ElseIf i = 1 Then
i = 19200
Else
i = 9600
End If
SerialPort1.BaudRate = i
SerialPort1.Encoding = System.Text.Encoding.GetEncoding("shift-jis")
Call SerialPort1.Open()
startstop.Text = "受信停止"
comportcombobox.Enabled = False
baudratecombobox.Enabled = False
transgroup.Enabled = True
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Else
Try
Call SerialPort1.Close()
startstop.Text = "受信開始"
comportcombobox.Enabled = True
baudratecombobox.Enabled = True
transgroup.Enabled = False
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End If
End SubDelegate Sub AddDataDelegate(ByVal str As String)
Private Sub AddData(ByVal str As String)
logtext.AppendText(str)
End Sub'受信イベント
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim add As New AddDataDelegate(AddressOf AddData)
Static rxbuff As String = ""
Dim rxdata As String
Try
rxdata = SerialPort1.ReadExisting
rxbuff += rxdata
If rxdata.IndexOf(vbCr) > 0 Then
logtext.Invoke(add, rxbuff)
rxbuff = ""
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub以上
ちなみに参考にさせてもらったソースでは
sComIn = Mid(sTmp, 1, iCount - 1)
TextBox3.Invoke(add, sComIn)
sComIn = ""
sTmpの使われなかった部分が捨てられちゃってますね・・・・すみません。前のままでは文字化けします。
その対策案です(^ ^ ; )
'■■■文字化け改善■■■
Static mojibake As Boolean = False
Static rxbuff As Byte
Dim rxdata(2048) As Byte
Dim offset As Integer = 0
'<断片データ挿入>
If mojibake = True Then
mojibake = False
rxdata(0) = rxbuff
offset = 1
End If
'<受信バッファ読み込み>
Dim rxcnt As Integer = SerialPort1.BytesToRead
SerialPort1.Read(rxdata, offset, rxcnt)
rxcnt += offset
Dim str As String = System.Text.Encoding.GetEncoding("Shift-JIS").GetString(rxdata, 0, rxcnt)
'<文字断片検出>
' (最後の文字が化けていないかのチェック)
Dim laststr As String = Microsoft.VisualBasic.Right(str, 1)
offset = Asc(laststr)
' (全角文字以外は除外:全角は-772以下となる)
If offset < -772 Then
rxbuff = CByte((256 * 256 + offset) Mod 256)
' (最後のHEXデータが合っていなければ文字化け発生!)
If rxbuff <> rxdata(rxcnt - 1) Then
' (断片は次回送る)
str = Microsoft.VisualBasic.Left(str, str.Length - 1)
rxbuff = rxdata(rxcnt - 1)
mojibake = True
End If
End If
logtext.Invoke(add, str)