Index | Next 

1. Overview



1. Overview



VB Migration Partner - Main window

VB Migration Partner is a tool that converts VB6 applications to either VB.NET or C#. It matches or exceeds the features of the conversion and assessment tools included in Microsoft Visual Studio 2005 or 2008, available on Microsoft’s site, or provided by other vendors, and is aimed at both the developer and the team manager that needs to plan the migration process. Current version of VB Migration Partner generates projects for VS2005, VS2008 (when generating VB.NET code), and VB2010 applications (when generating VB.NET or C# code).

VB Migration Partner’s engine is so fast that VB6 developers can use it to see where the problematic code sections, have a draft version of the .NET application, and produce an estimation of the time required to complete the migration process, all in a fraction of the time needed to run the Upgrade Wizard tool included in Microsoft Visual Studio.

At the end of the migration process VB Migration Partner produces accurate reports about the problems it found together with metrics about the code being migrated. These reports include estimations of the time required to migrate the VB6 application and individual projects or classes. Reports also include sophisticated code metrics, such as total and average cyclomatic index, maximum and average depth of control structures, ratio of comments to code, in addition to a summary of all the migration issues found by the parser engine. The cost related to these metrics and issues (in terms of time and money) is fully configurable, and users can export metrics to Microsoft Excel for further analysis.

VB Migration Partner owes its high success ratio to its two main components: (a) a better parser and code generation engine, and (b) a support library that contains both the language support library and the control support library.

For example, VB Migration Partner’s parser is able to convert a VB6 project groups into a .NET solution; it can convert GoSub and On Goto/Gosub statements; Declare parameters declared with “As Any” or that stand for callback addresses; User Define Type (UDT) blocks that require initialization, auto-instancing variables and arrays, IDisposable objects, fixed-length strings, and much more.

For converted .NET applications to run correctly it is mandatory that the support library be distributed with the other executable files. While a few developers might dislike the approach based on the support library, it can be easily proved that only this approach can offer full compatibility with VB6 peculiarities and idiosyncrasies.

Code Architects plans to release more efficient and robust versions of the support library over time. When a new version of the support library is released, existing .NET applications that use the support library can be upgraded by simply deploying the new version on the end user’s computer, without having to re-run VB Migration Partner.




1.1 Feature summary

This section summarizes the main features of Code Architects’ VB Migration Partner, with emphasis on those that are unique to this product.


General

  • high-speed conversion
  • runs outside Visual Studio
  • pragmas and extenders can affect migration behavior and help produce better code
  • open architecture allows 3rd-party vendors to add support for their own ActiveX controls

Language

  • VB6 project groups are migrated to .NET solutions, project references are preserved
  • arrays with lower index other than zero
  • Gosub keyword, calculated On…Goto/Gosub
  • auto-instancing (As New) variables and arrays
  • “As Any” parameters and callback parameters (AddressOf) in Declare statements
  • most VB6 keywords not supported by VB.NET, including IsMissing, Array, DoEvents
  • methods in support library exactly replicate the original VB6 behavior (e.g. Format, Dir, MsgBox), so that less time has to be spent on reviewing warnings
  • full support for Type blocks (UDTs), fixed-length strings and arrays thereof
  • accessing default properties, even in late-bound mode
  • text and binary file I/O is 100% compatible with files generated by VB6, which allows to import existing files and exchange data with existing VB6 apps
  • partial support for Variants, including Empty, Null, and null propagation in string expressions
  • VB6 system objects, including Screen, Clipboard, App, and Printer

Forms and Controls

  • converts all controls installed with VB6 (with the exception of OLE container and Repeater control)
  • controls in support library exactly replicate the original VB6 behavior
  • control arrays, including arrays of menus and 3rd-party controls
  • dynamic control creation, both through control arrays and the Controls.Add method
  • popup menus and menu shortcuts
  • help-related properties and methods
  • graphic methods: Line, Circle, PSet, Cls, PaintPicture, PrintForm methods and all graphics-related properties (with the only exception of ClipControls)
  • any value for the ScaleMode property, including custom coordinate systems
  • “classic” (VB6-style) drag-and-drop
  • automatic and manual OLE drag-and-drop
  • full support for printing, including the Printer object, the Printers collection, and the Print and PageSetup common dialogs

