Click here to Skip to main content
15,886,026 members
Articles / Programming Languages / Visual Basic

Asynchronous Named Pipes (Overlapped IO) with VB.NET

Rate me:
Please Sign up or sign in to vote.
4.65/5 (10 votes)
6 Dec 20063 min read 99.8K   4.6K   41  
An article on creating a library that takes advantage of the native Win32 overlapped IO for asynchronous named pipe communication.
''' <summary>
''' Listens for connections from named pipe clients.
''' </summary>
''' <remarks></remarks>
Public Class PipeListener
    Implements IDisposable
    Private ListenningThread As Threading.Thread
    Private ThreadSyncControl As New System.Windows.Forms.Control
    Private mStopEvent As New Threading.ManualResetEvent(False)
    Private mSyncEvent As New Threading.ManualResetEvent(False)
    ''' <summary>
    ''' Occurs when a named pipe client connects.
    ''' </summary>
    ''' <remarks></remarks>
    Public Event ClientConnected As EventHandler(Of ClientConnectedEventArgs)
#Region "Constructors "
    ''' <summary>
    ''' Instantiates the PipeListenner with a bufferSize of 16,384 bytes and a unique name(based on Guid.NewGuid).
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        Me.New(Guid.NewGuid.ToString)
    End Sub
    ''' <summary>
    ''' Instantiates the PipeListenner with a bufferSize of 2048 bytes.
    ''' </summary>
    ''' <param name="Name">Pipe name. Must be up to 246 characters long and without backslashes (\).</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal name As String)
        Me.New(name, 2048)
    End Sub


    ''' <summary>
    ''' Instantiates the PipeListenner class.
    ''' </summary>
    ''' <param name="Name">Pipe name. Must be up to 246 characters long and without backslashes (\).</param>
    ''' <param name="bufferSize">The size of the input/output buffers.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal name As String, ByVal bufferSize As Integer)
        mBufferSize = bufferSize
        mName = name
        ThreadSyncControl.CreateControl()
    End Sub
#End Region
#Region "Public Properties "
    Private mBufferSize As Integer
    ''' <summary>
    ''' Returns the input/output buffer size passed in to the constructor.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property BufferSize() As Integer
        Get
            Return mBufferSize
        End Get
    End Property
    Dim mName As String
    ''' <summary>
    ''' Pipe name. Must be up to 246 characters long and without backslashes (\).
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Name() As String
        Get
            Return mName
        End Get
    End Property

    Private mListenning As Boolean
    ''' <summary>
    ''' Returns True if the listenner is waiting for incoming connections.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Listenning() As Boolean
        Get
            Return mListenning
        End Get
    End Property
#End Region
#Region "Control Methods "
    Public Sub StartListenning()
        If mListenning Then Throw New InvalidOperationException("Already listenning.")
        mListenning = True
        ListenningThread = New Threading.Thread(AddressOf OnServiceRequest)
        ListenningThread.IsBackground = True
        ListenningThread.Start()
        mSyncEvent.WaitOne(-1, False)
        mSyncEvent.Reset()
    End Sub

    Public Sub StopListenning()
        If Not mListenning Then
            Throw New InvalidOperationException("Not listenning.")
        End If
        mListenning = False
        mStopEvent.Set()
        mSyncEvent.WaitOne(-1, False)
        mSyncEvent.Reset()
    End Sub
#End Region
#Region "Private Methods"
    Private Sub OnServiceRequest()
        Dim Async As IAsyncResult, eventRaiser As New iInvokeEvent(AddressOf InvokeEvent)
        'Dim mSyncEvents As IntPtr() = {mStopEvent.Handle, Nothing} 'This should be uncommented for final build?! lol
        Dim mSyncEvents As Threading.EventWaitHandle() = {mStopEvent, Nothing}
        mSyncEvent.Set()
        Dim ServerPipe As ServerPipeInstance
        Do
            ServerPipe = New ServerPipeInstance(Name, IO.FileAccess.ReadWrite, mBufferSize, True)
            Async = ServerPipe.BeginConnect(Nothing, Nothing)
            If Not Async.CompletedSynchronously Then
                'mSyncEvents(1) = Async.AsyncWaitHandle.Handle 'Final build
                mSyncEvents(1) = Async.AsyncWaitHandle

                'Select Case NativeMethods.WaitForMultipleObjects(mSyncEvents.Length, mSyncEvents, False, UInteger.MaxValue) 'Final build
                Select Case Threading.WaitHandle.WaitAny(mSyncEvents, -1, True)
                    Case 0 'Signal by application thread
                        Debug.WriteLine(Now.ToShortTimeString & ": Exiting")
                        mStopEvent.Reset()
                        Exit Do
                    Case 1 'Signal by OS - Client Connected
                        ServerPipe.EndConnect(Async)
                        Dim args As New ClientConnectedEventArgs(ServerPipe)
                        If Me.ThreadSyncControl.InvokeRequired Then
                            Me.ThreadSyncControl.BeginInvoke(eventRaiser, New Object() {args})
                        Else
                            eventRaiser.BeginInvoke(args, Nothing, Nothing)
                        End If
                End Select
            Else
                ServerPipe.EndConnect(Async)
                Dim args As New ClientConnectedEventArgs(ServerPipe)
                If Me.ThreadSyncControl.InvokeRequired Then
                    Me.ThreadSyncControl.BeginInvoke(eventRaiser, New Object() {args})
                Else
                    eventRaiser.BeginInvoke(args, Nothing, Nothing)
                End If
            End If
        Loop Until Not mListenning
        If Not Async Is Nothing Then
            If Not Async.IsCompleted Then
                ServerPipe.Disconnect()
                ServerPipe.Dispose()
            End If
        End If
        mSyncEvent.Set()
    End Sub
    Private Delegate Sub iInvokeEvent(ByVal args As EventArgs)
    Private Sub InvokeEvent(ByVal args As EventArgs)
        If TypeOf args Is ClientConnectedEventArgs Then
            RaiseEvent ClientConnected(Me, args)
        End If
    End Sub
#End Region
#Region " IDisposable Support "
    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    Private disposedValue As Boolean = False        ' To detect redundant calls
    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            'TODO: Check for any resources that should be free (none at first glance)
        End If
        Me.disposedValue = True
    End Sub
#End Region

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Greece Greece
Athens College Graduate - Class of '01
Deree College Student
IT Manager - Heliostat Ltd(www.heliostat.gr)

Comments and Discussions