Francesco's blog

 Friday, January 11, 2008

Many readers asked whether I was about to release a book about VB 2008 and, more in general, how come I have reduced my writing activity so dramatically. The answer is in this post.

Immediately after publishing my C# 2005 book I started working on a very ambitious software project. Now, after exactly two years of hard work, VB Migration Partner is in beta test stage and is quickly approaching the public release.

The name of this tool says it all: in a nutshell, it is a converter of VB6 applications to VB.NET. I won’t waste your time trying to emphasize how weak the Upgrade Wizard that comes with Visual Studio is: if you’ve never tried it out, just google for “vb6 migration” and read what developers and bloggers have to say about it. Our goal at Code Architects was to build a better mouse trap than that.

A word on the migration-vs-rewriting debate: Many industry experts suggest that you should rewrite your VB6 from scratch rather than trying to port it to .NET automatically using a conversion tool, because the two environments are just too different. In theory this argument makes a lot of sense; in practice, however, when you have a real-world business app with some hundreds thousands lines of code – or even millions of lines! – a rewrite from scratch is simply too expensive, especially when the developers who wrote it originally aren’t working with the company any longer, the documentation is poor, remarks are scarce, etc. When facing the perspective of investing many years/man in this daunting task, it’s no surprise that many companies have postponed the migration to “some other time.” Now they are realizing, however, that the migration step can’t be postponed any longer, either because a few VB6 apps don’t work under Microsoft Vista – possibly because they use 3rd-party controls that are incompatible with the new Microsoft operating system – or, above all, because Microsoft declared that VB6 support ends on March 2008.

The problem is, automatic code converters don’t have a good reputation and rarely keep their promises, regardless of the language you are migrating from/to. In most cases, they manage to convert 95% of existing code, or less. With a 100,000 line application – a medium-size application of average complexity, then – having to manually fix the remaining 5% means that you have to fix about five thousand lines. It doesn’t sound too bad, until you realize that most of these “fixes” might take hours or even days. For example, consider that VB6 and VB.NET have two vastly different (and incompatible) programming models for drag-and-drop. Therefore one OLEDrag method counts as an individual problematic statement, yet it forces you to rewrite a large portion of your code. Drag-and-drop isn’t the only example, because the same concept applies to graphic statements, printing, data-binding, object finalization, component initialization, and many others.

We tested our VB Migration Partner on hundreds of VB6 apps – for well over one million lines – and found out that it delivers code that compiles and runs correctly most of the times, with an average of one compilation error every 1,100 lines of code. This corresponds to an accuracy higher than 99.9%. Not bad, uh? Of course the actual accuracy depends on how well the VB6 code is and on the features that the application uses, thus you can get a better idea of how good our tool is by having a look at the VB6 features that itsupports ...and that are out of reach for most other conversion tool on the market:

  • arrays with nonzero LBound
  • Gosub, On...Goto, and On ...Gosub
  • auto-instancing variables (Dim x As New Person), which keep their lazy-instantiation feature even under VB.NET
  • As Any parameters and callback addresses in Declare parameters (e.g. EnumWindows)
  • default properties resolved correctly even for late-bound variables
  • deterministic finalization for objects such as Connection and Recordset, to ensure that the connection is correctly closed when the variable is set to Nothing or the current scope is exited
  • (limited) support for Variant variable and null propagation in expressions
  • all 60+ controls in the VB6 toolbox, with the only exceptions of OLE container and Repeater, plus the support for common ActiveX controls and components such as WebBrowser, ScriptControl, Scripting runtime, and the MSWLess library
  • control arrays, including arrays of 3-rd party controls
  • popup menus
  • the Controls.Add method and the VBControlExtender object, to dynamically create data-entry forms
  • graphic methods (Line, Circle, PSet, PaintPicture, etc.), with support for any ScaleMode, including custom user modes
  • the Printer object and the Printers collection
  • OLE drag-and-drop
  • UserControl classes, with support for advanced features such as the Ambient and Extender objects
  • data-binding to DAO, RDO, and ADO Data controls, ADO recordsets, DataEnvironment objects
  • non-hierarchical DataEnvironment objects
  • ADO data source and simple data consumer classes and user controls (e.g. custom ADO Data controls)
  • MultiUse, PublicNotCreatable, GlobalMultiUse classes
  • persistable classes, MTS/COM+ classes

The number of supported features is so high that it is simpler to list the features that are not supported: UserDocument, PropertyPage, WebClass and DHTML Page components; undocumented methods (VarPtr, ObjPtr, StrPtr); “classic” drag-and-drop, and little else.

