VB6 Legacy and COM Interop
Patterns for maintaining VB6 code and strategies for migrating to VB.NET with COM interop.
VB6 to VB.NET Migration
Key Differences
' VB6 - Variant types Dim data As Variant data = 123 data = "Hello"
' VB.NET - Strong typing with Option Strict On Option Strict On Dim data As Object ' Still avoid when possible Dim number As Integer = 123 Dim text As String = "Hello"
' VB6 - Default properties Text1.Text = "Hello" Text1 = "Hello" ' Uses default Text property
' VB.NET - Explicit properties required TextBox1.Text = "Hello" ' Must be explicit
' VB6 - ByRef default Sub ProcessData(data As String) ' ByRef by default
' VB.NET - ByVal default Sub ProcessData(data As String) ' ByVal by default Sub ProcessData(ByRef data As String) ' Explicit ByRef
' VB6 - On Error On Error Resume Next On Error GoTo ErrorHandler
' VB.NET - Try-Catch Try ' Code Catch ex As Exception ' Handle error End Try
Common Migration Issues
' VB6 - Fixed-length strings Dim name As String * 50
' VB.NET - Use regular string and PadRight Dim name As String = "John".PadRight(50)
' VB6 - Currency type Dim amount As Currency
' VB.NET - Use Decimal Dim amount As Decimal
' VB6 - Control arrays Dim TextBox(5) As TextBox
' VB.NET - Use collection Dim textBoxes As New List(Of TextBox)()
' VB6 - Let/Set keywords Let x = 5 Set obj = New MyClass
' VB.NET - Assignment without keywords Dim x As Integer = 5 Dim obj As New MyClass()
COM Interop from VB.NET
Early Binding (Type Library Reference)
' Add COM reference in project ' Tools -> Add Reference -> COM -> Excel Object Library
Imports Excel = Microsoft.Office.Interop.Excel
Public Sub ExportToExcel(data As DataTable) Dim excelApp As Excel.Application = Nothing Dim workbook As Excel.Workbook = Nothing Dim worksheet As Excel.Worksheet = Nothing
Try
excelApp = New Excel.Application()
workbook = excelApp.Workbooks.Add()
worksheet = CType(workbook.Worksheets(1), Excel.Worksheet)
' Write headers
For col = 0 To data.Columns.Count - 1
worksheet.Cells(1, col + 1) = data.Columns(col).ColumnName
Next
' Write data
For row = 0 To data.Rows.Count - 1
For col = 0 To data.Columns.Count - 1
worksheet.Cells(row + 2, col + 1) = data.Rows(row)(col)
Next
Next
excelApp.Visible = True
Catch ex As Exception
MessageBox.Show($"Excel export failed: {ex.Message}")
Finally
' Release COM objects
If worksheet IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet)
End If
If workbook IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook)
End If
If excelApp IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp)
End If
End Try
End Sub
Late Binding (No Type Library)
Imports System.Reflection
Public Sub CreateExcelLateBound() Dim excelType As Type = Type.GetTypeFromProgID("Excel.Application") If excelType Is Nothing Then MessageBox.Show("Excel not installed") Return End If
Dim excelApp As Object = Nothing
Try
' Create COM object
excelApp = Activator.CreateInstance(excelType)
' Call methods via reflection
excelType.InvokeMember("Visible",
BindingFlags.SetProperty,
Nothing,
excelApp,
New Object() {True})
Dim workbooks As Object = excelType.InvokeMember("Workbooks",
BindingFlags.GetProperty,
Nothing,
excelApp,
Nothing)
' Add workbook
workbooks.GetType().InvokeMember("Add",
BindingFlags.InvokeMethod,
Nothing,
workbooks,
Nothing)
Finally
If excelApp IsNot Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp)
End If
End Try
End Sub
COM Object Release Pattern
' ✅ Good: Proper COM object cleanup Public Sub UseComObject() Dim excelApp As Excel.Application = Nothing Dim workbook As Excel.Workbook = Nothing
Try
excelApp = New Excel.Application()
workbook = excelApp.Workbooks.Add()
' Use objects
Finally
' Release in reverse order of creation
If workbook IsNot Nothing Then
workbook.Close(False)
Marshal.ReleaseComObject(workbook)
workbook = Nothing
End If
If excelApp IsNot Nothing Then
excelApp.Quit()
Marshal.ReleaseComObject(excelApp)
excelApp = Nothing
End If
GC.Collect()
GC.WaitForPendingFinalizers()
End Try
End Sub
' ❌ Bad: Not releasing COM objects (memory leak) Dim excelApp = New Excel.Application() excelApp.Workbooks.Add() ' No cleanup - Excel process remains in memory!
Creating COM-Visible .NET Components
COM-Visible Class
Imports System.Runtime.InteropServices
<ComVisible(True)> <Guid("12345678-1234-1234-1234-123456789012")> <ClassInterface(ClassInterfaceType.None)> <ProgId("MyCompany.Calculator")> Public Class Calculator Implements ICalculator
Public Function Add(a As Integer, b As Integer) As Integer Implements ICalculator.Add
Return a + b
End Function
Public Function Subtract(a As Integer, b As Integer) As Integer Implements ICalculator.Subtract
Return a - b
End Function
End Class
' Interface for COM <ComVisible(True)> <Guid("87654321-4321-4321-4321-210987654321")> <InterfaceType(ComInterfaceType.InterfaceIsDual)> Public Interface ICalculator Function Add(a As Integer, b As Integer) As Integer Function Subtract(a As Integer, b As Integer) As Integer End Interface
Register for COM
Register assembly for COM
regasm MyAssembly.dll /tlb /codebase
Unregister
regasm MyAssembly.dll /u
Generate type library
tlbexp MyAssembly.dll
Legacy VB6 Patterns to Modernize
Error Handling
' VB6 style (avoid in new code) Public Function GetCustomer(id As Integer) As Customer On Error GoTo ErrorHandler
' Code here
Exit Function
ErrorHandler: MsgBox "Error: " & Err.Description Resume Next End Function
' VB.NET modern style Public Function GetCustomer(id As Integer) As Customer Try ' Code here Catch ex As ArgumentException MessageBox.Show($"Invalid argument: {ex.Message}") Return Nothing Catch ex As Exception MessageBox.Show($"Error: {ex.Message}") Throw End Try End Function
File I/O
' VB6 style (avoid) Dim fileNum As Integer = FreeFile() FileOpen(fileNum, "data.txt", OpenMode.Output) PrintLine(fileNum, "Hello World") FileClose(fileNum)
' VB.NET modern style Using writer = New StreamWriter("data.txt") writer.WriteLine("Hello World") End Using
' Or async Await File.WriteAllTextAsync("data.txt", "Hello World")
Collections
' VB6 Collection (avoid in new code) Dim customers As New Collection() customers.Add(customer, "key1") Dim item = customers("key1")
' VB.NET generic collections Dim customers = New Dictionary(Of String, Customer)() customers.Add("key1", customer) Dim item = customers("key1")
' Or List(Of T) Dim customerList = New List(Of Customer)() customerList.Add(customer)
Migration Strategy
Incremental Migration
' 1. Start with COM interop wrapper ' Wrap VB6 COM component in VB.NET
Public Class VB6Wrapper Private vb6Component As Object
Public Sub New()
vb6Component = CreateObject("VB6Project.Component")
End Sub
Public Function ProcessData(data As String) As String
Return vb6Component.ProcessData(data).ToString()
End Function
End Class
' 2. Gradually replace with native VB.NET Public Class ModernComponent Public Function ProcessData(data As String) As String ' New VB.NET implementation Return data.ToUpper() End Function End Class
Best Practices
✅ DO
' Use modern VB.NET features in new code Option Strict On Option Explicit On
' Release COM objects explicitly Marshal.ReleaseComObject(comObject) GC.Collect()
' Use Try-Catch instead of On Error Try ' Code Catch ex As Exception ' Handle End Try
' Use generics instead of Collections Dim items = New List(Of Customer)()
' Use async for I/O Await File.WriteAllTextAsync("file.txt", content)
❌ DON'T
' Don't use VB6 compatibility module Imports Microsoft.VisualBasic.Compatibility.VB6 ' Legacy only!
' Don't use Option Strict Off Option Strict Off ' Avoid!
' Don't use On Error in new code On Error Resume Next ' VB6 style
' Don't forget to release COM objects Dim excelApp = New Excel.Application() ' ... (no cleanup - memory leak!)
' Don't use late binding when early binding available Dim obj = CreateObject("Excel.Application") ' Use typed reference instead
Related Skills
-
vb-core: Modern VB.NET patterns
-
vb-winforms: Windows Forms migration
-
vb-database: Database migration strategies