Warnings
The following are some of the most common warnings generated by the Visual Basic Upgrade Companion.
206 - Untranslated statement in %1. Please check source code
Description
This warning indicates an unexpected error during the automated upgrade process. As a result, some of the VB6 source code was not upgraded.
Recommendations
Please report the issue to Mobilize Support.
You can manually write the missing code if the affected code is simple enough.
1003 - ParamArray %1 was changed from ByRef to ByVal
Description
In VB6, the Param Array keyword could specify an arbitrary number of parameters for a declaration, sub, or function. ParamArrays were always passed by reference (ByRef). In Visual Basic .NET, ParamArrays are always passed by value; the Param Array keyword must be preceded by the ByVal keyword. When a parameter is passed by value, a copy of the variable is passed; when passed by reference, a pointer to the variable is passed. When passing by value, it is possible that the value of the variable may have changed and that the copy is out of date.
Recommendations
Review the code to ensure that the variables being passed as parameters are not changed between their setting and their use in a procedure.
If necessary, modify your code to execute the procedure before the variables are modified.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
1044 - Sub Main in a DLL won't get called
Description
This EWI is generated when a non-EXE project has a Sub Main as a startup object.
Recommendations
Since .NET DLLs do not have any method to execute it when the respective assembly is loaded, we have to add a static constructor and call the sub-main inside.
This will not be executed simultaneously as VB6 but is the most similar behavior.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
1047 - Application will terminate when Sub Main() finishes
Description
Standard EXE applications written in VB6 can be started either from the Main sub or a startup form. The use of the Main sub is a very common practice in large applications, because it allows the execution of initialization logic before the load of the main form of the application, and allows separation of this logic from the logic of the form.
When an application that uses the Main sub as a startup object is migrated using the VBUC, equivalent code is generated in .NET. However, due to differences in the behavior of VB6 and the .NET Framework, the applications behave differently. Some manual changes are required to achieve functional equivalence in this case.
In VB6, all the code in the Main sub is executed and the method ends, but the application continues to run while a form is displayed. In .NET, on the other hand, the application will exit as soon as the Main method exits, any open form at that point will be closed automatically.
See also: How to prevent the application from exiting immediately after starting
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
1049 - Use of Null/IsNull() detected
Description
In Visual Basic 6, the Null keyword indicates that a field contained no valid data and the IsNull function is used to test for Null. In addition, Visual Basic 6 support Null propagation when Null was used in an expression; the result of the expression would also be Null. This EWI indicates the use of the Null keyword or the IsNull function.
Recommendations
In Visual Basic .NET, the Null keyword is still a reserved word, but it has no syntactical value, and the IsNull function is no longer supported.
C# also reserves the null keyword, but it is not to be confused with Null in Visual Basic 6. Visual Basic's Null keyword indicated missing or invalid data in data field, which is the purpose of DbNull in the .Net Framework. C#'s version of null is closer to Visual Basic 6's Nothing keyword.
Also, Null propagation is no longer supported in the .NET framework. When upgrading Visual Basic 6 applications avoid null propagation.
During the upgrade, Null is converted to DBNull, and IsNull is converted to IsDBNull of which there are several variants: Visual Basic's IsDBNull function, the Convert.IsDBNull method, the DataTableReader.IsDBNull method, and the IDataRecord.IsDBNull method.
The behavior of DBNull is slightly different than that of Null. Null could be used in functions and assignments as a Variant data type, however DBNull is a class and thus cannot be used as a direct replacement for Visual Basic's Null. DBNull.Value, however, can be passed as a value type in methods or assignments.
Where Null was used with a Variant data type, the Variant is converted to Object during the upgrade; in these cases, depending on the context, it may be more appropriate to use the Nothing and the IsNothing function for VB.NET. For C# use the null keyword and compare it with null with the equality operators (== and !=).
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
1063 - Arrays in structure %1 may need to be initialized before they can be used
Description
In C#, fixed-size arrays in structures are not supported. Fixed-size arrays that are members of structures defined in COM interfaces will need to be initialized before they can be used.
Recommendations
Call the Initialize function of the structure, right after the variable declaration.
VB6 Original Code
C# Upgraded Code
1068 - %1 of type %2 is being forced to %3
Description
The VBUC typing engine is able to infer the correct data type of undefined or Variant-type variables, and assign them the correct data type. In some scenarios, a variant-type variable is upgraded to a scalar value; this type of inference is done over the variable usage and context.
Recommendations
There are no recommendations.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
1070 - Member access from a dynamic/late binding object will be resolved using the ReflectionHelper
Description
When the VBUC's mechanism for solving Late Binding cannot determine the type of a class, and the ReflectionHelper feature is enabled, the ReflectionHelper class will be used to attempt to correctly resolve the late binding instance at runtime.
Recommendations
The ReflectionHelper class should be able to determine most cases of Late Binding at runtime.
Manually modify the upgraded code to determine the correct base class.
VB6 Original Code
The original code uses a variant to allow any object to be passed, and have its Enabled property set to true. VB6's late binding will solve this.
In a case such as this where the VBUC cannot determine a base type for all items passed to the method, it will use the ReflectionHelper to solve the late binding issue at runtime, as seen in the following example.
C# Upgraded Code
VB.NET Upgraded Code
2050 - %1 Event %2.%3 was not upgraded
Description
The VBUC is able to map VB6 library members to .NET equivalents. These equivalents are chosen to provide maximum functional equivalence on the target platform. In particular scenarios, some class properties and events may not have a direct equivalent in .NET or may not have been mapped in the current release of the VBUC. The event handler is declared in the target source code but there are no equivalent events to associate the handler to.
Recommendations
Use a more specialized/similar component to the original one, which provides the required events in the target platform.
Create an explicit invocation to the event handler method in the given circumstances to simulate the event triggering.
Associate the upgraded handler method to one or more .NET available events in case those events satisfy the code requirements and the original event behavior.
Refactor the code to apply a different solution. This strategy makes sense especially when the concepts in .NET are very different from the VB6 ones. In these cases it is likely that the way to implement a particular process should be done with a different approach.
VB6 Original Code
Sample taken from Drag & Drop Changes in Visual Basic .NET
C# Upgraded Code
C# Expected Code
In this case the sample code deals with manually handling Drag & Drop operations in a Visual Basic 6 application. As is clearly stated in that MSDN article we need to write custom code for the drag & drop operation. In this case, we replace the OLEDragOver event which no longer exists in .Net, and replaces it with the DragEnter event. Within this event, we add our drag & drop logic.
VB.NET Upgraded Code
VB.NET Expected Code
In this case, the sample code deals with manually handling Drag & Drop operations in a Visual Basic 6 application. As is clearly stated in that MSDN article we need to write custom code for the drag & drop operation. In this case, we replace the OLEDragOver event which no longer exists in .Net, and replaces it with the DragEnter event. Within this event, we add our drag & drop logic.
2065 - %1 %2 %3.%4 has a new behavior
Description
During the upgrade process, some events can be mapped to .NET with minor behavior differences. If this EWI is displayed in a given project, the selected target event will not threaten the functional equivalence of the resulting code but can create small differences that may require some manual adjustments.
Recommendations
Each case will have to be evaluated individually, as the behavior differences may not be significant for every project. Some common properties with new behaviors include the following:
System.Windows.Forms.Control.Controls collection, which is a hierarchical list of NamingContainers and is usually navigated recursively. It's important to remember that Child controls will not be in the parent's Controls collection.
Likewise, System.Windows.Forms.ControlCollection.Count does not represent the same number in .NET as in VB6, as only direct descendants of the current control will be counted. Any child controls will be part of their respective parent's ControlCollection.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
2074 - %1 %2 %3.%4 was upgraded to %5.%6 which has a new behavior
Description
During the upgrade process, some class members and events can be mapped to a .NET equivalent with minor behavior differences. If this EWI is displayed in a given project, the selected source structure will not threaten the functional equivalence of the resulting code but can require some manual adjustments.
Recommendations
Compare the new .NET members and events to the old ones and verify their behavioral equivalence.
MSDN contains some lists as well as documentation on these equivalences: Windows Forms Controls for Visual Basic 6.0 Users
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
2077 - Change the default 0 index in the Rows property with the correct one
Description
When upgrading an ADO Recordset object to native ADO.NET, the VBUC converts all the Recordset objects to System.Data.DataSet, however, there are major differences between these two classes. Cursors in ADO control record navigation in a Recordset; this way you are always pointing to a current row in the Recordset. This concept is not available in a DataSet object, which contains a collection of tables, and each table contains a collection of Rows and Columns, among other data. Since there is no current row concept in a DataSet object, when there are uses of a Recordset's current row, the VBUC then converts them to be the first row of the first table in the DataSet, and this EWI is generated.
In ADO, most of the time Recordset objects contain a single table retrieved from the Database. Therefore, the generated DataSets will only have one table in their Tables collections.
Recommendations
Review case by case to see if the first record of the DataTable object is actually the one intended to be used. If not, a change of logic might be required to achieve the functional equivalence between the original application and the upgraded one.
Also, turn on the ADODB-RDO feature in the VBUC (when available) to generate "Foreach" structures in places that match common recordset navigation patterns.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
2080 - %1 was upgraded to %2 and has a new behavior
Description
The Visual Basic Upgrade Companion converts VB6 library items (types and members) to .NET equivalents whenever possible. For some VB6 elements, there are .NET constructs that work in a very similar way but may differ in their behavior depending on how they are used. The VBUC generates this EWI for these scenarios.
During the upgrade process, some class members can be mapped to .NET structures with minor behavior differences. If this EWI is displayed in a given project, the selected target structure will keep the functional equivalence of the resulting code but may end up having small differences in some cases that may require some manual fine-tuning, such as methods that are called in a different order or text that is displayed in a different font.
Recommendations
Evaluate whether the specific differences might be present on the specific code being upgraded. Sometimes these potential differences will not affect the application depending on how the original VB6 element was used.
Apply some modification to the upgraded source code which references the conflictive elements so that the differences are resolved.
Implement a new element in .NET that does not show the conflictive behavior differences. This might be done from scratch or by taking advantage of the existing .NET elements by using extension or wrapping approaches.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
2081 - %1 has a new behavior
Description
The Visual Basic Upgrade Companion converts VB6 library items (types and members) to .NET equivalents whenever possible. For some VB6 elements, there are .NET constructs that work in a very similar way but may differ in their behavior depending on how they are used. The VBUC generates this EWI for these scenarios.
During the upgrade process, some class members can be mapped to .NET structures with minor behavior differences. If this EWI is displayed in a given project, the selected target structure will keep the functional equivalence of the resulting code but may end up having small differences in some cases that may require some manual adjustments, such as methods that are called in a different order or text that is displayed in a different font.
Recommendations
Evaluate whether the specific differences might be present on the specific code being upgraded. Sometimes these potential differences will not affect the application depending on how the original VB6 element was used.
Apply some modification to the upgraded source code which references the conflictive elements so that the differences are resolved.
Implement a new element in .NET that does not show the conflictive behavior differences. This might be done from scratch or by taking advantage of the existing .NET elements by using extension or wrapping approaches.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
2099 - Return value for Dir has a different behavior
Description
In VB6 when using the FileSystem.Dir we can get the first file name that matches the pathname used, but when no more file names match, it returns an empty string (""), that way you could perform an operation to get all the elements inside the Windows folder.
VB6 Original Code
When upgrading the previous code you will get the following code:
C# Upgraded Code
If no more file names match, the FileSystem.Dir will return a null value instead of an empty string, causing a runtime exception when the previous code is executed. A manual change to fix this behavior could be to change the comparison between the Files variable and the empty string with the IsNullOrEmpty method.
6002 - UserControl Event 1% is not supported
Description
Using the VBUC, ActiveX controls can be upgraded to .NET Windows Controls. This can present a problem when upgrading certain ActiveX User Controls that implement Events that are no longer supported in .NET. In most cases, this is because they do not have an exact equivalent in .NET.
Recommendations
An understanding of both the source platform and the target platform is helpful in coming up with a viable solution. Some of this is described in MSDN's User Controls for Visual Basic 6.0 Users.
Visual Basic 6.0 Support
Resources for those unfamiliar with Visual Basic 6.0 ActiveX Controls:
Creating an ActiveX Control - a basic tutorial from which the sample VB6 code was taken.
UserControl properties - on UserControl's built-in properties.
Life and Times of a UserControl Object - on the events and lifecycle of a UserControl.
Extender Object - for an overview of the Extender object.
.NET Framework Support
VB6 Original Code
C# Upgraded Code
C# Expected Code
This solution makes use of Application Settings to replace Visual Basic 6's PropertyBag. In most cases, this is not necessary as .NET's design model maintains the state of properties without the use of the Settings object. This example assumes that these values need to be preserved between instances of the program. We've also fixed up the code relating to the use of the Extender object.
VB.NET Upgraded Code
VB.NET Expected Code
This solution makes use of Application Settings to replace Visual Basic 6's PropertyBag. In most cases, this is not necessary as .NET's design model maintains the state of properties without the use of the Settings object. This example assumes that these values need to be preserved between instances of the program. We've also fixed up the code relating to the use of the Extender object.
6021 - Casting 'int' to Enum may cause different behavior
Description
Enums in .NET are integral types and therefore any valid integral value can be cast to an Enum type. This is still possible even when the value being cast is outside of the values defined for the given enumeration. Thus, when mixing integers with Enums it is possible to create invalid Enumeration instances that do not reference any of the defined values for that Enumeration.
Recommendations
One possible workaround is to use Enum.IsDefined() method to verify if a given integral value is defined for a given Enumeration. This method however will not work for enumerations marked with the Flags attribute and which are used as a bit map.
Additionally, one can ensure logic checks explicitly for defined Enum values and does not assume Enum-typed variables will conform to the defined list of values.
In many cases, functional equivalence will be maintained, but an effort should be made to eliminate these casts to ensure a cleaner code.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
6022 - The CommonDialog CancelError property is not supported in .NET
Description
The property CommonDialog.CancelError is not currently supported by VBUC, nevertheless, it is possible to get a similar behavior or functionality by using .NET properties.
Recommendations
Understand how the CommonDialog.CancelError property is used in the VB6 source code and applies a manual change in order to emulate the behavior in the .NET platform. In .NET, the CommonDialog.ShowDialog() method shows the Dialog and after the dialog is closed, returns the information of the Dialog button that was pressed by the user. This returning value must be compared against the members of the System.Windows.Forms.DialogResult Enumeration.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
7005 - Parameters (if any) must be set using the Arguments property of ProcessStartInfo
Description
This EWI appears when you are upgrading a Shell call, and it means that the way that parameters are passed to a process in .NET is different than the VB6's.
Recommendations
If you need to pass parameters to a command being executed by a Shell, split the command and the arguments.
VB6 Original Code
C# Upgraded Code
VB.NET Upgraded Code
7006 - The Named argument %1 was not resolved and corresponds to the following expression %2
Description
Both VB6 and VB.Net have support for Named parameters, which allow parameters to be specified by name and in any order, regardless of the method signature. In C# versions 1 through 3.5 this feature is not supported. In most cases, VBUC can resolve this issue by matching named parameters to method signatures and ensuring parameters are sent in the right overload/order. However, in certain cases where the VBUC cannot resolve references to methods with named parameters, this EWI is emitted.
Recommendations
For C# migrations, the VBUC generally creates a series of method overloads that mimic the behavior of named parameters. This is normal behavior as it is the best approximation of optional named parameters in C#. Workarounds for this EWI include reordering parameters and using the Type.Missing reference for optional parameters that should be omitted. In cases where the reference could not be resolved, this is particularly important. Since this EWI is related to the VBUC not being able to find mapped references, ensuring that the machine doing the migration has access to all dependent assemblies and COM objects is essential. Repeating the migration once this has been correct can reduce or eliminate the occurrence of these EWIs.
Reference documentation for sample code:
Since this EWI only appears in C#, an example will be shown just for that language.
VB6 Source Code
C# Upgraded Code
C# Expected Code
7008 - The ProgId could not be found on computer where this application was migrated
Description
This specific issue arises when converting VB6 applications that use API calls to interact with programs from the Microsoft Office suite, such as Word, Excel, or PowerPoint; the issue appears in the upgraded code if the application is converted on a machine that does not have the Microsoft Office components installed.
Recommendations
There are two different options to remove the issue:
Install the Microsoft Office components and then convert the application again using VBUC.
Solve this issue manually.
VB6 Original Code
C# Upgraded Code
C# Expected Code
VB.NET Upgraded Code
VB.NET Expected Code
7009 - Multiples invocations to ShowDialog in Forms with ActiveX Controls might throw runtime exceptions
Description
This EWI is not caused by a compilation error but may cause a runtime exception. The objective of this warning is to advise you to verify that the application is not having runtime issues when the ShowDialog method is called constantly, on a form that contains .NET third-party components or controls used through COM Interop.
Recommendations
Test the runtime behavior of the form and make sure that no runtime exceptions are thrown when calling the ShowDialog method repeatedly.
8007 - Trying to marshal a non Blittable Type (%1). A special conversion might be required at this point. Moreover use 'External Marshalling attributes for Structs' feature enabled if required
Description
This message indicates that at least one of the arguments to an API call that has now been converted to a .NET Platform invoke call has an issue. One important thing to note is the concept of "Blittable Types". Most data types have a common representation in both managed and unmanaged memory and do not require special handling by the interop marshaler. These types are called blittable types because they do not require conversion when passed between managed and unmanaged code.
The following types from the System namespace are blittable types:
System.Byte
System.SByte
System.Int16
System.UInt16
System.Int32
System.UInt32
System.Int64
System.IntPtr
System.UIntPtr
The following complex types are also blittable types:
One-dimensional arrays of blittable types, such as an array of integers.
Formatted value types that contain only blittable types (and classes if they are marshaled as formatted types).
This is important for VB6 migrations because if you are calling a DLL you will not be able to pass a non-blittable type because that DLL will expect a binary representation different from that in the .NET virtual machine.
This is also an issue in other scenarios like:
Serializing content to files.
Sending messages through messaging mechanisms like named-pipes or sockets.
What should I do with non-blittable types?
If your type is not blittable and it is a struct the VBUC can automatically add marshalling attributes that will help you.
If your type is a decimal, a DateTime, or a GUID you can use some helper instead. For example the helpers by Andrey Akinshing
So, for example, for Decimal you can use:
Or for DateTime you can use:
Last updated