COM Components

  • better support for IDisposable objects and finalization, including automatic disposal of fields and variables pointing to disposable objects
  • MTS/COM+ components, including support for most common objects in comsvcs.dll
  • private and public UserControl classes
  • persistable classes and the PropertyBag object
  • Sub Main is correctly called before any class in a DLL (as in VB6, unlike native .NE_T projects)
  • VB6 Description attribute translates to XML comments and (if inside a UserControl) to Description attributes
  • support for common type libraries such as FileSystemObject, Dictionary, and RegExp, without requiring COM Interop

Data Access

  • DAO and RDO data binding
  • ADO Data binding, including binding to ADO Recordsets and BindingCollection objects, with support for custom data formatting and StdDataFormat objects
  • DataEnvironment objects (excluding support for grouping and hierarchical recordsets)
  • ADO data-source classes and ADO simple data consumer classes
  • Effortless (optional) transformation of ADODB-based code into its ADO.NET equivalent code, by means of companion ADOLibrary. (Includes support for SQL Server keysets.)



1.2 The language support library

The language support library is entirely contained in the CodeArchitects.VBLibrary.DLL file and provides support for language commands that behave differently (or are missing) in the Microsoft.VisualBasic.dll file that comes with VB2005. All the objects and methods implemented in this support library have a trailing “6” appended to the original VB6 name, as in DoEvents6 or App6.

For example, this VB6 code fragment:

      If IsEmpty(value) Or IsNull(value) Then
        value = Array(1, 2, 3, 4, 5)
     End If
     

is translated to VB.NET as follows:

    
     If IsEmpty6(value) Or IsNull6(value) Then
        value = Array6(1, 2, 3, 4, 5)
     End If
     

NOTE: When converting to C#, static method in the VB6Helpers class are used instead:

        
        if (VB6Helpers.IsEmpty(value) || VB6Helpers.IsNull(value) )
        {
           value = VB6Helpers.Array(1, 2, 3, 4, 5);
        }

Methods that replace or extend members of the Microsoft.VisualBasic.dll library are exposed as members of the VB6Methods module, or other modules defined in the CodeArchitects.VBLibrary.dll.

These are the VB6 keywords that aren’t supported by VB.NET and that VB Migration Partner supports by means of the language support library:

  • Array6 creates an array of Object elements.
  • CVar6 returns an instance of the VB6Variant class.
  • CVErr6 returns an instance of the VB6Error class.
  • IsEmpty6, IsMissing6, IsNull6, and IsObject6 methods account for VB6Variant values.
  • LoadPicture6 supports all the arguments as the original VB6 method, but throws an exception if these extra arguments can’t be honored.
  • String6 works like StrDup, except it supports numeric values for its second argument.
  • SavePicture6 saves an image to BMP format.
  • VarType6 works correctly with scalar and array values stored in an Object element.

