ToDos

The following are some of the most common ToDos generated by the Visual Basic Upgrade Companion.

1035 - #If #EndIf block was not upgraded because the expression %1 did not evaluate to True or was not evaluated

Description

The #If #EndIf directives are evaluated by the VBUC preprocessing engine during the preliminary stage of the upgrade process. The current compiler-variable values are taken into consideration to figure out which blocks of code are active and which are inactive. The active blocks are upgraded to .NET, while the inactive ones are copied unchanged to the upgraded code and preceded by this EWI.

Recommendations

Often, conditional compilation directives might be missing and not all code paths will be expressed. Conditional compilation constants can be defined in three different ways in VB6:

How To Set

Scope

Project Properties dialog box

Public to all modules in the project

Command line

Public to all modules in the project

#Const statement in code

Available only in the module in which they are declared

Knowing the scope of these constants can help when modifying the code to correct this EWI. If the inactive code is small and simple, it can safely be rewritten manually. However, if the conditionally compiled code is extensive, an extra migration might be required. Different values of the conditional constants can be used for all valid permutations. This will convert previously inactive blocks of code. The results can then be manually merged to get a fully converted code block.

In some cases, it might be possible to comment out the conditionally compiled code segments completely. This will only work if there are no conflicts and the original code can be upgraded without the conditional compilation directives.

In order to apply for this workaround, the original code should compile.

Some inactive blocks of code might no longer be in use. If this is the case, then those code segments can be removed. Special care should be taken when reviewing conditionally compiled code. Locally declared variables do not affect and are not used for the evaluation of conditional compilation directives.

VB6 Original Code

#Const ShowMessage = -1 'True

Public Sub ConditionalCompilation()
   'ShowMessage is True'
   #If ShowMessage Then
      MsgBox "It will show this message!"
   #Else
      MsgBox "This text will not show!"
   #End If
End Sub

Public Sub ImproperConditionalCompilation()
   Dim show As Boolean
   Set show = True
   ' show is a local variable, and is not'
   ' used for conditional compilation'
   #If show Then
      MsgBox "This text will not show!"
   #Else
      'This message box is shown.'
      MsgBox "It will show this message!"
   #End If
End Sub

C# Upgraded Code

internal static class Module1
{
   //True

