Introduction
First of all, I have to say, I have debated about writing this article for a long time. There are already several articles out there that pretty much do the same thing. So why did I do it? Well, it seems that other solutions can find an existing instance of the app, but I haven’t seen too many examples that will bring up the existing instance if it is minimized or hidden.
Background
A few years back, when I was doing more Delphi programming than .NET, I had a nice little unit that helped me ensure I only had one instance of an application running on a user’s local machine. So I decided to try and do something similar in .NET. The only thing that is interesting with my solution is that it will bring up the form if it is minimized or hidden (like in a tray icon).
The Solution
First, I will tell you that I don’t know of any pure .NET solution for this. You have to do API calls to use Windows messaging. I used a Mutex to see if the app is already running. Then, I used Windows messaging to tell the app that is already running to show itself and go to the normal window state if it is minimized.
The Code
If you have never seen how to import a DLL and thus do a Windows API call, here is what the code looks like so we can send a Windows message:
[DllImport("USER32.DLL", EntryPoint="BroadcastSystemMessageA",
SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern int BroadcastSystemMessage(Int32 dwFlags, ref Int32
pdwRecipients, int uiMessage, int wParam, int lParam);
<DLLIMPORT("USER32.DLL", EntryPoint:="BroadcastSystemMessageA", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall> _
Public Shared Function BroadcastSystemMessage(ByVal dwFlags As Int32, _
ByRef pdwRecipients As Int32, ByVal uiMessage As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
Next, we have the method that is called in the OnLoad
event of the form.
private void CheckPrevious()
{
m_uniqueIdentifier = Application.ExecutablePath.Replace(@"\", "_");
m_Mutex = new System.Threading.Mutex(false, m_uniqueIdentifier);
MessageId = RegisterWindowMessage(m_uniqueIdentifier);
if (m_Mutex.WaitOne(1, true))
{
}
else
{
Int32 BSMRecipients = BSM_APPLICATIONS;
Int32 tmpuint32 = 0;
tmpuint32 = tmpuint32 | BSF_IGNORECURRENTTASK;
tmpuint32 = tmpuint32 | BSF_POSTMESSAGE;
int ret = BroadcastSystemMessage(tmpuint32, ref BSMRecipients,
MessageId, 0, 0);
Application.Exit();
}
}
Private Sub checkprevious()
m_uniqueIdentifier = Application.ExecutablePath.Replace("\", "_")
m_Mutex = New System.Threading.Mutex(False, m_uniqueIdentifier)
MessageId = RegisterWindowMessage(m_uniqueIdentifier)
If m_Mutex.WaitOne(1, True) Then
Else
Dim BSMRecipients As Int32 = BSM_APPLICATIONS
Dim tmpuint32 As Int32 = 0
tmpuint32 = tmpuint32 Or BSF_IGNORECURRENTTASK
tmpuint32 = tmpuint32 Or BSF_POSTMESSAGE
Dim ret As Integer
ret = BroadcastSystemMessage(tmpuint32, BSMRecipients, MessageId, 0, 0)
Application.Exit()
End If
End Sub
Finally, we have the method that checks the Windows messages for the form. Note: you must be very careful when you override this method. All Windows messages to this app go through this method.
protected override void DefWndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == MessageId)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.Show();
this.WindowState = FormWindowState.Normal;
}
this.Activate();
this.Focus();
}
else
{
base.DefWndProc(ref m);
}
}
Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = MessageId Then
If (Me.WindowState = FormWindowState.Minimized) Then
Me.Show()
Me.WindowState = FormWindowState.Normal
End If
Me.Activate()
Me.Focus()
Else
MyBase.DefWndProc(m)
End If
End Sub
Conclusion
So it is a pretty straightforward solution. I hope someone finds this helpful. I saw some postings on The Code Project where people were asking about a solution for this problem, so I decided to write this article after all.