Skip to content
AgileLogics
7 min read

From VB6 to VB.NET

Prerequisites: Exception handling

Visual Basic 6 (1998) was hugely popular, and many companies still run VB6 applications. Its successor, VB.NET (2002), looks similar but is a different language on a different platform — VB6 code doesn't compile unchanged, and Microsoft's old automatic upgrade wizard was removed after Visual Studio 2008. If you maintain or migrate VB6 code, you need to know the differences.

Key differences

VB6 VB.NET
Integer 16-bit, Long 32-bit Integer 32-bit, Long 64-bit
Variant Object (and Option Strict On to avoid it)
parameters ByRef by default ByVal by default
arrays could start at any bound (Option Base 1) arrays always start at 0
Set obj = New Thing obj = New Thing()
On Error GoTo Try / Catch / Finally
default properties (Text1 = "hi") explicit (Text1.Text = "hi")
Type ... End Type Structure ... End Structure
Collection object List(Of T), Dictionary(Of K, V)
COM, ActiveX controls .NET assemblies (COM still possible via interop)
Form1.Show (default form instance) Dim f As New Form1() : f.Show() (default instances still exist, via My.Forms)
Gosub, Wend, Let removed

Converting error handling

VB6 style (still compiles in VB.NET, but avoid it):

Module Program
    Function ReadConfigOld(text As String) As Integer
        On Error GoTo Failed
        ReadConfigOld = CInt(text)
        Exit Function
Failed:
        ReadConfigOld = -1
    End Function

    Function ReadConfig(text As String) As Integer
        Try
            Return CInt(text)
        Catch ex As InvalidCastException
            Return -1
        End Try
    End Function

    Sub Main()
        Console.WriteLine($"{ReadConfigOld("42")} {ReadConfigOld("oops")}")
        Console.WriteLine($"{ReadConfig("42")} {ReadConfig("oops")}")
    End Sub
End Module
42 -1
42 -1

Even better here: Integer.TryParse, which avoids the exception entirely.

Converting a VB6-style module

A typical VB6 program keeps data in global arrays and passes counters around. Here's the modern equivalent of "store names in an array and sort them":

Module Program
    ' VB6 style: a fixed-size array, a manual counter, a bubble sort
    Private oldNames(9) As String
    Private oldCount As Integer

    Sub AddOld(name As String)
        oldNames(oldCount) = name
        oldCount += 1
    End Sub

    Sub Main()
        AddOld("Grace") : AddOld("Ada") : AddOld("Linus")
        For i = 0 To oldCount - 2
            For j = 0 To oldCount - 2 - i
                If oldNames(j) > oldNames(j + 1) Then
                    Dim tmp = oldNames(j)
                    oldNames(j) = oldNames(j + 1)
                    oldNames(j + 1) = tmp
                End If
            Next
        Next
        Console.WriteLine(String.Join(", ", oldNames.Take(oldCount)))

        ' Modern VB.NET: a List and LINQ
        Dim names As New List(Of String) From {"Grace", "Ada", "Linus"}
        Console.WriteLine(String.Join(", ", names.OrderBy(Function(n) n)))
    End Sub
End Module
Ada, Grace, Linus
Ada, Grace, Linus

A migration strategy

  1. Get it building and under test. Before changing anything, write tests (or at least record inputs and outputs) that capture today's behavior.
  2. Move logic out of forms into classes, one feature at a time.
  3. Rewrite rather than translate the UI — a new Windows Forms or WPF front end over the extracted logic.
  4. Turn on Option Strict On file by file and fix each warning.
  5. Replace On Error, Variant, and global state as you touch code.
  6. Keep COM components working through COM interop until they can be replaced.

Commercial tools and consultancies offer VB6-to-.NET conversion, and some teams move to C# at the same time. Whatever the route, the tests from step 1 are what make it safe.

Where does classic BASIC fit?

VB6 grew out of QuickBASIC and earlier BASIC dialects — line numbers, GOTO, and PRINT. The BASIC course covers that classic style, which still appears in teaching and retro computing.