   internal static void ConditionalCompilation()
   {
      //ShowMessage is True
#if ShowMessage
      MessageBox.Show("It will show this message!", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
#else
      //UPGRADE_TODO: (1035) #If #EndIf block was not upgraded because the expression Else did not evaluate to True or was not evaluated.
      //        MsgBox "This text will not show!"
#endif
    }

    internal static void ImproperConditionalCompilation()
    {
      // show is a local variable, and is not
      // used for conditional compilation
#if show
      //UPGRADE_TODO: (1035) #If #EndIf block was not upgraded because the expression show did not evaluate to True or was not evaluated.
      //        MsgBox "This text will not show!"
#else
      //This message box is shown.
      MessageBox.Show("It will show this message!", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
#endif
   }
}

VB.NET Upgraded Code

Module Module1
   #Const ShowMessage = -1 'True

   Public Sub ConditionalCompilation()
      'ShowMessage is True'
#If ShowMessage Then
      MessageBox.Show("It will show this message!", My.Application.Info.Title)
#Else
      'UPGRADE_TODO: (1035) #If #EndIf block was not upgraded because the expression Else did not evaluate to True or was not evaluated.'
      'MsgBox "This text will not show!"'
#End If
   End Sub

   Public Sub ImproperConditionalCompilation()
      ' show is a local variable, and is not'
      ' used for conditional compilation'
#If show Then
      'UPGRADE_TODO: (1035) #If #EndIf block was not upgraded because the expression show did not evaluate to True or was not evaluated.'
      'MsgBox "This text will not show!"'
#Else
      'This message box is shown.'
      MessageBox.Show("It will show this message!", My.Application.Info.Title)
#End If
   End Sub
End Module

1050 - Structure %1 may require marshalling attributes to be passed as an argument in this Declare statement

Description

In Visual Basic 6, user-defined types could be passed as an argument in a Declare statement for a Windows API. Actually, we have a feature called PInvoke (Platform Invocation Service) that allows calls to native code and interact with .NET unmanaged code.

In Visual Basic .NET, a structure (user-defined type) passed as an argument in a Declare statement may require additional marshalling attributes in order to be passed correctly to the external function or subroutine. In particular, arrays and fixed-length strings may not function as expected without these attributes.

As mentioned before, we use the PInvoke feature; in this case, the declared statement will be commented and a new struct will be created using this feature in another file.

To see more information: PInvoke feature

Recommendations

Add an Imports statement to reference the System.Runtime.InteropServices namespace and then modify the structure and the string declaration to include marshalling attributes.

VB6 Original Code

Private Type MyStructure
   Name As String
   size As Integer
End Type

Declare Function FunctionName Lib "MyLibrary.DLL" (ByVal rs1 As MyStructure) As Long

C# Upgraded Code

Module1.cs

//UPGRADE_NOTE: (2041) The following line was commented.
////UPGRADE_TODO: (1050) Structure MyStructure may require marshalling attributes to be passed as an argument in this Declare statement.
//[DllImport("MyLibrary.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
//extern public static int FunctionName(UpgradeSolution1Support.PInvoke.UnsafeNative.Structures.MyStructure rs1);

UnsafeMethods\Structures.cs

public struct MyStructure
{
   public string Name;
   public short size;
   private static void InitStruct(ref MyStructure result, bool init)
   {
      if (init)
      {
         result.Name = String.Empty;
      }
   }
   public static MyStructure CreateInstance()
   {
      MyStructure result = new MyStructure();
      InitStruct(ref result, true);
      return result;
   }
   public MyStructure Clone()
   {
      MyStructure result = this;
      InitStruct(ref result, false);
      return result;
   }
}

C# Expected Code

Module1.cs

//UPGRADE_NOTE: (2041) The following line was commented.
////UPGRADE_TODO: (1050) Structure MyStructure may require marshalling attributes to be passed as an argument in this Declare statement.
//[DllImport("MyLibrary.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
//extern public static int FunctionName(UpgradeSolution1Support.PInvoke.UnsafeNative.Structures.MyStructure rs1);

UnsafeMethods\Structures.cs

public struct MyStructure
{
   [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 256)]
   public string Name;
   [MarshalAs(UnmanagedType.I4)]
   public short size;
   private static void InitStruct(ref MyStructure result, bool init)
   {
      if (init)
      {
         result.Name = String.Empty;
      }
   }
   public static MyStructure CreateInstance()
   {
      MyStructure result = new MyStructure();
      InitStruct(ref result, true);
      return result;
   }
   public MyStructure Clone()
   {
      MyStructure result = this;
      InitStruct(ref result, false);
      return result;
   }
}

VB.NET Upgraded Code

Module1.vb

'UPGRADE_NOTE: (2041) The following line was commented.'
'UPGRADE_TODO: (1050) Structure MyStructure may require marshalling attributes to be passed as an argument in this Declare statement.'
'Declare Function FunctionName Lib "MyLibrary" (ByVal rs1 As UpgradeSolution1Support.UnsafeNative.Structures.MyStructure) As Integer'

UnsafeMethods\Structures.vb

Public Structure MyStructure
   Dim Name As String
   Dim size As Short
   Private Shared Sub InitStruct(ByRef result As MyStructure, ByVal init As Boolean)
      If init Then
         result.Name = String.Empty
      End If
   End Sub
   Public Shared Function CreateInstance() As MyStructure
      Dim result As New MyStructure()
      InitStruct(result, True)
      Return result
   End Function
   Public Function Clone() As MyStructure
      Dim result As MyStructure = Me
      InitStruct(result, False)
      Return result
   End Function
End Structure

VB.NET Expected Code

Module1.vb

'UPGRADE_NOTE: (2041) The following line was commented.'
'UPGRADE_TODO: (1050) Structure MyStructure may require marshalling attributes to be passed as an argument in this Declare statement.'
'Declare Function FunctionName Lib "MyLibrary" (ByVal rs1 As UpgradeSolution1Support.UnsafeNative.Structures.MyStructure) As Integer'

UnsafeMethods\Structures.vb

Public Structure MyStructure
   <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)>
   Dim Name As String
   <MarshalAs(UnmanagedType.I4)>
   Dim size As Short
   Private Shared Sub InitStruct(ByRef result As MyStructure, ByVal init As Boolean)
      If init Then
         result.Name = String.Empty
      End If
   End Sub
   Public Shared Function CreateInstance() As MyStructure
      Dim result As New MyStructure()
      InitStruct(result, True)
      Return result
   End Function
   Public Function Clone() As MyStructure
      Dim result As MyStructure = Me
      InitStruct(result, False)
      Return result
   End Function