A few methods are supported by VB.NET but behave slightly differently from VB6, therefore VB Migration Partner re-implements them to ensure that no discrepancy exists:

  • Abs6 works with Boolean values, too.
  • AppActivate6 supports a second wait argument .
  • CDate6 accepts numeric values strings whose month and day values are reversed (locale-tolerant).
  • CreateObject6 works well also with public (managed) classes exposed by the current solution.
  • DebugPrint6 and DebugPrintLine6 display strings in the Debug window in the same format used by VB6.
  • Dir6 returns “.” and “..” elements and then returns names of files in a directory.
  • DoEvents6 returns the number of open forms.
  • FileDateTime6 works with both files and directories (the VB.NET method works only with files).
  • FileOpen6, FileClose6, FileGet6, FilePut6, and all other file-oriented method read and write values and UDTs using the same format that VB6 uses.
  • Format6 supports named formats (e.g. “scientific”) and null values, and accounts for minor differences between VB6 and VB.NET.
  • Input6 converts coordinates and correctly handles CRs in prompt strings.
  • IsDate6 accepts strings where month and day values are reversed.
  • Len6 works both with strings and User-Defined Types (UDTs).
  • LSet6 has support for strings and partial support for UDTs.
  • MsgBox6 correctly handles CRs in prompt.
  • RSet6 supports strings.
  • Str6 works with dates.
  • StrConv6 can convert Byte arrays to a string and works better with conversions to and from Unicode strings.
  • TypeName6 returns the value that would be returned under VB6; for example, when applied to an Int32 returns “Long”, when applied to a button control returns “Command”, and so forth.

The following keywords have been re-implemented to support extra features – for example, Variants and null propagation in expressions – that aren’t natively supported by .NET:

  • Chr6, CurDir6, Environ6, Hex6, LCase6, Left6, Mid6, Oct6, Right6, RTrim6, Space6, Trim6, and UCase6 account for null values.
  • IsArray6, IsDate6, IsError6, IsNothing6, and IsNumeric6 recognize values stored in Object and VB6Variant variables.
  • Erase6, Redim6, RedimPreserve6, IsArray6, LBound6, and UBound6 work with regular arrays, arrays stored in Object variables, and VB6Array objects.
  • Load6 and Unload6 perform additional processing that might be required in .NET applications converted from VB6.

The support library contains the counterpart of VB6 methods that can’t be implemented or mimicked perfectly under .NET. All the methods in this group are marked as Obsolete, thus they cause a warning message to be displayed in the Error List window. When invoked, these methods either do nothing or throw an exception:

  • ImeStatus6 and Calendar6 always return 0, assignments are ignored.
  • AscB6, ChrB6, InstrB6, LeftB6, RightB6, MidB6, InputB6, and LenB6 return an “approximate” value in .NET, and the warning message encourages the developer to edit the original or migrated code to get rid of such warnings.
  • VarPtr6, StrPtr6, and ObjPtr6 throw an exception.

VB6 system objects can be referenced by means of the following members:

  • App6: most members are supported, included PrevInstance and methods related to event logging; the OleRequest* and OleServer* properties aren’t supported and are marked as obsolete.
  • Clipboard6: all members are supported.
  • Screen6: all members are supported, except Fonts, FontCount, MousePointer, and MouseIcon are flagged as obsolete; assignments to MousePointer and MouseIcon throw an exception.
  • Printer6 and Printers6: all members are supported and behave exactly in VB6, except DrawMode, hDC, Zoom, Port, DeviceName.

In addition to methods and properties, the language DLL support most of the objects defined in the VB6 runtime. All the objects in this group have a trailing “VB6” prefix, as in “VB6Variant” and “VB6PropertyBag”.

  • VB6AsyncProperty simulates asynchronous properties in user controls.
  • VB6DataBinding and the VB6DataBindings collection correspond to the DataBinding and DataBindings objects defined in the VB6 runtime.
  • VB6DataEnvironment provides most of the functionality offered by the DataEnvironment object, except support for grouping, relations, and hierarchical recordsets.
  • VB6StdDataFormat and the VB6StdDataFormats collection provide support for custom formatting in data binding scenarios.
  • VB6DataObject and VB6DataObjectFiles are used in drag-and-drop scenarios to contain data moved from one control or application to another.
  • VB6Error is the object returned by the CVErr method.
  • VB6LicenseInfo and the VB6Licenses collection simulate license features of user controls.
  • VB6PropertyBag mimics the functionality of the VB6 PropertyBag object, even though the storage format differs from VB6’s (in other words, it isn’t possible to read VB6 serialized objects from .NET apps, and vice versa).
  • VB6Variant duplicates some of the functionality of the original VB6 Variant data type, such as support for Null and Empty values.

    NOTE: starting with version 1.52, the VB6Variant class is not officially supported.

  • VB6VBControlExtender is the alias for the VBControlExtender object used to trap events from controls that are added dynamically by means of the Controls.Add method.

