Standard EXE applications written in VB6 can be started either from a Main sub or a startup form.
Selection of the startup object for an Standard EXE project in VB6.
The use of the Main sub is a very common practice in large applications, because it allows the execution of initialization logic before the load of the main form of the application, and allows a separation of this logic from the logic of the form.
When an application that uses the Main sub as startup object is migrated using the VBUC, equivalent code is generated in .NET, however, due to differences in the behavior of VB6 and the .NET Framework the applications behave different. Some manual changes are required to achieve functional equivalence in this case.
In VB6, all the code in the Main sub is executed and the method ends, but the application continues to run while a form is displayed. In .NET on the other hand, the application will exit as soon as the Main method exits, any open form at that point will be closed automatically.
The following sections describe sample scenarios where this behavior affects the generated code and what kind of manual changes are required to achieve functional equivalence.
The basic scenario is the invocation of the main form of the application from the Main sub, this is described here.
We have a simple application with a Main module which contains the Main sub, and a main form that is displayed in the Main sub.
VB6 Project for the basic startup object scenario.
This is the code for the Main module:
Public Sub Main() MainForm.Show End Sub
VB6 code for the Main module.
As mentioned before, this application will start the execution on the Main sub, display the main form and exit the main sub, keeping the Main form open. The application will exit as soon as the Main form is closed.
The migration tool generates lines that are equivalent to the lines in the original application, it also generates an EWI informing the user that the "application will terminate when Sub Main() finishes".
//UPGRADE_WARNING: (1047) Application will terminate when Sub Main() finishes. More Information: https://www.mobilize.net/vbtonet/ewis/ewi1047.aspx [STAThread] public static void Main() { MainForm.DefInstance.Show(); }
If we execute this code, the Main Form window will be displayed but the application will exit as soon as the Main method exits, closing the window inmediately. To fix this behavior, we have two options:
For this application, as it is a simple one, we will use the first option, the other option will be seen in a later example.
The use of the System.Windows.Forms.Form.ShowDialog() method is straightforward. In the case of our sample application we just need to replace the call to Show() for a call to ShowDialog and we are good to go.
[STAThread] public static void Main() { MainForm.DefInstance.ShowDialog(); }
This simple change makes the form visible and stops the execution of any code after the ShowDialog call until the form is closed, achieving this way functional equivalence for the migrated application.
The main disadvantage of using ShowDialog() is that this method stops the execution of the caller method until the form is closed, this means that if the source application has logic that is executed after the form is displayed, tat logic will be executed only when the form is closed.
Another limitation is that if for some reason the application consists of more than one form, if all forms are displayed using the ShowDialog() then they will be displayed sequentially (the second after the first one is closed and so on).
The following example shows a (slightly) more complex application and a more general solution for the problem of the application exiting inmediately after it is loaded.
Here’s a frequent way of starting applications in VB6, which will not work with the previous solution of using the ShowDialog() method.
Public Sub Main() SplashForm.Show InitializeDatabaseAccess End Sub
VB6 code for the Main module.
Private Sub Timer1_Timer() Unload Me MainForm.Show End Sub
VB6 code for the SplashForm.
The application has a Splash Form that is displayed when the application starts, this form has a timer that after a couple of seconds closes the Splash Form and opens the main form of the application. The application also calls a method called InitializeDatabaseAccess() after displaying the Splash Form, assuming that the initialization method has been executed when the Main Form is displayed.
If we use the previous solution, two problems will arise:
In this particular case, a solution might be to move the call to InitializeDatabaseAccess before displaying the Splash Form and moving the call to the ShowDialog of the Main Form after the same call for the Splash Form. e.g.:
[STAThread] public static void Main() { InitializeDatabaseAccess(); SplashForm.DefInstance.ShowDialog(); MainForm.DefInstance.ShowDialog(); }
Possible solution to achieve functional equivalence.
Although this approach works fine, it requires several manual changes to the code (even for a small application) and it also has the issue that the initialization code will be executed before showing the splash screen, which means that the application might take longer to start.
The following solution requires the addition of two lines to the application’s Main method that will provide functional equivalence to any application in a simple way.
[STAThread] public static void Main() { SplashForm.DefInstance.Show(); InitializeDatabaseAccess(); MainForm.DefInstance.FormClosed += (s, e) => { System.Windows.Forms.Application.Exit(); }; System.Windows.Forms.Application.Run(); }
General solution to solve the problem.
The idea of this solution is, that with the call to System.Windows.Forms.Application.Run() we make the application wait until the System.Windows.Forms.Application.Exit() method is called, then, the previous line assigns an event handler to the FormClosed event of the Main Form of the application, and this event handler simply calls the Application.Exit() which will end the execution of the application.
Note that this solution will work as long as the assumption that once the Main Form is closed the application should terminate. If there are other active forms when this main form is closed this solution will cause the application to exit regardless of these forms. The solution in such case would be to keep track of the open forms of the application and when the last one is closed, call the Application.Exit method
8834 N Capital of Texas Hwy, Ste 302
Austin, TX 78759
Call us: +1 (425) 609-8458
info@wearegap.com