End Structure

1059 - Code was upgraded to use %1 which may not have the same behavior

Description

This EWI appears when a Visual Basic method call is changed to a .NET counterpart that may not have the same behavior as the original.

Recommendations

  • In most cases, the .NET equivalents provide equivalent functionality, but there can be some cases for which its functionality differs. Most commonly VB6 performed a lot of validations and auto coercions. Unfortunately, there is such a wide variety of cases that might cause this EWI that it would be prohibitive to list them all with possible resolutions. It is, however, important to note that oftentimes these differences can depend on the parameters passed to the methods. Thus choosing a different signature of the same method might provide the desired functionality.

  • Therefore, it is recommended that the migration consultant research the target and source methods to achieve the desired functionality.

VB6 Original Code

Attribute VB_Name = "Module1"
Public Function CoercionArrayToString(ByRef ByteArray() As Byte) As String
   CoercionArrayToString = ByteArray
End Function

Public Function CoercionStringToArray(ByVal ByteText As String) As Byte()
   CoercionStringToArray = ByteText
End Function

C# Upgraded Code

internal static string CoercionArrayToString(byte[] ByteArray)
{
   //UPGRADE_WARNING: (1059) Code was upgraded to use UpgradeHelpers.Helpers.StringsHelper.ByteArrayToString() which may not have the same behavior.
   return StringsHelper.ByteArrayToString(ByteArray);
}

internal static byte[] CoercionStringToArray(string ByteText)
{
   //UPGRADE_WARNING: (1059) Code was upgraded to use System.Text.UnicodeEncoding.Unicode.GetBytes() which may not have the same behavior.
   return UnicodeEncoding.Unicode.GetBytes(ByteText);
}

VB.NET Upgraded Code

Public Function CoercionArrayToString(ByVal ByteArray() As Byte) As String
   'UPGRADE_WARNING: (1059) Code was upgraded to use UpgradeHelpers.Helpers.StringsHelper.ByteArrayToString() which may not have the same behavior.'
   Return StringsHelper.ByteArrayToString(ByteArray)
End Function

Public Function CoercionStringToArray(ByVal ByteText As String) As Byte()
   'UPGRADE_WARNING: (1059) Code was upgraded to use System.Text.UnicodeEncoding.Unicode.GetBytes() which may not have the same behavior.'
   Return UnicodeEncoding.Unicode.GetBytes(ByteText)
End Function

1065 - Error handling statement (%1) could not be converted

Description

This EWI is generated when an error-handling statement is too complex or if it is a pattern that is not supported by the VBUC.

Recommendations

  • Most occurrences of this EWI will require manual changes to the source code to fix the issue. However, most cases of an error label that is globally called within a function can be replaced by a single try-catch statement with the addition of return statements.

  • The error handling is associated with the Error Handling upgrade option in the VBUC Tool. You can change it to generate different code.

See also: Error Handling Upgrade Option

VB6 Original Code

Public Function ErrorHandlingStatement() As String
   Dim ObjD As Integer
   On Error GoTo LabelErr
LabelStart:
   ObjD = ErrRaisableSub
LabelExit:
   Exit Function
LabelErr:
   If ObjD = 1 Then
      Resume LabelStart
   Else
      Resume LabelExit
   End If
End Function

C# Upgraded Code

public string ErrorHandlingStatement()
{
   int ErrRaisableSub = 0;
   int ObjD = 0;
   try
   {
      LabelStart:
      ObjD = ErrRaisableSub;
      LabelExit:;}
   catch
   {
      if (ObjD == 1)
      {
         //UPGRADE_TODO: (1065) Error handling statement (LabelStart) could not be converted.
         UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("Resume Label (LabelStart)");
      }
      else
      {
         //UPGRADE_TODO: (1065) Error handling statement (LabelExit) could not be converted.
         UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("Resume Label (LabelExit)");
      }
   }
   return "";
}

