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.
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.)
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”.
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.
Here is the complete list of the controls that VB Migration Partner supports:
Top-level objects:
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.
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:
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):
…
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):
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()
'## 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:
- A file named VBMigrationPartner.pragmas, in VB Migration Partner’s main directory. (This is known as the "master" pragma file.)
- A file named after the project’s file and with the .pragmas extensions - for example, Widgets.vbp.pragmas for the Widgets.vbp project.
- 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:
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).