Starting with version 1.10, VB Migration Partner can replace old-styled On Error Goto statements into structured exception handling (SEH) based on the Try-Catch block. You can activate this feature by means of the UseTryCatch pragma, which can have project-, file-, and method-level scope. For example, the following VB6 code:
'## UseTryCatch
Sub Test()
On Error Goto ErrorHandler
' method body
ErrorHandler:
' error handler
End Sub
is translated to the following VB.NET code:
Sub Test()
Try
' IGNORED: On Error Goto ErrorHandler
' method body
Catch _ex As Exception
' IGNORED: ErrorHandler:
' error handler
End Try
End Sub
In case you are wondering why you need a pragma to tell VB Migration Partner to perform this transformation, please consider that this refactoring feature can't be performed in a number of occasions. More precisely, VB Migration Partner can insert a Try-Catch block only if ALL the following conditions are met:
- The method contains only a single On Error GoTo <label> method.
- The On Error GoTo <label> statement doesn’t appear inside a conditional block such as If, For, Select Case, and isn’t preceded by a GoTo statement.
- The method doesn’t contain GoSub, Resume, or Resume Next statements. (Resume <label> statements are acceptable, though)
- There is no Goto statement in the method body that points to a label that is defined in the error handler. (Notice that it is ok if a GoTo in the error handler points to a label defined in the method body.)
- If the method contains one or more On Error Goto 0 statements, such statements must immediately precede a statement that causes exiting from the current method, e.g. Exit Sub or End Function.
- If the current method is a Property Let procedure, there must not be a Property Set procedure for the same property. Likewise, If the current method is a Property Set procedure, there must not be a Property Let procedure for the same property.
For example, the following VB6 code:
'## UseTryCatch
Sub Test()
On Error Goto ErrorHandler
' method body
If x > 0 Then GoTo ErrorHandler2
ErrorHandler:
' error handler
ErrorHandler2:
' do something here
End Sub
can't be converted to VB.NET using a Try-Catch block because a GoTo statement in the method body points to a label that is defined in the error handler.
By default, VB Migration Partner inserts a Try-Catch also if the method contains the On Error Resume Next statement plus another executable statement. For example, the following VB6 code:
Function Reciprocal(ByVal x As Double) As Double
'## UseTryCatch True
On Error Resume Next
Reciprocal = 1 / x
' returns zero if an error occurs (e.g. X is zero)
End Function
contains only two executable statements (including On Error Resume Next) and is converted to:
Function Reciprocal(ByVal x As Double) As Double
Try
Return 1 / x
' returns zero if an error occurs (e.g. X is zero)
Catch
' Do nothing if an error occurs
End Try
End Function
Methods with three or more executable statements can be converted using Try Catch if you specify a value higher than 2 in the second argument for the UseTryCatch pragma. For example, all methods with up to 5 executable statements under the scope of the following pragma:
'## UseTryCatch True, 5
are converted using a Try-Catch block.
Notice that the UseTryCatch pragma can be used together with the AutoDispose Force pragma, in which case VB Migration Partner generates a complete Try-Catch-Finally block. Combining the AutoDispose and UseTryCatch pragma can lead to complex Try-Catch-Finally blocks that can handle your errors and correctly dispose of your variables at the same time. For example, consider this VB6 method:
'## AutoDispose Yes
'## UseTryCatch
Sub Test()
On Error Goto ErrHandler
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
' opens the connection and the recordset
cn.Open MyConnString
rs.Open "SELECT * FROM Employees", cn
' …
Exit Sub
ErrHandler:
MsgBox "An error has occurred"
End Sub
This is how VB Migration Partner converts this code to VB.NET:
Public Sub Test()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Try
' IGNORED: On Error GoTo ErrHandler
' opens the connection and the recordset
cn.Open(myconnstring)
rs.Open("SELECT * FROM Employees", cn)
' …
Exit Sub
Catch _ex As Exception
' IGNORED: ErrHandler:
MsgBox6("An error has occurred")
Finally
' Clean up all disposable variables
SetNothing6(cn)
SetNothing6(rs)
End Try
End Sub
The SetNothing6 method is defined in VB Migration Partner support library. In addition to setting the variable to Nothing, this helper method invokes its Dispose method and - just as important - if the variable points to a COM object (as in this case), it removes the object from memory. (Many developers believe that you just need a call to Marshal.ReleaseComObject method to release a COM object, but it isn't always true because of a little-known bug: the SetNothing6 method takes all the necessary steps to ensure that the COM object is actually released).
Interestingly, VB Migration Partner has automatically recognized that the Recordset and Connection objects are disposable objects and require a call to SetNothing6.
In case you aren't familiar with .NET and the so-called undeterministic finalization issue, here is the short story: if you instantiate a disposable object - that is, an object that takes system resources such as a file, a database connection, a Windows API handle, etc - you MUST invoke its Dispose method before setting it to Nothing. If you fail to do so, you might introduce a noticeable overhead in your application (in the best case) or even a resource leakage that might crash your code in the long run (in the worst case).
As far as we know, VB Migration Partner is the only VB6 conversion tool that can automatically handle disposable objects in such a safe way.