This option will generate special attributes for the converted classes and their members in order to keep the resulting assemblies exposed through a COM interface.
This feature enables the resulting .NET components to be called from other non-managed components or applications via COM.
General Description:
The VBUC converts Visual Basic 6 ActiveX binaries to .NET assemblies. By default, the resulting assemblies can be used only from managed code. This option should be selected to generate the .NET attributes required to expose these assemblies as COM Objects if it’s necessary to use them from non-managed code.
In addition to the “COMVisible” attribute on the class members, the resulting project is also marked as COM Visible.
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub Form_Load() Set m_Customer1 =NewExeBillingObjects.Customer Set m_Customer2 =NewExeBillingObjects.CustomerEnd SubPrivate Sub cmdGet_Click() txtTheNumber.Text = m_Customer1.TheNumberEnd Sub
<ComVisible(True)> _<ProgId("ExeBillingObjects.Customer")> _<ClassInterface(ClassInterfaceType.AutoDual)> _PublicClass CustomerPublic Property TheNumber()AsInteger Get Return g_TheNumber End GetSet(ByVal Value AsInteger) g_TheNumber = Value End Set End PropertyEnd Class
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub cmdGet_Click(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles cmdGet.Click txtTheNumber.Text =CStr(m_Customer1.TheNumber)End SubPrivate Sub Form1_Load(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles MyBase.Load m_Customer1 =NewExeBillingObjects.Customer() m_Customer2 =NewExeBillingObjects.Customer()End Sub
1.2. Out process and Application
This optional feature enables the conversion of ActiveX DLLs and EXEs (with global variables in a .bas module) via a helper class (ComponentClassHelper) that controls the instantiation of the generated classes.
ActiveX EXEs are converted to out-of-process .NET EXEs.
ActiveX DLLs are converted to .NET class libraries using application domains.
Component instantiation is performed using helper classes. With this approach most of the ActiveX functionality is replicated in the converted code.
General Description:
The VBUC converts Visual Basic 6 ActiveX EXEs to .NET EXE projects (out-of-process) and ActiveX DLLs to .NET assemblies (class library projects).
One of the main differences between Visual Basic 6 ActiveX binaries and .NET assemblies is how the components are instantiated and how their initialization determines its lifetime behavior.
When this feature is active, a helper class is used to replicate the following ActiveX instantiation types:
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub Form_Load() Set m_Customer1 =NewExeBillingObjects.Customer Set m_Customer2 =NewExeBillingObjects.CustomerEnd SubPrivate Sub cmdGet_Click() txtTheNumber.Text = m_Customer1.TheNumberEnd Sub
Module Module1Public myVar AsString=""Public Sub InitGlobalVars() myVar ="" End SubEnd Module
Customer.vb
PublicClass Customer Inherits UpgradeHelpers.Activex.ComponentClassHelperPublic Property TheNumber()AsInteger Get Return g_TheNumber End GetSet(ByVal Value AsInteger) g_TheNumber = Value End Set End PropertyEnd Class
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub cmdGet_Click(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles cmdGet.Click txtTheNumber.Text =CStr(m_Customer1.TheNumber)End SubPrivate Sub Form1_Load(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles MyBase.Load m_Customer1 = ExeBillingObjects.ExeBillingObjectsFactory.Create(Of ExeBillingObjects.Customer)(m_Customer1) m_Customer2 = ExeBillingObjects.ExeBillingObjectsFactory.Create(Of ExeBillingObjects.Customer)(m_Customer2)End Sub
1.3. Standard .NET Assemblies
This optional feature converts the ActiveX DLLs and EXEs to .NET class libraries (DLLs).
All ActiveX binaries are converted to native .NET assemblies (class libraries).
With this approach, the converted code can be used only from managed code and the different ActiveX instantiation models (e.g MultiUse, GlobalMultiuse, etc) won’t be supported.
General Description:
The VBUC converts Visual Basic 6 ActiveX EXEs and ActiveX DLLs to .NET class libraries (DLLs).
One of the main differences between Visual Basic 6 ActiveX binaries and .NET assemblies is how the components are instantiated and how their initialization determines its lifetime behavior.
With this option switched on, the code is converted to pure .NET code and the ActiveX instantiation models won’t be supported.
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub Form_Load() Set m_Customer1 =NewExeBillingObjects.Customer Set m_Customer2 =NewExeBillingObjects.CustomerEnd SubPrivate Sub cmdGet_Click() txtTheNumber.Text = m_Customer1.TheNumberEnd Sub
PublicClass CustomerPublic Property TheNumber()AsInteger Get Return g_TheNumber End GetSet(ByVal Value AsInteger) g_TheNumber = Value End Set End PropertyEnd Class
Code located in the main application that uses the Activex EXE:
Private m_Customer1 As ExeBillingObjects.CustomerPrivate m_Customer2 As ExeBillingObjects.CustomerPrivate Sub cmdGet_Click(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles cmdGet.Click txtTheNumber.Text =CStr(m_Customer1.TheNumber)End SubPrivate Sub Form1_Load(ByVal eventSender AsObject, ByVal eventArgs As EventArgs) Handles MyBase.Load m_Customer1 =NewExeBillingObjects.Customer() m_Customer2 =NewExeBillingObjects.Customer()End Sub
2. Comment Out Dead Code
2.1. On
Private methods that are not referenced will be commented out.
Original VB6 code:
Public Sub PublicMethod() Call CalledPrivateMethodEnd SubPrivate Sub CalledPrivateMethod() MsgBox "This method is called."End SubPrivate Sub UncalledPrivateMethod() MsgBox "This method is not called."End Sub
C# code:
publicvoidPublicMethod(){ CalledPrivateMethod();}privatevoidCalledPrivateMethod(){MessageBox.Show("This method is called.",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));}//UPGRADE_NOTE: (7001) The following declaration (UncalledPrivateMethod) seems to be dead code//private void UncalledPrivateMethod()//{ //MessageBox.Show("This method is not called.", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));//}
VB.NET code:
Public Sub PublicMethod()CalledPrivateMethod()End SubPrivate Sub CalledPrivateMethod() MessageBox.Show("This method is called.", My.Application.Info.Title)End Sub'UPGRADE_NOTE: (7001) The following declaration (UncalledPrivateMethod) seems to be dead code''Private Sub UncalledPrivateMethod()''MessageBox.Show("This method is not called.", My.Application.Info.Title)''End Sub'
2.1. Off
This feature will be turned off and no changes pertaining to this feature will be made.
Original VB6 code:
Public Sub PublicMethod() Call CalledPrivateMethodEnd SubPrivate Sub CalledPrivateMethod() MsgBox "This method is called."End SubPrivate Sub UncalledPrivateMethod() MsgBox "This method is not called."End Sub
C# code:
publicvoidPublicMethod(){ CalledPrivateMethod();}privatevoidCalledPrivateMethod(){MessageBox.Show("This method is called.",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));}privatevoidUncalledPrivateMethod(){MessageBox.Show("This method is not called.",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));}
VB.NET code:
Public Sub PublicMethod()CalledPrivateMethod()End SubPrivate Sub CalledPrivateMethod() MessageBox.Show("This method is called.", My.Application.Info.Title)End SubPrivate Sub UncalledPrivateMethod() MessageBox.Show("This method is not called.", My.Application.Info.Title)End Sub
3. Default Property Resolution
3.1. Static code analysis and helpers classes
By switching this feature on, the majority of default property cases that could not be resolved with a static code analysis are managed at runtime by the use of a helper class.
Manages special cases of default properties at runtime by using a helper class.
Increases the automation ratio and reduces the manual effort required to achieve functional equivalence.
General Description:
The Visual Basic Upgrade Companion uses a powerful static code analyzer to determine the correct type for each object. By having the correct type for each object, the VBUC is able to determine its default property and expand this property in the converted code.
However, there are some cases where it’s not possible to determine the type of an object by using this technique. For these scenarios, the VBUC provides a helper class that is able to determine the type of these objects at runtime and get or set their default property.
In the following example, the variable ctl is used to iterate over a different type of controls. Each of these controls has different default properties, thus, during runtime, the default property of ctl will change. If this example is converted using this option, the helper class will determine the type of each use of the ctl variable at runtime and will get the appropriate default property for each instance.
Original VB6 code:
Dim s AsString'Display the default property of controls of a Form'For Each ctl In Me.Controls s = ctl MsgBox sNext ctl'Display the default property of TextBox'MsgBox Me.TextBox1
C# code:
string s =String.Empty;//Display the default property of controls of a Formforeach (Control ctl inContainerHelper.Controls(this)){ s =ReflectionHelper.GetPrimitiveValue(ctl).ToString(); MessageBox.Show(s,Application.ProductName);}//Display the default property of TextBoxMessageBox.Show(this.TextBox1.Text,Application.ProductName);
VB.NET code:
Dim s AsString=""'Display the default property of controls of a Form'For Each ctl As Control In ContainerHelper.Controls(Me) s = ReflectionHelper.GetPrimitiveValue(ctl).ToString() MessageBox.Show(s, Application.ProductName)Next ctl'Display the default property of TextBox'MessageBox.Show(Me.TextBox1.Text, Application.ProductName)
3.2. Static code analysis only
By switching this feature on, the VBUC will use a powerful static code analysis process to determine the correct type for each object and expands its default property.
Expands the default properties by using only static code analysis.
There are some cases where it’s not possible to determine the type of an object by using static code analysis and it may require manual intervention to achieve functional equivalence.
General Description:
The Visual Basic Upgrade Companion (VBUC) uses a static code analysis process to infer/determine the correct type for each object. By having the correct type of each object, the VBUC can determine the default property of the object and expand this property in the converted code.
However, there some cases where it is not possible to determine the type of an object by using a static code analysis. For these cases manual changes are required to achieve functional equivalence.
Original VB6 code:
Dim s AsString'Display the default property of controls of a Form'For Each ctl In Me.Controls s = ctl MsgBox sNext ctl'Display the default property of TextBox'MsgBox Me.TextBox1
C# code:
string s =String.Empty;//Display the default property of controls of a Formforeach (Control ctl inContainerHelper.Controls(this)){ //UPGRADE_WARNING: (1068) ctl of type VB.Control is being forced to string s =ctl.ToString();MessageBox.Show(s,Application.ProductName);}//Display the default property of TextBoxMessageBox.Show(this.TextBox1.Text,Application.ProductName);
VB.NET code:
Dim s AsString=""'Display the default property of controls of a Form'For Each ctl As Control In ContainerHelper.Controls(Me)'UPGRADE_WARNING: (1068) ctl of type VB.Control is being forced to String.' s = ctl.ToString() MessageBox.Show(s, Application.ProductName)Next ctl'Display the default property of TextBox'MessageBox.Show(Me.TextBox1.Text, Application.ProductName)
4. Error Handling
4.1. Leave on Error Statements (VB.NET Only)
By choosing this option the VBUC will generate .NET source code that employs the “On Error” statements just like the Visual Basic 6 code.
This option increases the automation and reduces the manual effort required to get functional equivalence.
This feature is optional while upgrading to Visual Basic .NET but is not available for C#.
General Description:
The “On Error Go To” and “On Error Resume Next” error handling statements present in the Visual Basic 6 code will remain the same on the Visual Basic .NET output code. This feature removes the need for manual changes to bring the error handling statements to functional equivalence since it will be used the same in the upgraded code.
Original VB6 code:
Public Sub OnErrorGotoLabelMethod(arg AsString)On Error GoToerrHnd Dim s AsInteger s =CInt(arg) Foo s Exit SuberrHnd: MsgBox "Invalid Argument"End SubPublic Sub OnErrorResumeNextMethod(arg AsString)On Error Resume Next MsgBox arg MsgBox CInt(arg) MsgBox "This line will be executed allways" If Err.Number <>0 Then'This code should be executed if there were any error(s)' MsgBox "OnErrorResumeNextMethod reached the last statement" MsgBox "OnErrorResumeNextMethod reached the last statement" MsgBox "OnErrorResumeNextMethod reached the last statement" End IfEnd Sub
VB.NET code:
Public Sub OnErrorGotoLabelMethod(ByVal arg AsString)On Error GoToerrHnd Dim s AsInteger s =CInt(arg)Foo(s) Exit SuberrHnd: MessageBox.Show("Invalid Argument", My.Application.Info.Title)End SubPublic Sub OnErrorResumeNextMethod(ByVal arg AsString)On Error Resume Next MessageBox.Show(arg, My.Application.Info.Title) MessageBox.Show(CStr(CInt(arg)), My.Application.Info.Title) MessageBox.Show("This line will be executed allways", My.Application.Info.Title) If Information.Err().Number <>0 Then'This code should be executed if there were any error(s)' MessageBox.Show("OnErrorResumeNextMethod reached the last statement", My.Application.Info.Title) MessageBox.Show("OnErrorResumeNextMethod reached the last statement", My.Application.Info.Title) MessageBox.Show("OnErrorResumeNextMethod reached the last statement", My.Application.Info.Title) End IfEnd Sub
4.2. Convert to Try-Catch
The most common occurrences of error handling patterns will be automatically upgraded to Try-Catch blocks using this feature. It covers a vast amount of On Error Goto patterns and very basic cases of On Error Resume Next.
This option generates more .NET-like code.
This feature is optional while upgrading to Visual Basic .NET but is compulsory for C# code generation.
General Description:
The Visual Basic Upgrade Companion analyzes the execution control of the Visual Basic 6 code detecting the “On Error GoTo” error handling patterns to generate .NET inherent Try-Catch blocks. When "On Error Resume Next" error handling patterns are found, they will be transformed to a basic Try-Catch block, which will have a different behavior. For the most common scenarios this transformation generates error-free pure .NET code out of the box. For more radical cases, the spaghetti-like error handling code found on Visual Basic 6 might require either some changes prior to the upgrade process or manual efforts once it is upgraded to .NET.
Original VB6 code:
Public Sub OnErrorGotoLabelMethod(arg AsString)On Error GoToerrHnd Dim s AsInteger s =CInt(arg) Foo s Exit SuberrHnd: MsgBox "Invalid Argument"End SubPublic Sub OnErrorResumeNextMethod(arg AsString)On Error Resume Next MsgBox arg MsgBox CInt(arg) MsgBox "This line will be executed allways" If Err.Number <>0 Then'This code should be executed if there were any error(s)' MsgBox "OnErrorResumeNextMethod reached the last statement" MsgBox "OnErrorResumeNextMethod reached the last statement" MsgBox "OnErrorResumeNextMethod reached the last statement" End IfEnd Sub
C# code:
publicvoidOnErrorGotoLabelMethod(string arg){try {int s =0; s =Convert.ToInt32(Double.Parse(arg)); Foo(s); }catch {MessageBox.Show("Invalid Argument",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); }}publicvoidOnErrorResumeNextMethod(string arg){ //UPGRADE_TODO: (1069) Error handling statement (On Error Resume Next) was converted to a pattern that might have a different behavior.try {MessageBox.Show(arg,AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));MessageBox.Show(Convert.ToInt32(Double.Parse(arg)).ToString(),AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));MessageBox.Show("This line will be executed allways",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); //UPGRADE_WARNING: (2081) Err.Number has a new behavior.if (Information.Err().Number!=0) { //This code should be executed if there were any error(s)MessageBox.Show("OnErrorResumeNextMethod reached the last statement",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));MessageBox.Show("OnErrorResumeNextMethod reached the last statement",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));MessageBox.Show("OnErrorResumeNextMethod reached the last statement",AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly())); } }catch (Exception exc) {NotUpgradedHelper.NotifyNotUpgradedElement("Resume in On-Error-Resume-Next Block"); }}
VB.NET code:
Public Sub OnErrorGotoLabelMethod(ByVal arg AsString) Try Dim s AsInteger s =CInt(arg)Foo(s) Catch MessageBox.Show("Invalid Argument", My.Application.Info.Title) End TryEnd SubPublic Sub OnErrorResumeNextMethod(ByVal arg AsString)'UPGRADE_TODO: (1069) Error handling statement (On Error Resume Next) was converted to a pattern that might have a different behavior.' Try MessageBox.Show(