Upgrading VB6 Projects to VB.NET
This article describes some of the many differences between VB6 and VB.NET. Much
of the current VB6 code base will not run under VB.NET due to changes in
VB.NET's syntax and language, its use of the new common runtime, and its
switch to WinForms from the VB6 form model.
Visual Basic.NET includes an upgrade tool to assist in converting VB6 projects
to .NET. The tool adds an upgrade report to your project listing any
problems and inserts comments into your code and To Do items into the
new Task List indicating where additional changes need to be made.
However, understanding the following changes can help simplify migrating your
existing VB6 code. For further information on this topic, visit Microsoft's web
site.
Beside the changes discussed here there are many new and fundamentally different
language features and programming concepts incorporated into the VB.NET
platform. The big ones include: Polymorphism, Inheritance
and Encapsulation (PIE), operation
overloading, parameterized constructors, class-level attributes and
operations.
To understand VB.Net you really need to learn more about these features. For
example, the Form Load and Class
Initialize events are replaced by the Sub New
procedure which is a constructor.
A good place to learn about these changes is my Object
Oriented Programming (OOP) article.
Passing Parameters
Parameters can be passed to a procedure in one of two ways. Either
by reference (ByRef) or by value (ByVal).
When you use the by reference method, changes made to parameters' values
in a sub procedure are known when control returns back to the calling
procedure.
ByRef is the default method of parameter passing in VB6 and prior versions when
the parameter's data type is an intrinsic one such as Integer, Long, Boolean,
String, etc.
Then second method is pass by value (ByVal). This
is the default for all non-intrinsic data types. When passed by value, the
calling procedure knows nothing about changes made to the parameter's value in
a sub procedure.
VB.NET passes all parameters ByVal. Thus, don't rely on the default
behavior and always explicitly specify ByVal or ByRef in your parameter lists.
Optional Parameters
VB allows you to define variant parameters to a
procedure as being optional and not required.
The code within a VB6 procedure then checks to see if the parameter contains a
value using the IsMissing keyword. For example:
Function fDouble (Optional A)
If IsMissing(A) Then
fDouble = Null
Else
fDouble = A * 2
End If
Since VB.NET does not support the IsMissing keyword, you should always use a
default value on your optional parameters:
Function fDouble (Optional A = 0)
Always declare variables on separate lines. I always thought this to be good
practice anyway.
Dim lngOne As Long
Dim lngTwo As Long
The above statement declares both variables as Long.
Dim lngOne, lngTwo As Long
This statement, however, declares lngOne as a Variant (which is not supported in
.NET) and lngTwo as a Long.
Since VB.NET uses a common runtime among Visual Studio languages, data types in
VB needed to be brought into line with those of other languages. Here are some
of the data type changes.
VB6
|
VB.NET
|
Comments
|
Integer
|
Short
|
16 bits
|
Long
|
Integer
|
32 bits
|
N/A
|
Long
|
64 bits
|
Variant
|
N/A
|
Use the new 'Object' data type
|
Currency
|
N/A
|
Use Decimal in VB6 or Decimal or Long in VB.NET
|
N/A
|
Decimal
|
Available* in VB6. Native in VB.NET
|
String
|
String
|
VB.NET doesn't support fixed length strings
|
VB.NET no longer supports the Variant and Currency data types. VB documentation
has always warned to minimize your use of variants. In .Net they are not
supported. Use the object data type instead.
The currency data type stores values as 64-bit
integers, scaled by 10,000 to give a fixed-point number with 15 digits to the
left of the decimal point and 4 digits to the right. In VB.NET you can replace
currency variables with the new 64-bit Long variable or the 64-bit
decimal data type.
In VB6, you can also use the decimal data type. Although you cannot
declare a variable as decimal, you can declare it as variant then use the
cDec function to make its subtype decimal.
Most APIs that take numeric arguments expect 32-bit values. In VB6 that's a
Long data type. In VB.NET a long is 64-bits and will not work with 32-bit API
calls. Your .NET API parameters will have to be changed or cast to the Integer
data type prior to invoking the API.
Many APIs will no longer be callable from VB and others will have replacements.
Some that pass strings will need tweaking to pass the correct string or Null
value. Check the VB.NET Help for more information.
APIs will need to be handled on a case by case basis. Your best bet is to
isolate all your API calls so changes only need to be made in a single location
in your code. The upgrade tool will attempt to convert API calls by creating
wrappers for them. However, manual intervention will be required.
VB.NET no longer supports the VarPtr, ObjPtr and
StrPtr functions which retrieved the underlying memory address of
variables. It also no longer supports the LSet command
which was used to convert one user defined type to another.
Some defunct keywords are: GoSub, Let, Is Missing, DefBool,
DefByte, DefLng, DefCur, DefSng, DefDbl, DefDec, DefDate, DefStr, DefObj and
DefVar as well as On x Goto.
Here are more affected commands:
VB6
|
VB.NET Namespace
|
Method/Property
|
Circle
|
System.Drawing.Graphics
|
DrawEllipse
|
Line
|
System.Drawing.Graphics
|
DrawLine
|
Atn
|
System.Math
|
Atan
|
Sgn
|
System.Math
|
Sign
|
Sqr
|
System.Math
|
Sqrt
|
Lset
|
System.String
|
PadRight
|
Rset
|
System.String
|
PadLeft
|
Rnd
|
Microsoft.VisualBasic.Compatibility.VB6
|
Rnd
|
Round
|
Microsoft.VisualBasic.Compatibility.VB6
|
Round
|
DoEvents
|
System.Winform.Application
|
DoEvents
|
VarType
|
System.Object
|
GetType (returns an object of class Type, which has
properties to get information.
|
The Set command is no longer supported. That means
Set objObject = objAnotherObject
becomes:
objObject = objAnotherObject
The Debug command changes from.
Debug.Print
to:
Debug.Write
Debug.WriteLine
New Commands and Keywords
|
VB.NET introduces many new keywords with no counterpart in VB6. Many of these
are a result of the added object oriented features.
Keyword
|
Purpose
|
Example
|
Inherits
|
Points to a base class to use for inheritance
|
Inherits System.Winforms.Form
|
MyBase
|
Refernces the base calss for use in the subclass' code
|
StringProperty = MyBase.StringProperty
|
Shared
|
All instances of a class should share a variable in a
class
|
Public Shared Baselocation As String
|
Try
Catch
Finally
Throw
|
New error handling. "Try" starts the code with error
handling enabled. "Catch" indicates the code to use to process an error.
"Finally" indicates the code to run regardless. "Throw" is used to raise an
error.
|
Try
rs.Update
Catch
Log("Error")
Finally
rs.MoveNext
End Try
|
ReadOnly
|
Used in a property that contains only a "Get"
|
Public ReadOnly Property StrProperty() As String
|
WriteOnly
|
Used in a property that contains only a "Set"
|
Public WriteOnly Property StrProperty() As String
|
Char
|
New character datatype
|
Dim chrInitial As Char
|
Imports
|
Makes an object hierarchy (namespace) available in a
module
|
Imports System.WinForms
|
Namespace
|
Specifies a namespace for a module
|
NameSpace MyAppName
|
Webmethod
|
Tags a method as part of a publically available Web
Service
|
Public Function <Webmethod()>
MyMethod(sIn As String) As String
|
Overloads
|
Indicates there's more than one version of a function
and the compiler can distinguish among them by the input parameters
|
'Both of these in same module:
Overloads Sub Print(s As String)
Overloads Sub Print(l As long)
|
Overrides
|
Indicates a member overrides the identically named
member in the base class
|
Inherits MyBaseClass
Overrides Function X() As String
|
Overridable
|
A member is allowed to be overridden in any class
derived from the base class
|
Overridable Function X() As String
|
MustOverride
|
Indicates that any class that derives from this class
must supply an override for this member.
|
MustOverride Function X() As String
|
Protected
|
This member is only available to classes derived from
this class
|
Protected Sub Clear()
|
In VB6 declaring an array
Dim Items(5) As String
gives you 6 items from index 0 to index 5. In VB.NET, this same declaration will
yield 5 elements from index 0 through index 4. Be on the look out for "out of
bounds" type errors. Also, all arrays in .NET must now be zero-based.
VB6 allows you to reference the default property of a control or object without
specifying the name of the property. VB.NET disallows this.
txtMyText = "Hello"
rst!("name") = "Dave"
rst!name = "Dave"
The above statements must be replaced with:
txtMyText.text = "Hello"
rst!("name").value = "Dave"
rst!name.value = "Dave"
References to Form Controls
|
Controls on a form are no longer public in VB.NET. Thus, form2 cannot reference
form1.text1.text. What you now need to do is add public Let
and Get property procedures to the form for each
control property you want to reference from another form. By the way,
Let is no longer supported, read on for more info.
You can also declare the control you want to reference as Public
Shared but that is not the recommended approach.
VB.NET has added new features such as Control Anchoring
which lets a form automatically resize controls as a user resizes the form.
Also, Control Docking lets controls be docked to
any side of a form.
As a result of these changes much of your form's resize code may not be
needed.
VB Integrated Development Environment
|
The VB Integrated Development Environment (IDE) is
now fully integrated with the Visual Studio.NET IDE. Thus VB.NET has a new language-neutral
extensibility model. VB.NET add-ins are now VS.NET add-ins. While this
lets you create a VB.NET add-in that changes a Visual C# form, your existing
add-ins need to change to reflect the new extensibility model.
VB.NET is geared towards ADO. All bound controls
will work only with ADO. Although DAO and RDO will still work, with some minor
changes, you cannot bind DAO or RDO recordsets to controls.
Let and Get Property Procedures
|
The syntax for Let and Get
user defined property procedures has changed. Instead of being two separate
property procedures, the logic for both Let and Get are combined into a single
procedure. For example:
Property Get MyProperty() As Integer
m_MyProperty = MyProperty
End Property
Property Let MyProperty(NewValue As Integer)
m_MyProperty = NewValue
End Property
Becomes
Property MyProperty() As Short
Get
m_MyProperty = MyProperty
End Get
Set
m_MyProperty = Value
End Set
End Property
Windows Forms (WinForms) replace the VB6 forms.
Winforms have many new and improved features such as in place menu
editing and better Graphical Display Interface (GDI+) support resulting
in better graphics handling.
You can now use transparency, layering, alpha blending, gradient effects, etc.
for fancier looking forms (see my Irregular Form samples for explanations of
these terms).
However, along with this comes a similar but different form object model. Here
are some differences from VB6 forms:
-
Winforms do not support the OLE Container, shape or line controls.
-
Winforms use new Circle, CLS, PSet, Line and Point graphic commands.
-
Winforms do not support Dynamic Data Exchange (DDE) or the form.PrintForm
method.
-
Winforms and controls do not expose a .Name property at runtime. You cannot
enumerate the controls collection looking for a control with a given name.
-
Winforms use a different menu system, drag and drop and clipboard object model.
-
Setting a timer control's interval to 0 does not disable the timer.
Visual Inheritance
Means an organization can define a standard base form containing items such as
a corporate logo and a common toolbar. This form can be used by developers
through inheritance and extended to meet the requirements of specific
applications while promoting a common user interface across the organization.
The creator of the base form can specify which elements can be extended and
which must be used as is, ensuring that the form is reused appropriately.
When upgrading a VB6 project to VB.NET the upgrade tool attempts to convert
references to old, obsolete or missing object properties and methods to the new
ones. For example,
Dim o As Object
Set o = Me.Label1
o.Label1 = "Name:"
o.Label1.Caption = "Name:"
Both statements set Label1's caption to "Name:" in VB6. In VB.NET the .caption
property is now the .text property. Since the object was declared using late
binding the upgrade tool doesn't know what type of object "o" refers
and cannot update the code.
If early binding was used as show below, the tool would successfully
convert your code to use the new .text property.
Dim o As Label
Set o = Me.Label1
o.Label1.Caption = "Name:"
Boolean and Logical Operations
|
Logical versus BitWise Operations
The Not, And and Or operators
work differently in VB.NET. In VB6 and earlier, these functions performed
either logical or Bitwise
operations depending on the context they were used in. If all their operands
were of type boolean they performed logical operations. Otherwise they
performed bitwise operations.
Now they will only perform logical operations. VB.NET introduces the
BitAnd, BitOr, BitNot and BitXor keywords
to perform bitwise operations.
If your existing VB6 code uses the logical operators on non-boolean values
either you will get incorrect results or your code will convert to use the
slower VB6.And, VB6.Or and VB6.Not
compatibility functions.
Short Circuit Logic
New to VB.NET is short circuit logic. Short
circuit logic only evaluates multiple conditions in a logical statement if
necessary. Consider:
Dim b As Boolean
b = Function1() And Function2()
Under VB6 both functions are evaluated. Under VB.NET if function1 is false,
function2 is not evaluated since "b" cannot be True. While this is more
efficient it can cause problems. If a side effect of evaluating function2 is
the setting of a global variable, that variable will no longer get set. This
will produce the desired effect:
Dim b As Boolean
Dim c As Boolean
Dim d As Boolean
c = Function1()
d = Function2()
b = c AndAlso d
Use Constants Instead of Underlying Values
|
You are safer using named constants in your code rather than the underlying
value. VB6 constants will convert to the correct value when upgraded to VB.NET.
But if you use the actual value, you may end up with an incorrect value hard
coded in your program.
The best example is that of the constant True which
has a value of -1 in VB6. VB.NET, however, uses a
value of 1 to mean True.
Code written is VB6 is synchronous. Each line of code must be executed before
the next one is processed. With .NET you can spawn a thread to perform a
long-running task, execute a complex query, or run a multipart calculation
while the rest of the application continues, providing asynchronous processing.
Sub CreateThread(
Dim b As BackGroundTask
Dim t As Thread
Set b = New BackGroundTask()
Set t = New Thread(New ThreadStart(AddressOf bTask))
End Sub
Class BackGroundTask
Sub Task
. . .
End Sub
End Class
|