I used your old ways to force a single instance of VB 3,4, 5 and 6 ... how do you do it in VB.Net?
If there is some single-line Framework method that gets around the age-old silliness, we haven't come across it. But it's not all that hard.
We just ported our old Delphi Mutex logic over and it seemed to do the trick quite nicely. It's done with System.Threading working the Mutex (a Mutex could be thought of as a systemwide flag that goes away when it's creator process ends - they're quite handy little suckers), Process objects to iterate through what's running on the machine, and traditional Win32 API calls for the form visibility manipulation.
Add this module to your WinForms project and make the Sub Main the entry point of the program (in VS project properties). The thing to change is the name of the primary form in your app.
You see that this will not only restrict your app to a single instance, but bring a running instance back to the top of the ZOrder and even bring it back from the minimized state.
Module main
Private Const MB_TITLE As String = "Smithvoice.com Demo"
Public Const SW_RESTORE = 9
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2
Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1
Declare Function ShowWindowAsync Lib "user32" (ByVal hwnd As Integer, _
ByVal nCmdShow As Integer) As Integer
Declare Function SetWindowPos Lib "user32" _
(ByVal hwnd As Integer, ByVal hWndInsertAfter As Integer, _
ByVal x As Integer, ByVal y As Integer, _
ByVal cx As Integer, ByVal cy As Integer, _
ByVal wFlags As Integer) As Integer
Private m_Mutex As System.Threading.Mutex
Private m_UniqueIdentifier As String = _
Process.GetCurrentProcess.MainModule.FileName.Replace("\", "_")
Sub main()
m_Mutex = New System.Threading.Mutex(False, m_UniqueIdentifier)
Dim bFound As Boolean = False
If m_Mutex.WaitOne(1, True) Then
'first instance
Dim f As New frmMain
'start the app by showing the primary form
f.ShowDialog()
Else
'not first instance
Try
Dim Procs() As Process = Process.GetProcesses()
Dim proc As Process
For Each proc In Procs
If proc.MainModule.FileName.Replace("\", "_") = m_UniqueIdentifier _
And proc.Id <> Process.GetCurrentProcess.Id Then
'MsgBox("another")
bFound = True
Exit For
End If
Next proc
If bFound Then
'start this one
Dim temphwnd, x As Integer
temphwnd = proc.MainWindowHandle.ToInt32
x = ShowWindowAsync(temphwnd, SW_RESTORE)
'bring it to the top of the z-order
SetWindowPos(temphwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
'and release it
SetWindowPos(temphwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
End If
'exceptions from Process.GetProcesses are possbile
'on certain hardware running Win2kPro and using Hyperthreading
'MS is aware of this and while they are not fixing .Net1x
'they say that the fix will be in .Net2
Catch ex As ArgumentOutOfRangeException
MsgBox("This program is already running." & vbCrLf & _
"To maximize performance of your computer only one instance of" & vbCrLf & _
"this program can run at a time.", MsgBoxStyle.Information, MB_TITLE)
Catch ex As InvalidOperationException
MsgBox("This program is already running." & vbCrLf & _
"To maximize performance of your computer only one instance of" & vbCrLf & _
"this program can run at a time.", MsgBoxStyle.Information, MB_TITLE)
End Try
End If
End Sub
End Module
Hope it helps!
Robert Smith
Kirkland, WA
added to smithvoice October 2004