For my fellow C# developers, I understand the dilemma. I came to this page in search of an answer, and I found most of it here.
Using the information in this page as a starting point, I discovered that you can accomplish everything you want, using code that is almost identical to the code you would write in C#,
without touching the application property sheet! and the only change needed on the application property sheet is to disable the Application Framework.
I have an existing application,
EZPayWebPmtsNotifier
, whose only form is called
frmMain
. Like many that came before it, the initial requirements were pretty simple: display a window when a specific file exists in a designated folder. Otherwise, keep the window hidden. A timer loop checks every second or so to see whether conditions have changed (File is now present/absent.), and adjust the display accordingly.
Requirements have since evolved, and the program now keeps a log of its activities. This led to the need for a mechanism to allow a script to shut it down, e. g., for maintenance.
Into the application I go, and add the following short function to the file that contains the hand coded portion of the source code of
frmMain
,
Form1.vb
.
Public Shared Function Main(ByVal cmdArgs As String()) As Integer
Application.Run(New frmMain())
Return (ERROR_SUCCESS)
End Function
That's it.
You can use any of the four ways to declare your Main routine that are discussed in "Main Procedure in Visual Basic," at
http://msdn.microsoft.com/en-us/library/ms235406%28v=VS.100%29.aspx[
^]; I chose the most complete form, because I need the argument list, and I want the option of returning a nonzero exit code.
I've omitted the code to parse the command line, which isn't written yet. My first objective was to prove the concept, by incorporating my own start-up routine.
The key points are these.
1) The function or subroutine must be called Main.
2) The function or subroutine must be marked Public and Shared.
3) The function or subroutine must be defined in the class module that defines your startup form.
4) If Main is a function, it must return Integer.
5) If Main takes arguments, it must take only one, which must be an array of strings, passed
ByVal
.
Caveats
When you disable the Application Framework, you lose the ability to mark the application as a single instance. Nevertheless, you don't really lose the ability to have a single instance; you just have to work for it.
The following routine does two things.
1) Enforce single instance.
2) Implement shutdown by command, so that a script can shut it down.
Following is the whole routine that I am about to put into production, having proven to myself, by enumerating processes, that single instance is enforced.
Public Shared Function Main(ByVal cmdArgs As String()) As Integer
Const CMD_SHUTDOWN As String = "shutdown"
Dim intMyProcessID As Integer
Dim strMyProcessName As String
Dim myProcess As Process = Process.GetCurrentProcess
With myProcess
intMyProcessID = .Id
strMyProcessName = .ProcessName
End With
myProcess.Dispose()
myProcess = Nothing
If cmdArgs.Length > ZERO Then
If cmdArgs(ARRAY_FIRST_ELEMENT).ToLower() = CMD_SHUTDOWN Then
If Application.OpenForms.Count > ZERO Then
For Each frm As Form In Application.OpenForms
frm.Close()
Next
End If
For Each activeProcess As Process In Process.GetProcessesByName(strMyProcessName)
If activeProcess.Id <> intMyProcessID Then
activeProcess.CloseMainWindow()
End If
activeProcess.Dispose()
Next
Application.Exit()
Return (ERROR_SUCCESS)
End If
End If
If Process.GetProcessesByName(strMyProcessName).Length = PLUS_ONE Then
Application.Run(New frmMain())
End If
Return (ERROR_SUCCESS)
End Function