VB.NET Upgraded Code

Public Function ErrorHandlingStatement() As String
   Dim ErrRaisableSub, ObjD As Integer
   Try
LabelStart:
      ObjD = ErrRaisableSub
LabelExit:
   Catch
      If ObjD = 1 Then
         'UPGRADE_TODO: (1065) Error handling statement (LabelStart) could not be converted.'
         UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("Resume Label (LabelStart)")
      Else
         'UPGRADE_TODO: (1065) Error handling statement (LabelExit) could not be converted.'
         UpgradeHelpers.Helpers.NotUpgradedHelper.NotifyNotUpgradedElement("Resume Label (LabelExit)")
      End If
   End Try
End Function

1067 - Member %2 is not defined in type %3

Description

This EWI appears when an object cannot be typed correctly or a particular method could not be found in the class. This usually occurs in late binding scenarios. In some cases, the VBUC will still be unable to map the reference correctly due to late binding scenarios where multiple types are sent as parameters.

See also: Late Binding Resolution

VB6 Original Code

Public Sub CreateObjectExample()
   Dim PluginObj
   PluginObj = CreateObject("PluginNamespace.Plugin")
   PluginObj.Property = 0
   PluginObj.Func ("A")
   PluginObj.Action (1)
End Sub

C# Upgraded Code

public void CreateObjectExample()
{
   //UPGRADE_WARNING: (7008) The ProgId could not be found on computer where this application was migrated.
   //UPGRADE_WARNING: (1068) CreateObject() of type Plugin is being forced to Scalar.
   object PluginObj = ReflectionHelper.GetPrimitiveValue(Activator.CreateInstance(Type.GetTypeFromProgID("PluginNamespace.Plugin")));
   //UPGRADE_TODO: (1067) Member Property is not defined in type Variant.
   PluginObj.Property = 0;
   //UPGRADE_TODO: (1067) Member Func is not defined in type Variant.
   PluginObj.Func("A");
   //UPGRADE_TODO: (1067) Member Action is not defined in type Variant.
   PluginObj.Action(1);
}

VB.NET Upgraded Code

Public Sub CreateObjectExample()
   'UPGRADE_WARNING: (7008) The ProgId could not be found on computer where this application was migrated.'
   'UPGRADE_WARNING: (1068) CreateObject() of type Plugin is being forced to Scalar.'
   Dim PluginObj As Object = ReflectionHelper.GetPrimitiveValue(Activator.CreateInstance(Type.GetTypeFromProgID("PluginNamespace.Plugin")))
   'UPGRADE_TODO: (1067) Member Property is not defined in type Variant.'
   PluginObj.Property = 0
   'UPGRADE_TODO: (1067) Member Func is not defined in type Variant.'
   PluginObj.Func("A")
   'UPGRADE_TODO: (1067) Member Action is not defined in type Variant.'
   PluginObj.Action(1)
End Sub

1069 - Error handling statement (%1) was converted to a pattern that might have a different behavior

Description

This usually occurs when a Resume Next Error Handling Pattern appears. It is a warning because functional equivalence could not be accomplished in this scenario.

Recommendations

  • The Resume Next error handling pattern resumes execution of the next statement after an error. In the case of structured error handling, the resulting behavior is more similar to an On Error GoTo statement, where the catch statement serves as the GoTo label. For this reason, the replacement done by the VBUC might not be the exact functional equivalent of the original code. In cases where the code is related, meaning if one call fails subsequent calls are likely to fail, then leaving a single try-catch statement could work. Since an error at any point of the process would merely be replicated in the subsequent.

  • In other cases, the error pattern of Resume Next is necessary when the code statements are fairly independent (a failure in one statement does not affect the error condition of a subsequent call). In order to ensure functional equivalence, it's necessary to add a try-catch (with an empty clause) to each line that can throw an exception. In these cases the main try-catch (generated by the VBUC) is less effective and should be removed.

  • The error handling is associated with the Error Handling upgrade option in the VBUC Tool. You can change it to generate a different code.

See also: Error Handling Upgrade Option

VB6 Original Code

