Click here to Skip to main content
Click here to Skip to main content

Single instance applications

, 4 Feb 2006
Rate this:
Please Sign up or sign in to vote.
Implementing single instance applications with command line recieving in VB.NET

Introduction

Visual Studio 2005 brings new way of creating single instance applications via help of Application Framework. But to be able to use Application Framework, application must start with form. That's right - no support for tray-ed applications at this point.

To overcome this limitation one must implement its own multiple instance management. Most traditional usage is to use mutex for detecting second instance. Problem is that first instance does not know when second instance fires. To overcome this behavior we must implement some kind of communication mechanism between instances. This will allow us to use custom action when second instance fires - like opening our main application window.

Mutex & Named Pipe

Usual mechanism for determining existence of another instance is mutex object. And while mutex can help us to end second instance, for data transfer we must use some other methods. For this example we will use named pipes since they are present on every system we may use as platform for .NET programs. There is also one more advantage over remoting - no problems with firewall warnings. Sometime it takes too much effort explaining to customer why all firewall warnings are not bad.

Shared Sub New()<BR>    Dim refIsCreated As Boolean<BR>    _mtxFirstInstance = New Threading.Mutex(True, Name, refIsCreated)<BR>    IsAlreadyStarted = Not refIsCreated<BR>    If IsAlreadyStarted = False Then<BR>        _thrThread.Start()<BR>    Else<BR>        Dim ms As New IO.MemoryStream()<BR>        Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter<BR>        bf.Serialize(ms, New NewInstanceEventArgs(System.Environment.GetCommandLineArgs()))<BR>        ms.Flush()<BR>        Dim np As New NamedPipe(Name)<BR>        np.OpenExisting()<BR>        np.Write(ms.GetBuffer())<BR>        np.Close()<BR>        ms.Close()<BR>    End If<BR>End Sub<BR>

Since there is no built in support for named pipes, on of classes in highlander assembly does just that. Implementation of named pipe is story which we will not tell now, suffice to say that some Win32 API calls were needed. For what is worth, its name (and also name of mutex) we have chosen full path to application.

Private Shared ReadOnly Property Name() As String<BR>    Get<BR>        Return System.Reflection.Assembly.GetEntryAssembly.FullName.Replace("\", "/")<BR>    End Get<BR>End Property<BR>

First application instance creates new thread which is dormant for most of time so there is no performance hit (named pipe connect method is blocking one). Second instance tries to create mutex, sees that mutex is already alive and thus exits itself. Before exit it takes its command line arguments and serializes them to named pipe channel thus breaking connect block on first application instance. First instance reads data, deserializes it and fires NewInstanceDetected event after which named pipe connect is called again thus blocking that thread until another instance is fired.

Private Shared Sub Run()<BR>    Dim np As New NamedPipe(Name)<BR>    np.Create()<BR>    Do<BR>        np.Connect()<BR>        Dim b As Byte() = np.Read()<BR>        np.Disconnect()<BR>        Dim ms As New IO.MemoryStream(b)<BR>        Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter<BR>        Dim e As NewInstanceEventArgs = DirectCast(bf.Deserialize(ms), NewInstanceEventArgs)<BR>        ms.Close()<BR>        RaiseEvent NewInstanceDetected(Nothing, e)<BR>    Loop<BR>End Sub<BR>

Tray

In this example I have chosen tray application since there is no built in support for multiple instance handling in VB.NET 2005 for application that have something else than form as their entry point. Most useful behavior is to show main window and parse through command line arguments given. Here parsing is substituted for showing all received arguments in TextBox.

    AddHandler Highlander.Highlander.NewInstanceDetected, AddressOf NewInstanceDetected<BR>    If Highlander.Highlander.IsAlreadyStarted = True Then End

Notice special handling for main form which includes its early creation. This is needed to facilitate invoke when new instance fires and code in shared sub New ensures that underlying window handle is really created.

    frmMain = New frmMain<BR>    frmMain.CreateControl()<BR>    frmMain.Handle.GetType()<BR>

Back in main class I have placed event handling and delegate for transferring that data in form. Delegate is very important since all data comes from different thread into application one (remember thread creation in Highlander class!). After we get call in our method based on delegate, we can access form safely. In this example here is where we placed filling of TextBox with command line from other instance.

Private Shared Sub NewInstanceDetected(ByVal sender As Object, ByVal e As Highlander.NewInstanceEventArgs)<BR>    Dim method As New NewInstanceDetectedProcDelegate(AddressOf NewInstanceDetectedProc)<BR>    Tray.Form.Invoke(method, New Object() {e.CommandLineArgs})<BR>End Sub<BR><BR> 
Private Delegate Sub NewInstanceDetectedProcDelegate(ByVal args As String())<BR>
Private Shared Sub NewInstanceDetectedProc(ByVal args As String())<BR>    Tray.Form.txtParameters.Lines = args<BR>    Tray.Form.Show()<BR>    Tray.Form.Activate()<BR>End Sub<BR>

Conclusion

For better understanding of this process, look at given sources. Although this may seem too complicated to get into, once Highlander assembly is deployed, one must only include proper calls and event handling.

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

Share

About the Author

Josip Medved
Software Developer (Senior) Siemens
Croatia Croatia
.NET programmer with MCSD and MCPD status. Loves chevapi...
Medo's Home Page

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.141015.1 | Last Updated 4 Feb 2006
Article Copyright 2006 by Josip Medved
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid