clefranc 0 Newbie Poster

Hi,
I've wrote a class that inherits from IO.Ports.SerialPort namespace. The goal of my custom class is to manage delegates (if needed) so I can get rid of them in my main form. The class works great, but it sometimes deadlock when closing the form, often at line 30 of the SerialPortCT class, or at line 39 of the frmForm1. I've tried framework 2.0 and 3.5SP1 with same result. Can someone have any idea how to close the form without thread issues?

Thanks,
Christian

The class:

Public Class SerialPortCT

    Inherits IO.Ports.SerialPort

    Private _sync As System.ComponentModel.ISynchronizeInvoke

    Public Shadows Event DataReceived As EventHandler(Of System.IO.Ports.SerialDataReceivedEventArgs)
    Public Shadows Event ErrorReceived As EventHandler(Of System.IO.Ports.SerialErrorReceivedEventArgs)
    Public Shadows Event PinChanged As EventHandler(Of System.IO.Ports.SerialPinChangedEventArgs)

    Public Sub New(ByVal sync As System.ComponentModel.ISynchronizeInvoke)

        ' Parent thread
        _sync = sync

    End Sub

    Private Sub DataReceivedCrossThreadEventHandler(ByVal sender As Object, ByVal e As Object)

        RaiseEvent DataReceived(sender, CType(e, IO.Ports.SerialDataReceivedEventArgs))

    End Sub

    Private Sub SerialPortCT_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles MyBase.DataReceived

        If Not _sync Is Nothing AndAlso _sync.InvokeRequired Then ' If source thread require invoking...
            Dim AsyncResults As IAsyncResult
            AsyncResults = _sync.BeginInvoke(New EventHandler(AddressOf DataReceivedCrossThreadEventHandler), New Object() {sender, e}) ' ...invoke asynchronous delegate with arguments
            Dim ReturnValue As Object
            ReturnValue = _sync.EndInvoke(AsyncResults) ' ...and wait for UI thread to complete its task
        Else ' ...otherwise...
            DataReceivedCrossThreadEventHandler(sender, e) ' ...call the delegate directly
        End If

    End Sub

End Class

The main form:

Public Class frmForm1

    Private WithEvents COMPort As SerialPortCT

    Private Sub frmForm1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        ' Set default UI behavior
        ComboBox1.Enabled = False
        ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
        Button1.Enabled = False
        Button1.Text = "CONNECT"

        COMPort = New SerialPortCT(Me)

        ' Set default settings for the port
        COMPort.BaudRate = 9600
        COMPort.Parity = IO.Ports.Parity.None
        COMPort.DataBits = 8
        COMPort.StopBits = IO.Ports.StopBits.One
        COMPort.ReceivedBytesThreshold = 1
        COMPort.Handshake = IO.Ports.Handshake.None

        ' Populate the combobox with available serial port
        For Each port In IO.Ports.SerialPort.GetPortNames
            ComboBox1.Items.Add(port)
        Next

        If ComboBox1.Items.Count > 0 Then
            ComboBox1.SelectedIndex = 0
            ComboBox1.Enabled = True
            Button1.Enabled = True
        End If

    End Sub

    Private Sub frmForm1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        If COMPort.IsOpen Then
            COMPort.Close()
        End If

        COMPort = Nothing

        'System.Environment.Exit(0) ' Still deadlock

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        If COMPort.IsOpen Then
            COMPort.Close()
            ComboBox1.Enabled = True
            Button1.Text = "CONNECT"
        Else
            Try
                COMPort.Open()
                ComboBox1.Enabled = False
                Button1.Text = "DECONNECT"
            Catch ex As Exception
                MessageBox.Show(ex.Message, Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End Try
        End If

    End Sub

    Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMPort.DataReceived

        TextBox1.Text &= COMPort.ReadExisting
        TextBox1.SelectionStart = TextBox1.TextLength
        TextBox1.ScrollToCaret()

    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged

        COMPort.PortName = CStr(ComboBox1.SelectedItem)

    End Sub

End Class