A few objects have no direct counterpart in VB6:

  • VB6Array provides support for arrays with any lower index.
  • VB6ArrayNew provides support for arrays of auto-instancing objects (as in Dim arr() As New Person).
  • VB6ControlArray mimics VB6 control arrays and can contain both built-in controls and 3rd party controls.
  • VB6ControlCollection is the collection returned by the Controls property of forms and user control; unlike the .NET Controls collection, it contains controls all the controls hosted by the form or the user control, including those contained in container controls (e.g. a PictureBox or a Frame control).
  • VB6FixedString offer support for the translation of fixed-length strings (FLS).
  • VB6WindowSubclasser can be used to implement safer and more robust window subclassing.

Finally, the support library includes managed counterparts of the following COM objects:

  • VB6Binding and VB6BindingCollection duplicate the functionality of the Binding and BindingCollection objects in the MSBind type library.
  • VB6Dictionary is the alias for the keyed collection defined in the Scripting type library.
  • VB6FileSystemObjects and all related classes, such as VB6Drive and VB6File, mimic the behavior of file-related objects defined in the Scripting type library.
  • VB6ObjectContext is the .NET counterpart of the COMSVCSLib.ObjectContext used by MTS/COM+ components.
  • VB6RegExp and all related classes support the migration of VB6 apps that rely on the VBScript Regex Engine type library.



1.3 The control support library

Here is the complete list of the controls that VB Migration Partner supports:


Top-level objects:

Form MDIForm UserControl

Built-in controls:

CheckBox ComboBox CommandButton
Data DirListBox DriveListBox
FileListBox Frame HScrollBar
Image Label Line
ListBox Menu OptionButton
PictureBox Shape TextBox
Timer VScrollBar

Windows Common controls:

Animation DTPicker FlatScrollBar
ImageCombo ImageList ListView
MonthView ProgressBar Slider
StatusBar TabStrip Toolbar
TreeView UpDown

Window-less controls:

WLCheck WLCombo WLCommand
WLFrame WLHScroll WLList
WLOption WLText WLVScroll

Other controls:

ADO Data CommonDialog DataCombo
DataList MaskEdBox PictureClip
Remote Data RichTextBox SSTab
SysInfo WebBrowser

ActiveX Components (invisible at runtime):

INet MAPIMessage MAPISession
MSComm ScriptControl Winsocket

ActiveX Controls (visible at runtime):

MMControl MSCalendar (MSCAL.Calendar) MSChart
MSDataGrid MSHierarchicalFlexGrid

Notice that the list includes all the controls that are installed with Visual Basic 6, with the only exception of the OLE container control and the Repeater control.

In general, the name of all the classes in the control support library is formed by prefixing “VB6” to the name of the original VB6 control. For example, the VB6CommandButton control renders the VB6 CommandButton control, and so on.

In most cases, a class that replaces a VB6 control inherits from a Windows Forms control and adds or overrides members that behave exactly as they do under VB6. For example, the class that supports VB6’s TabStrip control inherits from System.Windows.Forms.TabControl. This approach ensures that the converted .NET application has no dependency from the original ActiveX control.

Only the controls that belong to the ActiveX Components and ActiveX Controls groups listed above are implemented as wrappers on the original ActiveX objects.

If the original VB6 application uses one or more controls listed in the ActiveX Components group, then the converted .NET project includes a reference to a TlbImp-generated DLL (for example MSCommLib for the MS Comm control). If the original VB6 application uses one or more controls listed in the ActiveX Controls group, then the converted .NET project includes a reference to the CodeArchitects.VBLibraryOCX.dll and CodeArchitects.AxVBLibraryOCX.dll libraries:

Here is a list of relevant features that VB Migration Partner supports:

  • Late binding
    The fact that members of the .NET control have the same name, return type, and syntax as the original VB6 control ensures that existing code accessing the control in late-bound mode continues to work after the migration to .NET.
  • Standard and popup menus
    Standard and popup menus are fully supported, including shortcut keys and control arrays of menu items.
  • Control arrays
    All control array features are supported, including dynamic loading and events. Support is provided by means the VB6ControlArray(Of T) type. Because of the generic nature of this type, VB Migration Partner supports arrays of any controls, including 3rd party controls. Arrays of menu items are supported as well.
  • Dynamic control creation
    In addition to loading a control by means of a control array, the CodeArchitects.VBLibrary DLL fully supports the Controls.Add method. The return value from this method can be assigned to a VBControlExtender variable, and .NET code can handle the ObjectEvent event exactly as the original VB6 code does.
  • Graphic methods
    Cls, Line, Circle, PaintPicture, PSet, Point, Print, Scale, TextWidth, and TextHeight methods are supported for the Form, PictureBox, and UserControl classes. All graphics-related properties are fully supported (including AutoRedraw and persistent graphic), except ClipControls. The DrawMode property is partially supported, whereas the PrintForm method is fully supported and provides useful options that are missing in the VB6 version.
  • Coordinate systems
    ScaleMode property can be set to values other than vbTwips, both at design-time and at run-time; ScaleLeft, ScaleTop, ScaleWidth, and ScaleHeight properties and Scale, ScaleX, and ScaleY methods are supported as well.
  • Data binding
    The control library supports binding with the Data, RDO Data, and ADODC controls, perfectly reproducing the VB6 behavior, including custom formatting by means of the StdDataFormat object and its Parse and Format events. VB Migration Partner supports also binding to ADO Recordsets, DataEnvironment objects, ADO data source classes, ADO simple data consumer classes, and BindingCollection objects.
  • Error codes
    When the support library throws an error, the error is raised by means of the Err.Raise method (rather than a Throw statement). Care has been taken in using exactly the same error codes that would be produced in VB6. This detail is essential to ensure that existing VB6 error handlers work correctly after the migration to .NET.
  • Enum properties
    All enumerated values have retained the value they have in VB6. This feature ensures that if an enum property is assigned a value returned by a Function or read from a configuration file, such a piece of code continues to work as expected after the migration to .NET. Spaces in enumerated values – as in [Test Value] – are replaced by underscores.
  • Help support
    All the help-related properties and methods are supported, including HelpContextID and WhatsThisHelpID. The converted .NET program can continue to use the help file provided with the original VB6 application.


1.4 Pragmas and the "convert-test-fix" cycle

Pragmas are special remarks that developers can add to the VB6 code to affect the behavior of the VB Migration Partner. The parser considers as a pragma any comment that starts with the “##” sequence; if the pragma name isn’t recognized, a warning appears in the Log Activity window.

Pragmas encourage the process we call convert-test-fix cycle. The convert-test-fix cycle is essential in converting large VB6 applications that need to be maintained or expanded until the migration process is completed and the .NET application is ready for the market. For large applications, in fact, the easiest way to ensure that the VB6 and .NET versions are always in-sync is doing as much work as possible on the original VB6 code and annotating it with pragmas. These pragmas tell VB Migration Partner how to migrate given pieces of code without producing errors.

A key feature of pragma is that they can be scoped at the project, class, method, and variable level. Project-level pragmas can appear anywhere in the VB6 source code and use the project: prefix. For example, the following pragma tells the code generator to use the Arial 10pt font for all the forms in the current project, unless another FormFont pragma at the form level overrides it:

        '## project:FormFont Arial, 10
    

Pragma arguments are separated by commas; if an argument is a string literal that contains commas, it must be enclosed in double quotes. If an argument contains a command and a double quote character (in a remark, for example), it must be enclosed in double quotes and all double quotes in the original value must be doubled, as you would do if it were a VB literal string.