Public Function ComplexErrorPattern() As Integer
   F1 (1)
   On Error Resume Next

   Dim I As Integer
   I = 0
   I = F2(1)
   If I <> 0 Then
      I = F4(80)
   Else
      I = F3(50)
   End If
Exit_Label:
   ComplexErrorPattern = I
   Exit Function
End Function

C# Upgraded Code

public int ComplexErrorPattern()
{
   int[] F2 = null;
   int[] F4 = null;
   object[] F1 = null;
   int[] F3 = null;
   object tempAuxVar = F1[1];
   //UPGRADE_TODO: (1069) Error handling statement (On Error Resume Next) was converted to a pattern that might have a different behavior.
   try
   {
      int I = 0;
      I = F2[1];
      if (I != 0)
      {
         I = F4[80];
      }
      else
      {
         I = F3[50];
      }
      return I;
   }
   catch (Exception exc)
   {
      NotUpgradedHelper.NotifyNotUpgradedElement("Resume in On-Error-Resume-Next Block");
   }
   return 0;
}

VB.NET Upgraded Code

Public Function ComplexErrorPattern() As Integer
   Dim F2() As Integer, F4() As Integer
   Dim F1() As Object
   Dim F3() As Integer
   Dim tempAuxVar As Object = F1(1)
   'UPGRADE_TODO: (1069) Error handling statement (On Error Resume Next) was converted to a pattern that might have a different behavior.'
   Try
      Dim I As Integer = 0
      I = F2(1)
      If I <> 0 Then
         I = F4(80)
      Else
         I = F3(50)
      End If
      Return I
   Catch exc As Exception
      NotUpgradedHelper.NotifyNotUpgradedElement("Resume in On-Error-Resume-Next Block")
   End Try
End Function

2018 - Remove the next line of code to stop form from automatically showing

Description

VBUC converts MDI forms to regular .NET forms but also applies specific conversion rules in order to emulate exactly the same behavior as in VB6. If that behavior is no longer wanted, then just remove the tagged comment and the line of code that calls the Show method of the form.

This EWI will appear in the designer file.

Recommendations

  • If the MDI form in the VB6 project had its AutoShowChildren property set to True, to simulate the VB6 behavior, VBUC needs to automatically show the form whenever it is loaded.

VB6 Original Code

MDIForm1.frm

Private Sub MDIForm_Load()
   Form1Child.Show
End Sub

C# Upgraded Code

Form1Child.Designer.cs

partial class Form1Child
{
   ...
   public static Form1Child CreateInstance()
   {
      Form1Child theInstance = new Form1Child();
      //The MDI form in the VB6 project had its
      //AutoShowChildren property set to True
      //To simulate the VB6 behavior, we need to
      //automatically Show the form whenever it
      //is loaded.  If you do not want this behavior
      //then delete the following line of code
      //UPGRADE_TODO: (2018) Remove the next line of code to stop form from automatically showing.
      theInstance.Show();
      return theInstance;
   }
   ...
   void ReLoadForm(bool addEvents)
   {
      //This form is an MDI child.
      //This code simulates the VB6 
      // functionality of automatically
      // loading and showing an MDI
      // child's parent.
      this.MdiParent = Project1.MDIForm1.DefInstance;
      Project1.MDIForm1.DefInstance.Show();
   }
}

VB.NET Upgraded Code

Form1Child.Designer.vb

Partial Class Form1Child
   Public Shared Function CreateInstance() As Form1Child
      Dim theInstance As New Form1Child()
      'The MDI form in the VB6 project had its'
      'AutoShowChildren property set to True'
      'To simulate the VB6 behavior, we need to'
      'automatically Show the form whenever it'
      'is loaded.  If you do not want this behavior'
      'then delete the following line of code'
      'UPGRADE_TODO: (2018) Remove the next line of code to stop form from automatically showing.'
      theInstance.Show()
      Return theInstance
   End Function
   ...
   Sub ReLoadForm(ByVal addEvents As Boolean)
      'This form is an MDI child.'
      'This code simulates the VB6 '
      ' functionality of automatically'
      ' loading and showing an MDI'
      ' childs parent.'
      Me.MdiParent = Project1.MDIForm1.DefInstance
      Project1.MDIForm1.DefInstance.Show()
      ...
   End Sub
