VB Migration Partner's pragmas offer a powerful and granular approach to code customization. With 70+ pragmas available, you can control virtually any single aspect of code conversion. For example you can use pragmas to:
• correctly convert Null and Variant values
• solve problems caused by arrays with nonzero lower bound, As New (auto-instancing) variables, IDisposable variables, etc.
• optimize code that would be inefficient when converted as-is to .NET (e.g. string concatenation)
• prevent subtle runtime exceptions caused by imperfect functional equivalence between VB6 and VB.NET
• remove or comment unused or unreachable code, use Try-Catch blocks where possible, refactor Gosub keywords into calls to separate methods, and so forth
• ... and much more.
Each pragma is described in depth in our online documentation, therefore I won't explain what each pragma does. Suffice it to say that all these pragmas allow you be in control of VB Migration Partner's code generation engine, so that you can always generate the most efficient and robust VB.NET code that is functional equivalent to the original VB6 project.
The purpose of this article is to compare migration pragmas with the customization mechanisms offered by other VB6 conversion tools.
In a nutshell, a migration pragma is a remark that you insert in the original VB6 code base or in a separate file named <projectname>.pragmas. Pragma files are very handy for copying groups of pragmas to another migration project, on the same or different computer. Pragma files even support #Include directives, therefore different projects can actually share a centralized pragma file. If you later want to add or remove a pragma from the centralized file you don't have to manually edit individual files.
The great thing about pragmas is that they can affect the entire solution/project, a single file, or an individual method or variable. This sophisticated scoping mechanism allows you to define a general conversion rule at the project-level and then mention one or more exceptions at the file-, method-, or variable-level.
VB Migration Partner is the only conversion software that supports pragmas. All other conversion tools offer personalization rules that can only work at the project level. Each rule is an all-or-nothing decision, and you can't apply a rule only to a portion of the project. As you'll see shortly, such lack of granularity can be a problem in real-world scenarios.
Let’s see a concrete example that shows how the two approaches compare to each other.
VB6 language supports Variant variables, which can contain both a scalar value - e.g. a number or a string - or a reference to an object. When migrating to VB.NET such Variant variables, all migration tools convert those Variant variables as Object variables. For example, consider the followingVB6 code:
Sub ShowDefaultMemberValue(ByVal var As Variant)
Dim s As String
s = var
This method works well both when var contains a scalar value and when it contains a reference to an object, for example a TextBox control. In the latter case, the method displays the default member for the object (e.g. the Text property if var points to a TextBox control, or the Value property if var points to an ADODB.Field object.)
By default, VB Migration Partner and other conversion tools convert the above method to VB.NET as follows:
Sub ShowDefaultMemberValue(ByVal var As Object)
Dim s As String = var
This code works well if var contains a scalar value, but throws an InvalidCast exception if var points to an object. The reason is that the VB.NET is unable to extract the default member of an object, unlike VB6.
NOTE: VB Migration Partner and possibly other products can, in some cases, use type inference to convert these Variants into definite types such as Integer or String. Besides, VB Migration Partner is also able to use the special VB6Variant variables, for improved functional equivalence. We won't take these cases into account, because aren't important for our general discussion on pragmas.)
Let's now see how each different conversion tools can fix this problem.
VB Migration Partner supports the DefaultMemberSupport pragma, which tells the code generation engine that references to Variant and Object variables should be wrapped in a helper method that determines the object’s default member and returns its value to callers:
Sub ShowDefaultMemberValue(ByVal var As Object)
Dim s As String = GetDefaultMember6(var)
The GetDefaultMember6 method (defined in VB Migration Partner's support library) returns the value of the Text property for a TextBox control, the value of the Checked property for a CheckBox or OptionButton control, and so on. A similar helper method named SetDefaultMember6 is used to assign the default member of a given object that is accessed in late-bound mode.
The GetDefaultMember6 and SetDefaultMember6 methods clearly improve functional equivalence with the original VB6 code at the expense of reduced code readability and maintainability. In addition, these two methods can slightly affect runtime performance.
For these reasons, we recommend that you use the DefaultMemberSupport pragma only where one or more variables are known to contain a reference to a control or object. Conversely, if an Object variable is the result of the conversion of a VB6 Variant that can contain a scalar value, you should avoid the overhead – in both readability and performance – introduced by these methods.
Avoiding such an overhead is easy with VB Migration Partner, because its pragmas can be granularly scoped at the file or method level, and even at the single variable level. In previous example, you can leverage this granularity and associate the DefaultMemberSupport pragma only with the obj variable:
'## obj.DefaultMemberSupport True
When such a pragma is used, only references to the obj variable are wrapped in GetDefaultMember6 or SetDefaultMember6 methods. (One pragma affects all occurrences o a given variable, or all variables defined in a given method or file.) All other Object variables are unaffected by this specific pragmas.
Conversely, because of their project-wide conversion rules, when using a converter other VB Migration Partner you're forced to pollute your entire code base with one helper method call for each occurrence of an Object variable, even if that variable can only contain a scalar value. Such a massive presence of helper method calls can have a serious impact on overall performance, readability, and ease of maintance.
Not surprisingly, given these drawbacks, users of products other than VB Migration Partner often avoid enabling this and other project-level options, for example support for IsMissing keywod, conversion from On Error to Try/Catch, and improved support for late-bound calls.
This is a well-known problem that only VB Migration Partner's pragmas can solve in a simple and effective way.