Click here to Skip to main content
15,892,537 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 100.1K   4.6K   41  
An article on creating a library that takes advantage of the native Win32 overlapped IO for asynchronous named pipe communication.
Imports System.Runtime.InteropServices
''' <summary>
''' Connects to named pipes.
''' </summary>
''' <remarks></remarks>
Public Class PipeClient
    Implements IDisposable
    Private mHandle As New Microsoft.Win32.SafeHandles.SafeFileHandle(IntPtr.Zero, True)
    Private mBufferSize As Integer
#Region "Constructors "
    ''' <summary>
    ''' Instantiates the client.
    ''' <example>
    ''' 'Creates an instance that will connect to myPipe on the local machine and will have a 4 kb buffer.
    '''  Dim PipeClientInstance As New PipeClient("\\.\pipe\myPipe",4096) 
    ''' </example>
    ''' </summary>
    ''' <param name="fullName">The full name of the pipe to connect. Example: \\.\pipe\SomePipe</param>
    ''' <param name="bufferSize">The size of the input/output buffers of the IO.Stream returned by ClientStream.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal fullName As String, ByVal bufferSize As Integer)
        mBufferSize = bufferSize
        mFullName = fullName
        mHandle.SetHandleAsInvalid()
    End Sub

    ''' <summary>
    ''' Instantiates the client with a buffer size of 2048 bytes.
    ''' <example>
    ''' 'Creates an instance that will connect to myPipe on the local machine and will have a 2 kb buffer.
    '''  Dim PipeClientInstance As New PipeClient("\\.\pipe\myPipe")
    ''' </example>
    ''' </summary>
    ''' <param name="fullName">The full name of the pipe to connect. Example: \\.\pipe\SomePipe</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal fullName As String)
        Me.New(fullName, 2048)
    End Sub
#End Region
#Region "Private Methods "
    ''' <summary>
    ''' Returns an instance of IO.Stream which the client can use to communicate with the server.
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GetStream() As IO.Stream
        If Me.mHandle.IsInvalid Then Throw New InvalidOperationException("Client not connected.")
        Return New IO.FileStream(mHandle, IO.FileAccess.ReadWrite, mBufferSize, True)
    End Function
    Private Sub ThrowUnknownException(ByVal FunctionName As String)
        Dim ex As New System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error)
        Throw New InvalidOperationException("Error #" & Marshal.GetLastWin32Error & " was returned by the operating system while calling " & FunctionName & ". Description: " & ex.Message, ex)
    End Sub
#End Region
#Region "Public Properties "
    ''' <summary>
    ''' Returns True if the client is connected.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property IsConnected() As Boolean
        Get
            Return Not mHandle.IsInvalid
        End Get
    End Property

    Private mFullName As String
    ''' <summary>
    ''' The client's fullname as passed into the constructor.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property FullName() As String
        Get
            Return mFullName
        End Get
        Set(ByVal value As String)
            If Not Me.IsConnected Then
                mFullName = value
            Else
                Throw New InvalidOperationException("Property is read-only while the client is connected.")
            End If
            Dim T As New Net.Sockets.TcpClient
        End Set
    End Property

    Private mTimeOut As UInt16 = UInt16.MaxValue
    ''' <summary>
    ''' The time in milliseconds to wait for a connect operation. Use UInt16.MaxValue to wait indefinately or 0 to use the same value as the server pipe.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property TimeOut() As UInt16
        Get
            Return mTimeOut
        End Get
        Set(ByVal value As UInt16)
            mTimeOut = value
        End Set
    End Property

    Private mStream As IO.Stream
    ''' <summary>
    ''' An instance of IO.Stream used to send and receive data.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property ClientStream() As IO.Stream
        Get
            If Me.IsConnected Then
                Return mStream
            Else
                Throw New InvalidOperationException("Not connected")
            End If
        End Get
    End Property
#End Region
#Region "Control Methods "
    ''' <summary>
    ''' Connects the client to an instance of the server pipe.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Connect()
        If IsConnected Then Throw New InvalidOperationException("Already connected. Call Close() first.")
        If NativeMethods.WaitNamedPipe(mFullName, Me.TimeOut) Then
            mHandle = New Microsoft.Win32.SafeHandles.SafeFileHandle( _
                                    NativeMethods.CreateFile(FullName, IO.FileAccess.ReadWrite, IO.FileShare.ReadWrite, 0, IO.FileMode.Open, NativeMethods.FILE_FLAG_OVERLAPPED, 0), _
                                     True)
            If mHandle.IsInvalid Then ThrowUnknownException("CreateFile") Else mStream = Me.GetStream
        Else
            Select Case Marshal.GetLastWin32Error
                Case 2
                    Throw New IO.FileNotFoundException("A pipe with the specified name is not open on the target machine.", Me.FullName)
                Case 121
                    Throw New TimeoutException("The connect operation timed out.")
                Case Else
                    ThrowUnknownException("WaitNamedPipe")
            End Select
        End If


    End Sub
    ''' <summary>
    ''' Closes the connection with the server.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Close()
        mStream.Close()
        mHandle.SetHandleAsInvalid()
    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
    ' IDisposable
    Private disposedValue As Boolean = False        ' To detect redundant calls
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                Me.mHandle.Close()
                Me.mStream.Dispose()
            End If
        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