
 |
Download these IBM resources today!
e-Kit: IBM Rational Systems Development Solution
With systems teams under so much pressure to develop products faster, reduce production costs, and react to changing business needs quickly, communication and collaboration seem to get lost. Now, theres a way to improve product quality and communication.
Webcast: Asset Reuse Strategies for Success--Innovate Don't Duplicate!
Searching for, identifying, updating, using and deploying software assets can be a difficult challenge.
eKit: Rational Build Forge Express
Access valuable resources to help you increase staff productivity, compress development cycles and deliver better software, fast.
Download: IBM Data Studio v1.1
Effectively design, develop, deploy and manage your data, databases, and database applications throughout the data management life.
eKit: Rational Asset Manager
Learn how to do more with your reusable assets, learn how Rational Asset Manager tracks and audits your assets in order to utilize them for reuse.
|
|
 |
|
  |
|
|
|
|

The Book of VB .NET: Migrating to Visual Basic .NET, Part 1
By Matthew MacDonald
Go to page: 1 2 Next
Excerpted with permission from The Book of VB .NET, by Matthew MacDonald, No Starch Press, Copyright 2002.
A traditional computer book usually discusses migration-the
question of how to work with existing data files-early on. In many
programs, including office productivity software such as Microsoft
Word, working with files from a previous version is just as easy as creating
new documents. Unfortunately, Visual Basic .NET doesn't work this
way. As you've discovered in the preceding thirteen chapters of The Book of VB .NET, Visual Basic .NET introduces an entirely new programming framework called .NET. To program
well in .NET, you have to surrender many time-honored habits and adopt a new,
object-oriented style. When it comes to migration, the question is not how you
can import your existing applications, but whether you should at all.
This article surveys the major changes between Visual Basic 6 and
VB .NET, and in doing so, provides a nice summary of the .NET philosophy.
We'll take a look at t he Upgrade Wizard, and see how a sample VB 6 project
weathers the transition to .NET. You'll also learn about how to integrate legacy
code, which is useful when migration is simply too painful. Specifically, we'll
examine how you can access COM components and ActiveX controls-the "old
world" of programming-in a .NET project. These techniques allow you to make
maximum use of your existing code, while pursuing new development in
Visual Basic .NET. Integration and interaction may not always be convenient,
but it will be an essential ingredient of .NET programming for the next few
years. It will also be the best strategy in many cases where migration is not possible
and re-coding is just too time-consuming.
Introducing .NET Migration
Visual Basic .NET compromises backward compatibility in a number of troublesome
ways. Hopefully, the advances you've seen over the course of this book will
make these complications worthwhile. Once you're in the .NET world, there's
really no easy way back.
Visual Basic 6 in the .NET World
Visual Basic 6 is a mature, well-developed programming environment. There's
no immediate need to replace a VB 6 program (and there's no shame in maintaining
a program in Visual Basic 6). Think of Visual Basic 6 as a well-worn, austere
language at the end of its evolution. It still has a nice autumn glow to it, but
it will gradually fade into disuse. On the other hand, Visual Basic .NET is a
young, dynamic upstart at the beginning of its life cycle. As with any new program,
changes will abound in VB .NET over the next few years. However, it's
Visual Basic .NET, not Visual Basic 6, that will power the next generation of VB
applications.
A key theme in this article is breaking down the barriers between VB 6
and VB .NET. There may not be an easy migration solution for many of your
projects. Instead, you may need to start over again in .NET, and make heavy use
of the COM compatibility layer that is built into .NET, in order to use your existing
VB components.
File Compatibility
There is no file compatibility between Visual Basic .NET and earlier versions. In
Chapter 3 of The Book of VB .NET, we explored the new file formats used in VB .NET projects. These
files have different extensions (.vb instead of .mod or .frm, and .vbproj instead
of .vbp). VB .NET files also use a block structure that allows modules, forms,
and classes to be combined in a single file, while Visual Basic 6 used a special
syntax for its form files (as explained in Chapter 4 of The Book of VB .NET).
The syntax of the language of itself has been updated, and the alterations
range from minor cosmetic changes to entirely new concepts such as namespaces.
All these technical details have a single result: There is no way to open a
Visual Basic 6 project in VB .NET. Instead, you have to migrate the project.
The Upgrade Wizard
Migration is a special procedure carried out by Visual Studio .NET's built- in
Upgrade Wizard. Essentially, the Upgrade Wizard scans through every line of
every file in your project. It examines the line, analyzes it for a variety of potential
problems, and tries to assign an equivalent VB .NET statement. When dealing
with simple programs (for example, utilities that have only one window, or
that have the majority of their capabilities concentrated in a few core procedures),
it does remarkably well. However, for complex programs that manage a
sophisticated user interface and a large amount of data, it works almost embarrassingly
badly. In these cases, migration usually isn't a feasible option.
Migrating a Simple Project
Here's a relatively simple VB 6 project using several concepts that are foreign to
VB .NET. The full project is available with the samples for this article.
It starts with a simple startup procedure, contained in a module file:
' VB 6 code.
Public Sub Main()
frmSplash.Show vbModal
frmMain.Show
End Sub
The first line launches a window modally-a splash screen with a company
logo. The window uses a timer that unloads itself automatically after a set
amount of time:
' VB 6 code.
Private Sub tmrClose_Timer()
Unload Me
End Sub
Then the code continues to the second line, launches the main program window
nonmodally, and allows the Main subroutine to end. The main window consists
of a simple form with an MSFlexGrid control and a single button. When the
user clicks on the button, a short routine runs, retrieves information from a database
table, and uses that information to fill the grid, as shown in Figure 14-1.