End Class

2045 - Only TrueType and OpenType fonts are supported in Windows Forms

VB6 Original Code

Private Sub Form_Load()
   Text1.FontName = "MS Sans Serif"
   cboBundleName.FontName = "MS Sans Serif"
End Sub

C# Upgraded Code

private void Form_Load()
{
   //UPGRADE_WARNING: (2045) Only TrueType and OpenType fonts are supported in Windows Forms.
   Text1.Font = Text1.Font.Change(name:"MS Sans Serif");
   //UPGRADE_WARNING: (2045) Only TrueType and OpenType fonts are supported in Windows Forms.
   cboBundleName.Font = cboBundleName.Font.Change(name:"MS Sans Serif");
}

VB.NET Upgraded COde

Private Sub Form_Load()
   'UPGRADE_WARNING: (2045) Only TrueType and OpenType fonts are supported in Windows Forms.'
   Text1.Font = Text1.Font.Change(name:="MS Sans Serif")
   'UPGRADE_WARNING: (2045) Only TrueType and OpenType fonts are supported in Windows Forms.'
   cboBundleName.Font = cboBundleName.Font.Change(name:="MS Sans Serif")
End Sub

7010 - The connection string must be verified to fullfill the .NET data provider connection string requirements

Description

In most cases, the conversion of ADO, RDO, or DAO to ADO.NET will require a manual modification of the connection string.

Recommendations

  • ADO.NET uses different parameters to connect to the database. The easiest way to know the appropriate connection string in the .NET environment is to use the "Data Connections" tool, which can be found in the "Server Explorer" tab of the .NET IDE, to create a new connection to the database and get the complete connection string from there.

  • This EWI is associated with the ADODB Upgraded Option. You can change it to generate a different code.

See also: ADODB to ADO.NET

VB6 Original Code

Public Sub connect()
   'Instantiate the connection'
   Set cnConexion = New Connection

   'Configure the connection string'
   strConex = "DRIVER=SQL Server;Database=NorthwindSQL;APP=Microsoft Data Access Components;SERVER=.\SQLEXPRESS"

   'Set the connection string of the Connection object'
   cnConexion.ConnectionString = strConex

   'Open the connection'
   cnConexion.Open
End Sub

C# Upgraded Code

internal static void connect()
{
   //Instantiate the connection
   DbConnection cnConexion = UpgradeHelpers.DB.AdoFactoryManager.GetFactory().CreateConnection();

   //Configure the connection string
   string strConex = "DRIVER=SQL Server;Database=NorthwindSQL;APP=Microsoft Data Access Components;SERVER=.\\SQLEXPRESS";

   //Set the connection string of the Connection object
   cnConexion.ConnectionString = strConex;

   //Open the connection
   //UPGRADE_TODO: (7010) The connection string must be verified to fullfill the .NET data provider connection string requirements.
   cnConexion.Open();
}

VB.NET Upgraded Code

Public Sub connect()
   'Instantiate the connection'
   Dim cnConexion As DbConnection = UpgradeHelpers.DB.AdoFactoryManager.GetFactory().CreateConnection()

   'Configure the connection string'
   Dim strConex As String = "DRIVER=SQL Server;Database=NorthwindSQL;APP=Microsoft Data Access Components;SERVER=.\SQLEXPRESS"

   'Set the connection string of the Connection object'
   cnConexion.ConnectionString = strConex

   'Open the connection'
   'UPGRADE_TODO: (7010) The connection string must be verified to fullfill the .NET data provider connection string requirements.'
   cnConexion.Open()
End Sub

7016 - This property was auto-generated because it is used in WriteProperties but does not exist.

Description

Visual Basic 6 allows the user to add design-time properties to user controls by adding them in the WriteProperties event of the UserControl class, even though the properties are not defined in the UserControl. The following example defines such a UserControl.

VB6 Original Code

Begin VB.UserControl MyUserControl 
   ClientHeight    =   570
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   2265
   ScaleHeight     =   570
   ScaleWidth      =   2265
   Begin VB.ComboBox Combo1 
      Height          =   315
      Left            =   120
      TabIndex        =   0
      Text            =   "Combo1"
      Top             =   120
      Width           =   2055
   End
