VB Migration Partner

KNOWLEDGE BASE - Forms and controls


Previous | Index | Next 

[PRB] NullReference exception in Form_Initialize

If the Form_Initialize event handler contains one or more statements that access a form’s property or one of the controls on the form, the VB.NET code throws a NullReference exception.

The reason for this exception is trivial: in VB6 the Initialize event fires when no form resource has been created yet. Migrated VB.NET forms replicate this behavior by firing the Form_Initialize_VB6 method before any control variable has been assigned a reference to a non-Nothing object, hence the exception.

This exception is the symptom of bad programming practice in VB6. In fact, the code in a Form_Initialize event should never access a control on the form, because this action triggers the load of the form itself. You can prove this detail by running the following piece of VB6 code:

        Private Sub Form_Initialize()
            Debug.Print "Enter Initialize"
            Me.Label1.Caption = "Test"
            Debug.Print "Exit Initialize"
        End Sub
		
        Private Sub Form_Load()
            Debug.Print "Enter Load"
            ' …
            Debug.Print "Exit Load"
        End Sub

This is the output in the Debug window:

        Enter Initialize
        Enter Load
        Exit Load
        Exit Initialize

In other words, the Load event fires in the middle of the Initialize event, which isn’t probably what the VB6 developer expected. In some cases, this unintended behavior is the causes of subtle bugs, for example when the code in the second half of the Form_Initialize method relies on values and properties that have been set inside the Form_Load method.

There is no easy way to migrate VB6 code that relies on this undocumented behavior. Under VB.NET a reference to a control doesn’t automatically fire the Load event. However, you can use the HasBeenLoaded variable (defined in VB6Form base class) to detect whether the form has been already loaded or not, and rearrange the code as follows:

        Protected Overrides Sub Form_Initialize_VB6()
            ' exit if this method is invoked by the VBLibrary, or proceed
            ' if the event is manually invoked from inside Form_Load.
            If Not MyBase.HasBeenLoaded Then Exit Sub
			
            '  here goes the code in the original Form_Initialize method
            ' …
        End Sub

        Private Sub Form_Load()
            ' the code in the original Form_Load method
            ' …
            ' manually invoke the code in Form_Initialize at the end of this method
            Call Form_Initialize_VB6()
       End  Sub

In some, very rare circumstances, you have to ideally split the code in Form_Initialize in two portions, the statements that don’t access any form property or control and the remaining statements. In this case you need an If…Then…Else block in Form_Initialize to exactly replicate VB6 behavior:

        Protected Overrides Sub Form_Initialize_VB6()
            If Not MyBase.HasBeenLoaded Then Exit Sub
                ' the statements that don’t access any property or control
                ' e.g. counter = 0
                ' …
            Else
                ' the first statement that accesses a property or a control
                ' and all the statements that follow
                Me.Label1.Caption  = "XXX"
                ' …
            End If
        End Sub
  
        Private Sub Form_Load()
            ' the code in the original Form_Load method
            ' …
            ' manually invoke the code in Form_Initialize at the end of this method
            Call Form_Initialize_VB6()
        End Sub

Notice that the undocumented VB6 behavior affects also the UserControl_Initialize event: if the code in this event references a constituent control on the UserControl’s surface, then the VB6 runtime anticipates the allocation of Windows resources to be allocated to the UserControl.

UserControls are dealt with slightly differently than forms in converted VB.NET programs. In a converted UserControl, the UserControl_Initialize method fires after all constituent controls have been created,therefore no runtime exception occurs even if the code in the method references a constituent control.

If it is essential that the UserControl_Initialize event fires immediately after creating the UserControl (and before any other event), you can invoke the special FireInitializeEvent method (defined in the VB6UserControl base class) from inside the constructor of your UserControl class, which you can find in the code-behind portion of that class (i.e. the *.Designer.vb file):

        <System.Diagnostics.DebuggerNonUserCode()> Public Sub New()
            MyBase.New()
            ' Create all controls and control arrays.
            InitializeComponents()
            ' fire the Initialize event now
            FireInitializeEvent()
        End Sub
Previous | Index | Next 




Follow Francesco Balena on VB6 migration’s group on

LinkedIn





Read Microsoft Corp’s official case study of a VB6 conversion using VB Migration Partner.




Code Architects and its partners offers remote and onsite migration services.

More details




Subscribe to our free newsletter for useful VB6 migration tips and techniques.

newsletter



To learn more about your VB6 applications, run VB6 Analyzer on your source code and send us the generated text file. You will receive a detailed report about your VB6 applications and how VB Migration Partner can help you to quickly and effectively migrate it to .NET.

Get free advice



A fully-working, time-limited Trial Edition of VB Migration Partner allows you to test it against your actual code

Get the Trial




The price of VB Migration Partner depends on the size of the VB6 application, the type of license, and other factors

Request a quote




Migrating a VB6 application in 10 easy steps

Comparing VB Migration Partner with Upgrade Wizard

Migration tools: Feature Comparison Table

All whitepapers