Figure 14-1: A VB 6 program
The code is quite straightforward. The Form_Load event handler configures
the grid appropriately, and opens a database connection (using the form-level
variable con):
' VB 6 code.
Private con As ADODB.Connection
Private Sub Form_Load()
grid.Cols = 2
grid.Rows = 0
grid.ColWidth(1) = 3000
grid.ColAlignment(0) = 1
Set con = New ADODB.Connection
con.ConnectionString = "Provider=SQLOLEDB.1;Data Source=localhost;" & _
"Initial Catalog=Northwind;Integrated Security=SSPI"
con.Open
End Sub
Of course, opening a database connection in the Form_Load event and
closing it in the Form_Unload event is an extremely bad design practice,
because it ties up a limited database connection for an undetermined amount of
time. The individual using the computer could easily forget, leave the computer
running, and go on holiday, tying up the connection indefinitely. However,
there's nothing invalid in this code (and probably nothing unusual either).
The button event handler contains the following code:
' VB 6 code.
Private Sub cmdFill_Click()
Me.MousePointer = vbHourglass
grid.Rows = 0
Dim rs As ADODB.Recordset
Set rs = con.Execute("SELECT * From Customers")
Dim i As Integer
Do While rs.EOF <> True
grid.AddItem (rs("CustomerID") & vbTab & rs("ContactName"))
rs.MoveNext
Loop
Me.MousePointer = vbDefault
End Sub
Don't spend too much time analyzing this code; it uses the ADO library,
which is the connection-based predecessor to ADO.NET. ADO works quite a bit
differently, using a live connection and a MoveNext method to access all the
information in a Recordset (instead of a Rows collection in a DataSet). This technique
is similar to the way you use ADO.NET's special DataReader object.
You might also notice that this code uses the MousePointer property to
thoughtfully turn the user's mouse pointer into an hourglass, indicating that a
database operation is underway and that no other user action can be taken until
the operation is finished.
One additional frill is the form's automatic resizing code:
' VB 6 code.
Private Sub Form_Resize()
grid.Width = Me.Width - 350
grid.Height = Me.Height - 1200
cmdFill.Top = Me.Height - 1000
cmdFill.Left = (Me.Width - cmdFill.Width - 60) \ 2
End Sub
While this code can't stop the form from being made too small, like our
VB .NET code can, it still manages to ensure that the button and grid use the
appropriate amount of space. The drawback is the introduction of hard-coded
values, and generally ugly code, into the Form_Resize event handler. Interestingly,
this code is the manual equivalent of two different VB .NET concepts we
take for granted. The grid's size changes, but its position does not; this is an
example of manual docking. The command button's position changes, but its
size is constant, which is an example of anchoring.
Clearly, this is an extremely simple program. However, it does have some
aspects that can pose difficulty in the .NET world. They are:
- The use of ADO, which is a database technology built on COM.
(Remember, COM isn't native to .NET.)
The use of the MSFlexGrid control, which is an ActiveX control. Like all
ActiveX controls, it's also based on COM, and so there is no direct
equivalent in the .NET class library.
The treatment of forms. In Visual Basic .NET, forms are classes, and you
have to create an instance of a form before using it. Clearly, the startup
routine in our example doesn't follow these rules. If you'd known that this
program was destined for VB .NET migration, you could have programmed
accordingly by dynamically creating forms, even in your VB 6 code.
However, if you haven't specifically planned for this step, or if you are
dealing with an older application, this technique probably hasn't been used.
Design-wise, there are a couple of other potential problems in this example,
such as the way the database connection is held open. However, you can create a
poorly designed program in VB .NET with the same ease that you could in
Visual Basic 6. This example of poor programming should not affect the migration
process.
Importing the Project
To import this project into Visual Basic .NET, all you need to do is open the
.vbp file. The Upgrade Wizard will automatically appear, as seen in Figure 14- 2.

Figure 14-2: The Upgrade Wizard
At this point, it's just a matter of clicking on Next several times, and the
conversion will begin. Along the way, you will be prompted to choose a new
directory where the .NET version of our project will be stored (see Figure 14- 3).

Figure 14-3: Creating the new .NET project
Remember, this a complex migration, not a simple File Open operation.
The whole process is surprisingly slow, as you'll notice with any real-life application.
Even with this simple program, Visual Studio .NET may still take a couple
of minutes to complete the migration.
Once the process is completed, the first thing you should do is read the
migration report that has been created for you. You can find this as an HTML
file (_UpdateReport.htm) in the Solution Explorer. If you double- click on it,
you'll see an impressive file-by-file analysis of the project (Figure 14- 4). Each
section lists migration problems and warnings, and can be expanded or collapsed
individually.

Figure 14-4: The upgrade report
In the case of the simple ADOTest project, no errors are reported, but
three warnings are flagged. You can read a full description of these issues by
clicking the provided hyperlink, which takes you to a help topic. Usually, though,
you'll want to investigate the code yourself. The appropriate area will be marked
with a comment and another hyperlink to the help topic:
' UPGRADE_WARNING: Form event frmMain.Unload has a new behavior.
' Click for more: ms-help://MS.MSDNVS/vbcon/html/vbup2065.htm
Private Sub frmMain_Closed(ByVal eventSender As System.Object, _
ByVal eventArgs As System.EventArgs) Handles MyBase.Closed
con.Close()
End Sub
In this case, the Wizard has changed the event handler for the Unload event
to the corresponding Close event. (The Wizard has also taken care of additional
details, such as adding the Handles clause and changing the event handler signature
to the .NET standard.)
The second warning is a similar false alarm that alerts us that the Resize
event may occur when the form is first initialized. The third warning in the
migration report informs us, rather cryptically, that the application will end
when the Main subroutine ends. This warning highlights another difference
between VB .NET and VB 6: In Visual Basic 6, a program wouldn't end until
every window was closed. If you used a startup routine to begin your program,
the startup routine could end and leave the other windows running to take care
of the rest of the program. In VB .NET, applications work a little differently.
If you use a startup subroutine in Visual Basic .NET, the program will close
as soon as the subroutine ends, even if other windows are still open (somewhat
like using the End statement).
Module StartupModule
Public Sub Main()
frmSplash.DefInstance.ShowDialog()
' Program will end immediately after executing the next line.
frmMain.DefInstance.Show()
End Sub
End Module
This migration problem could have been avoided if the original program
had displayed both windows modally from the Main subroutine. In that case, the
subroutine would pause until the frmMain window had closed, rather than ending
early. To fix this minor problem, all you need to do is make this modification:
Module StartupModule
Public Sub Main()
frmSplash.DefInstance.ShowDialog()
frmMain.DefInstance.ShowDialog()
End Sub
End Module
Forms and the Default Instance
You may notice another unusual feature in this portion of the code: the reference
to DefInstance. A logical .NET startup routine would look more like this:
Public Sub Main()
' Create and show first window.
Dim Splash As New frmSplash
Splash.ShowDialog()
' Create and show second window.
Dim Main As New frmMain
Main.ShowDialog()
End Sub
The .NET Upgrade Wizard doesn't have enough intelligence to make this
change. In fact, the problem is potentially a lot more complicated. In traditional
VB code, the Wizard really has no way of knowing when you are referring to a
form, and when you are trying to create it. In VB 6, a form is loaded automatically
the first time it is referred to in code, even if it isn't displayed. This system
allows the following kind of logic to work:
' This is VB6 code.
frmMain.TextBox1.Text = "Hi" ' The form is created and loaded automatically.
frmMain.Show ' Now the form is displayed.
To emulate this logic, the Upgrade Wizard adds a special block of code to
every form under the collapsed Upgrade Support region that works like this:
Private Shared m_vb6FormDefInstance As frmMain
Private Shared m_InitializingDefInstance As Boolean
Public Shared Property DefInstance() As frmMain
Get
If m_vb6FormDefInstance Is Nothing _
OrElse m_vb6FormDefInstance.IsDisposed Then
m_InitializingDefInstance = True
m_vb6FormDefInstance = New frmMain()
m_InitializingDefInstance = False
End If
DefInstance = m_vb6FormDefInstance
End Get
Set
m_vb6FormDefInstance = Value
End Set
End Property
The logic here is quite interesting. It works like this:
- Every form has a shared property called DefInstance. Because it is shared, it
can be accessed even without creating a form instance. (Also, because it is
shared, every class uses the same code for this property, and returns the
same result.)
- When you retrieve the DefInstance property in your code, the Property Get
procedure checks the form's private m_vb6FormDefInstance shared
variable. This variable is designed to hold a reference to the current form
(in our example, frmMain). If this variable hasn't yet been initialized, the
Property Get procedure creates the form automatically, effectively
mimicking the VB 6 form behavior.
- The end result is that whenever a part of your program uses the
DefInstance property, it gets the instance of the form stored in the
m_vb6FormDefInstance variable. If necessary, the form is loaded on the
spot automatically.
This special block of "upgrade support" code is a trick that allows you to
use forms in the VB 6 way, as long as you call the form's default instance instead
of just the form's class name. If you have the time, it may make sense to go
through your code, remove the default instance logic, and recreate your form
properly. However, this isn't strictly necessary.
TIP Incidentally, this code violates an important recommendation of object-oriented programming: namely, that retrieving information from a property procedure should never change the state of the object. In this case, retrieving the property of an
uninitialized form causes it to be created.
Go to page: 1 2 Next
Previous article: The Book of VB .NET: Web Services, Part 2
Next article: The Book of VB .NET: Migrating to Visual Basic .NET, Part 2
|