End
Attribute VB_Name = "MyUserControl"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Private active as Boolean

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    active = PropBag.ReadProperty("IsActive", False)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    Call PropBag.WriteProperty("IsActive", active)
End Sub

When this type of control is added to a form, the form's designer code will look like this:

Begin Project1.Chkx Chkx1 
   Height          =   855
   Left            =   120
   TabIndex        =   0
   Top             =   120
   Width           =   1815
   _ExtentX        =   3201
   _ExtentY        =   1508
   IsActive        =   -1  'True
End

Since the UserControl does not contain an IsActive property, the VBUC will auto-generate one to provide a single place to fix this issue.

C# generated code

//UPGRADE_ISSUE: (2068) PropertyBag object was not upgraded. More Information: https://docs.mobilize.net/vbuc/ewis#2068
//UPGRADE_WARNING: (6002) UserControl Event ReadProperties is not supported. More Information: https://docs.mobilize.net/vbuc/ewis#6002
private void UserControl_ReadProperties(ref UpgradeStubs.PropertyBag PropBag)
{
	//UPGRADE_ISSUE: (2064) PropertyBag method PropBag.ReadProperty was not upgraded. More Information: https://docs.mobilize.net/vbuc/ewis#2064
	//UPGRADE_WARNING: (1068) PropBag.ReadProperty() of type Variant is being forced to bool. More Information: https://docs.mobilize.net/vbuc/ewis#1068
	active = Convert.ToBoolean(PropBag.ReadProperty("IsActive", false));
}

//UPGRADE_ISSUE: (2068) PropertyBag object was not upgraded. More Information: https://docs.mobilize.net/vbuc/ewis#2068
//UPGRADE_WARNING: (6002) UserControl Event WriteProperties is not supported. More Information: https://docs.mobilize.net/vbuc/ewis#6002
private void UserControl_WriteProperties(UpgradeStubs.PropertyBag PropBag)
{
	//UPGRADE_ISSUE: (2064) PropertyBag method PropBag.WriteProperty was not upgraded. More Information: https://docs.mobilize.net/vbuc/ewis#2064
	PropBag.WriteProperty("IsActive", active, null);
}

//UPGRADE_TODO: (7016) This property was auto-generated because it is used in WriteProperties but does not exist. More Information: https://docs.mobilize.net/vbuc/ewis#7016
private object _IsActive = null;
[Browsable(true)]
public object IsActive
{
	get
	{
		return _IsActive;
	}
	set
	{
		_IsActive = value;
	}
}

Recommendations

This code will provide the missing property at design time, but will need to be manually changed to provide the same functionality as the VB6 program. By using the contents of ReadProperties and WriteProperties, it should be possible to manually change the getter and setter of the new property to achieve functional equivalence.

How to prevent the application from exiting immediately after starting

Basic Scenario

The basic scenario is the invocation of the main form of the application from the Main sub. This is described here.

VB6 Application

We have a simple application with a main module which contains the main sub, and a main form that is displayed in the main sub.

This is the code for the main module:

Public Sub Main()
   MainForm.Show
   MsgBox "This message should be displayed first"
End Sub

As mentioned before, this application will start the execution on the main sub, display the main form and exit the main sub, keeping the main form open. The application will exit as soon as the main form is closed.

Upgraded Application

The VBUC tool generates lines that are equivalent to the lines in the original application, it also generates an EWI informing the user that the "Application will terminate when Sub Main() finishes".

//UPGRADE_WARNING: (1047) Application will terminate when Sub Main() finishes.
[STAThread]
public static void Main()
{
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(MainForm.DefInstance);
   MessageBox.Show("This message should be displayed first", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
}

If we execute this code, the main form window will be displayed and the main sub will not be executed until the main form is closed. To fix this behavior, you need to change the order in the VB6 application, placing form.show at the end of the main sub.

VB6 Code

Public Sub Main()
   MsgBox "This message should be displayed first"
   MainForm.Show
End Sub

CS Upgraded Code

[STAThread]
public static void Main()
{
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   MessageBox.Show("This message should be displayed first", AssemblyHelper.GetTitle(System.Reflection.Assembly.GetExecutingAssembly()));
   Application.Run(MainForm.DefInstance);
}

Last updated