VB Migration Partner can convert an entire VB6 project group in one operation, in which case it typically delivers better quality code because it can see “inside” a DLL that belongs to the group. The tool also includes a very sophisticated code analyzer that can spot unused members: a large project that has evolved over many years can easily include 5-10% of “dead code”, thus this feature alone can save you a lot of precious time because it allows you to focus on just the code that is really important.

One of the secrets for such high error-free conversion factor is the support for migration pragmas. A migration pragma is a special remark that you can add to the original VB6 code and that teaches VB Migration Partner how a given portion of code must be translated, if many alternatives exist. For example, the following ArrayBounds pragma tells VB Migration Partner that all the arrays in the current projects must have their lower bound index forced to zero:
          '##project:ArrayBounds ForceZero
Pragmas can have project, class, method, or variable scope. A pragma scoped at the variable- or method-level always have higher priority than pragmas scoped at the project- or class-level. For example, you can override the previous pragma inside a method, and then override this latter pragma for a given array variable:
          Sub Test()
             '## ArrayBounds Shift
             '## arr.ArrayBounds ForceZero
             '## names.ShiftIndexes 1
             Dim names(1 To 10) As String
             Dim values(1 To 10) As Long
             Dim arr(1 To 10) As Integer
             names(1) = "John": names(2) = "Ann"
             '...
          End Sub

The Shift option tells VB Migration Partner that the LBound and UBound indexes must be shifted towards zero, so that the total number of elements in the array is preserved. The ShiftIndexes pragma –applied only to the names array – ensures that constant indexes are correctly shifted too:
          Sub Test()
             Dim names(9) As String
             Dim values(9) As Integer
             Dim arr(0 To 10) As Short
             names(0) = "John": names(1) = "Ann"
          End Sub

VB Migration Partner supports over 50 pragmas. For example, the SetName pragma changes the name of a control or variable during the migration, SetType changes its type, AutoNew implements the auto-instancing behavior of As New variables, AutoDispose implements the deterministic finalization when the variable is set to Nothing or the current scope is exited, and so forth.

One of the main defects of a “traditional” conversion tool is that – after the first migration – there is no relationship between the original VB6 project and the new VB.NET project. If the migration process takes weeks or months – which is common for large projects – and if the VB6 application must evolve in the meantime with new features and bug fixing, then at the end of the migration process the VB.NET code is already outdated and must be manually patched. The margin for mistakes in this phase is very high.

VB Migration Partner allows you to work around this issue, by means of pragmas and what we call the convert-text-fix cycle methodology. In a nutshell, you can iteratively migrate a given VB6 project by reaching the zero compilation errors stage and then the zero runtime error stage by simply inserting pragmas in the original project, but without modifying any VB6 executable statement. Thanks to the convert-test-fix cycle you can face complex migration tasks and keep the VB6 and VB.NET versions of your app always in sync.

I am especially proud of VB Migration Partner’s refactoring engine, which is able to apply many optimization techniques the result of the “raw” conversion. For example, it can merge variable declarations and the initializations, to generate Return statements, and to leverage the compound assignment operators (e.g. +=), and more:

    Function GetValue() As Long     =>     Function GetValue() As Integer
       Dim x As Long                          Dim x As Integer = 123
       x = 123                                ...
       ...                                    If x > 0 Then
       If x > 0 Then                             Return x
          GetValue = x                        ElseIf x = 0 Then
          Exit Function                          Return -1
       ElseIf x = 0 Then                      End If
          GetValue = -1                       ...
          Exit Function                       x += 1
       End If                                 ...
       ...                                 End Function
       x = x + 1
       ...
    End Function

Other refactoring techniques can be achieved by means of pragmas. For example, you can move the declaration of a variable inside a For or For Each method, as in this example:

    Dim i As Integer                =>     For i As Integer = 1 To 100
    For i = 1 To 100                          ...
       ...                                 Next
    Next

On top of the cake: in spite of all these features, VB Migration Partner is up to 8 times faster than the Upgrade Wizard that comes with Visual Studio!

You can learn all about VB Migration Partner on our new site www.vbmigration.com. The web site hosts a Resource section where we dissect each and every difference between VB6 and VB.NET – most of which have never been documented anywhere – thus you can find many useful tips even if you don’t plan to use our tool. I also opened a new blog, entirely devoted to migration techniques.

That's it for now. Stay tuned!

 
Get RSS/Atom Feed
RSS 2.0 | Atom 1.0
Search in the blog
Archive
<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
Categories

Powered by: newtelligence dasBlog 1.8.5223.1