There are a few of exceptions to the above rule, most notably the InsertStatement, ReplaceStatement, Rem, and Note pragmas. These pragmas take just one argument, which is an entire VB.NET statement, and never require that their only argument be enclosed in double quotes, because the comma can’t be misinterpreted as an argument separator.

A pragma can be applied to a specific member by prefixing its name with the member name, using the “dot” syntax. For example, the following VB6 code snippet applies the DeclareImplicitVariables pragma to the Test method (this pragma forces VB Migration Partner to generate a Dim statement for each variable that is implicitly declared):

        '## Test.DeclareImplicitVariables True
        …
        
        Sub Test()
            …
        End Sub 
    

You use the “dot” syntax to refer to specific variables, if the pragma can be applied to a variable. The following code tells the code generator to consider the frm variable as an auto-instancing variable (in this case VB Migration Partner generates code that preserves the As New semantics):

        '## frm.AutoNew True
        Dim frm As New Form1
    

If a pragma isn’t prefixed by project: or by a member name, its scope depends on where it appears in the VB6 code. The scoping rules are the same as in VB6: if the pragma appears at the class-, form-, or module-level - that is, it isn’t inside a method - it affects the entire form, module, or class and all its members; if the pragma appears inside a method, then it affects the current method and all its local variables:

        Sub Test()
            ' this pragma affects all local variables in Test method
            '## AutoNew True
            …
        End Sub
    

The effect of a pragma can be overridden by a pragma with a narrower scope. For example, you can use a project-level AutoNew pragma that affects all the fields and variables, except those that are affected by AutoNew pragmas at the class, method, or variable level. This hierarchical mechanism adds a lot of flexibility and lets developers precisely define the outcome from VB Migration Partner with few additions to the original VB6 code.

VB Migration Partner checks the syntax of all pragmas and doesn’t support pragmas with arbitrary names; however, we provide a one-size-fits-all pragma named SetTag, which developers can use to associate values to code entities. The SetTag pragma is especially useful with extensions.

You can easily insert new pragmas by means of a dialog box that explains what each pragma does and what each argument means, and that ensures that the syntax is correct.

In addition to processing pragmas in VB6 source code files, VB Migration Partner looks for the following files:

  1. A file named VBMigrationPartner.pragmas, in VB Migration Partner’s main directory. (This is known as the "master" pragma file.)
  2. A file named after the project’s file and with the .pragmas extensions - for example, Widgets.vbp.pragmas for the Widgets.vbp project.
  3. A file named VBMigrationPartner.pragmas, in the same directory as the project’s .vbp file. (This file is processed only if the search for previous file fails.)

Storing project-level pragmas inside these files is necessary or convenient in two cases. First, you can store project-level PreProcess, ImportTypeLib, and AddLibraryPath pragmas only inside these files. Second, this mechanism allows you to easily share pragma among different projects.

For example, you can ensure that all the form fonts in multiple projects are converted in the same way by creating a file named VBMigrationPartner.pragmas containing this text:

        '## FormFont Arial, 10

and then copying it to all the directories that contain the projects you plan to convert. Notice that the project: prefix is optional for pragmas stored in *.pragmas files.

Keep in mind that the “master” pragma file in VB Migration Partner’s main directory (step 1) is always processed, whereas the VBMigrationPartner.pragmas file in the VB6 project’s folder (steps 3) is processed only if the search at step 2 fails.  The order in which these files are processed ensures that the settings in files inside the project’s folder can override the settings specified in the “master” pragma file. For example, if both the “master” pragma file and the pragma file in the project’s folder contain an ImportTypeLib pragma that refers to the same type library, the setting specified in the latter file wins.

IMPORTANT: if you modify a *.pragma file related to a VB6 project that is currently loaded (but not migrated yet) inside VB Migration Partner’s editor, it is mandatory that you reload once again the VB6 project. This can be achieved by clicking on the Reload button (i.e. the second button from left, on the topmost toolbar).


 

Index | Next