Click here to Skip to main content
15,896,320 members
Articles / Programming Languages / C#

.NET Interprocess Communication Revisited

Rate me:
Please Sign up or sign in to vote.
4.96/5 (30 votes)
4 Jan 2010CPOL4 min read 122.2K   2.3K   111  
The XDMessaging 2.0 library provides an easy-to-use, zero configuration alternative to existing IPC implementations.
'=============================================================================
'*
'*	(C) Copyright 2007, Michael Carlisle (mike.carlisle@thecodeking.co.uk)
'*
'*   http://www.TheCodeKing.co.uk
'*  
'*	All rights reserved.
'*	The code and information is provided "as-is" without waranty of any kind,
'*	either expressed or implied.
'*
'*=============================================================================
'

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Imports TheCodeKing.Net.Messaging
Imports System.Threading
Imports System.Diagnostics

Namespace TheCodeKing.Demo
    ''' <summary>
    ''' A demo messaging application which demostrates the cross AppDomain Messaging API.
    ''' This independent instances of the application to receive and send messages between
    ''' each other.
    ''' </summary>
    Partial Public Class Messenger
        Inherits Form
        ''' <summary>
        ''' The instance used to listen to broadcast messages.
        ''' </summary>
        Private listener As IXDListener

        ''' <summary>
        ''' The instance used to broadcast messages on a particular channel.
        ''' </summary>
        Private broadcast As IXDBroadcast

        ''' <summary>
        ''' Delegate used for invoke callback.
        ''' </summary>
        ''' <param name="dataGram"></param>
        ''' <remarks></remarks>
        Private Delegate Sub UpdateDisplay(ByVal dataGram As DataGram)

        ''' <summary>
        ''' Default constructor.
        ''' </summary>
        Public Sub New()
            InitializeComponent()
        End Sub
        ''' <summary>
        ''' The onload event which initializes the messaging API by registering
        ''' for the Status and Message channels. This also assigns a delegate for
        ''' processing messages received. 
        ''' </summary>
        ''' <param name="e"></param>
        Protected Overloads Overrides Sub OnLoad(ByVal e As EventArgs)
            MyBase.OnLoad(e)

            Dim tooltips As New ToolTip()
            tooltips.SetToolTip(sendBtn, "Broadcast message on Channel 1" & vbCr & vbLf & "and Channel2")
            tooltips.SetToolTip(groupBox1, "Choose which channels" & vbCr & vbLf & "this instance will" & vbCr & vbLf & "listen on")
            tooltips.SetToolTip(Mode, "Choose which mode" & vbCr & vbLf & "to use for sending" & vbCr & vbLf & "and receiving")

            UpdateDisplayText("Launch multiple instances of this application to demo interprocess communication." & vbCr & vbLf, Color.Gray)

            ' set the handle id in the form title
            Me.Text += String.Format(" - Window {0}", Me.Handle)

            InitializeMode(XDTransportMode.WindowsMessaging)

            ' broadcast on the status channel that we have loaded
            broadcast.SendToChannel("Status", String.Format("{0} has joined", Me.Handle))
        End Sub

        ''' <summary>
        ''' The closing overrride used to broadcast on the status channel that the window is
        ''' closing.
        ''' </summary>
        ''' <param name="e"></param>
        Protected Overloads Overrides Sub OnClosing(ByVal e As CancelEventArgs)
            MyBase.OnClosing(e)
            broadcast.SendToChannel("Status", String.Format("{0} is shutting down", Me.Handle))
        End Sub
        ''' <summary>
        ''' The delegate which processes all cross AppDomain messages and writes them to screen.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub OnMessageReceived(ByVal sender As Object, ByVal e As XDMessageEventArgs)
            If MyBase.InvokeRequired Then
                Try
                    Dim callback As New UpdateDisplay(AddressOf UpdateDisplayText)
                    MyBase.Invoke(callback, e.DataGram)
                Catch
                End Try
            Else
                Me.UpdateDisplayText(e.DataGram)
            End If
        End Sub

        ''' <summary>
        ''' A helper method used to update the Windows Form.
        ''' </summary>
        ''' <param name="dataGram">dataGram</param>
        Private Sub UpdateDisplayText(ByVal dataGram As DataGram)
            Dim textColor As Color
            Select Case dataGram.Channel.ToLower()
                Case "status"
                    textColor = Color.Green
                    Exit Select
                Case Else
                    textColor = Color.Blue
                    Exit Select
            End Select
            Dim msg As String = String.Format("{0}: {1}" & vbCr & vbLf, dataGram.Channel, dataGram.Message)
            UpdateDisplayText(msg, textColor)
        End Sub

        ''' <summary>
        ''' A helper method used to update the Windows Form.
        ''' </summary>
        ''' <param name="message">The message to be displayed on the form.</param>
        ''' <param name="textColor">The colour text to use for the message.</param>
        Private Sub UpdateDisplayText(ByVal message As String, ByVal textColor As Color)
            If Not IsDisposed Then
                Me.displayTextBox.AppendText(message)
                Me.displayTextBox.[Select](Me.displayTextBox.Text.Length - message.Length + 1, Me.displayTextBox.Text.Length)
                Me.displayTextBox.SelectionColor = textColor
                Me.displayTextBox.[Select](Me.displayTextBox.Text.Length, Me.displayTextBox.Text.Length)
                Me.displayTextBox.ScrollToCaret()
            End If
        End Sub

        ''' <summary>
        ''' Sends a user input string on the Message channel. A message is not sent if
        ''' the string is empty.
        ''' </summary>
        ''' <param name="sender">The event sender.</param>
        ''' <param name="e">The event args.</param>
        Private Sub sendBtn_Click(ByVal sender As Object, ByVal e As EventArgs)
            SendMessage()
        End Sub

        ''' <summary>
        ''' Wire up the enter key to submit a message.
        ''' </summary>
        ''' <param name="m"></param>
        ''' <param name="k"></param>
        ''' <returns></returns>
        Protected Overloads Overrides Function ProcessCmdKey(ByRef m As Message, ByVal k As Keys) As Boolean
            ' allow enter to send message
            If m.Msg = 256 AndAlso k = Keys.Enter Then
                SendMessage()
                Return True
            End If
            Return MyBase.ProcessCmdKey(m, k)
        End Function

        ''' <summary>
        ''' Helper method for sending message.
        ''' </summary>
        Private Sub SendMessage()
            If Me.inputTextBox.Text.Length > 0 Then
                ' send to all channels
                broadcast.SendToChannel("Channel1", String.Format("{0} says {1}", Me.Handle, Me.inputTextBox.Text))
                broadcast.SendToChannel("Channel2", String.Format("{0} says {1}", Me.Handle, Me.inputTextBox.Text))
                Me.inputTextBox.Text = ""
            End If
        End Sub

        ''' <summary>
        ''' Adds or removes the Message channel from the messaging API. This effects whether messages 
        ''' sent on this channel will be received by the application. Status messages are broadcast 
        ''' on the Status channel whenever this setting is changed. 
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub channel1_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
            If channel1Check.Checked Then
                listener.RegisterChannel("Channel1")
                broadcast.SendToChannel("Status", String.Format("{0} is registering Channel1.", Me.Handle))
            Else
                listener.UnRegisterChannel("Channel1")
                broadcast.SendToChannel("Status", String.Format("{0} is unregistering Channel1.", Me.Handle))
            End If
        End Sub

        ''' <summary>
        ''' Adds or removes the Message channel from the messaging API. This effects whether messages 
        ''' sent on this channel will be received by the application. Status messages are broadcast 
        ''' on the Status channel whenever this setting is changed. 
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub channel2_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
            If channel2Check.Checked Then
                listener.RegisterChannel("Channel2")
                broadcast.SendToChannel("Status", String.Format("{0} is registering Channel2.", Me.Handle))
            Else
                listener.UnRegisterChannel("Channel2")
                broadcast.SendToChannel("Status", String.Format("{0} is unregistering Channel2.", Me.Handle))
            End If
        End Sub

        ''' <summary>
        ''' Adds or removes the Status channel from the messaging API. This effects whether messages 
        ''' sent on this channel will be received by the application. Status messages are broadcast 
        ''' on the Status channel whenever this setting is changed. 
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub statusChannel_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
            If statusCheckBox.Checked Then
                listener.RegisterChannel("Status")
                broadcast.SendToChannel("Status", String.Format("{0} is registering Status.", Me.Handle))
            Else
                listener.UnRegisterChannel("Status")
                broadcast.SendToChannel("Status", String.Format("{0} is unregistering Status.", Me.Handle))
            End If
        End Sub

        ''' <summary>
        ''' Initialize the broadcast and listener mode.
        ''' </summary>
        ''' <param name="mode">The new mode.</param>
        Private Sub InitializeMode(ByVal mode As XDTransportMode)
            If listener IsNot Nothing Then
                ' ensure we dispose any previous listeners, dispose should aways be
                ' called on IDisposable objects when we are done with it to avoid leaks
                listener.Dispose()
            End If

            ' creates an instance of the IXDListener object using the given implementation  
            listener = XDListener.CreateListener(mode)

            ' attach the message handler
            AddHandler listener.MessageReceived, AddressOf OnMessageReceived

            ' register the channels we want to listen on
            If statusCheckBox.Checked Then
                listener.RegisterChannel("Status")
            End If

            ' register if checkbox is checked
            If channel1Check.Checked Then
                listener.RegisterChannel("Channel1")
            End If

            ' register if checkbox is checked
            If channel2Check.Checked Then
                listener.RegisterChannel("Channel2")
            End If

            ' if we already have a broadcast instance
            If broadcast IsNot Nothing Then
                broadcast.SendToChannel("Status", String.Format("{0} is changing mode to {1}", Me.Handle, mode))
            End If

            ' create an instance of IXDBroadcast using the given mode, 
            ' note IXDBroadcast does not implement IDisposable
            broadcast = XDBroadcast.CreateBroadcast(mode, propagateCheck.Checked)
        End Sub

        ''' <summary>
        ''' On form changed mode.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub mode_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
            If DirectCast(sender, RadioButton).Checked Then
                SetMode()
            End If
        End Sub

        Private Sub SetMode()
            If wmRadio.Checked Then
                InitializeMode(XDTransportMode.WindowsMessaging)
            ElseIf ioStreamRadio.Checked Then
                InitializeMode(XDTransportMode.IOStream)
            Else
                InitializeMode(XDTransportMode.MailSlot)
            End If
        End Sub

        ''' <summary>
        ''' If the MailSlot checkbox is checked, display info about single-instance limitation.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        Private Sub mailRadio_MouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)
            If mailRadio.Checked Then
                UpdateDisplayText("MailSlot mode only allows one listener on a single channel at any one time." & vbCr & vbLf, Color.Red)
            End If
        End Sub

        Private Sub propagateCheck_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
            If propagateCheck.Checked Then
                UpdateDisplayText("Messages will be propagated to all machines on the same domain or workgroup." & vbCr & vbLf, Color.Red)
            Else
                UpdateDisplayText("Message are restricted to the current machine." & vbCr & vbLf, Color.Red)
            End If
            SetMode()
        End Sub
    End Class
End Namespace




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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United Kingdom United Kingdom
Mike Carlisle - Technical Architect with over 20 years experience in a wide range of technologies.

@TheCodeKing

Comments and Discussions