Migrating From VB6 to VB.NET
If you are used to programming with Visual Basic 6.0, then Visual Basic .NET is unlike anything you’ve used before. Fortunately, says Huw Collingbourne, the changes are mostly for the better.
Originally published on DNJ Online, Jan 2005
In theory, Microsoft’s Visual Basic .NET should provide an easy path for experienced VB programmers to migrate to the .NET Framework. However, not all VB programmers have been enthusiastic about making the move. VB.NET is so different from Visual Basic 6.0 that even an experienced VB programmer will need to make an effort to learn to use it to effectively.
If this sounds a daunting prospect, the good news is that not only is the syntax of VB.NET broadly compatible with earlier versions, but the language itself is more powerful and elegant than ever before. There is no question of VB.NET being a ‘poor relation’ to other .NET language – it takes full advantage of the .NET Framework and it is, in essence, just as powerful as other .NET languages such as C#.
The language itself been tidied up a good deal with the removal of certain unnecessary keywords and constructs – Let, DefInt and GoSub, for example, have all gone. More significantly, it has been transformed into a rigorously Object Orientated Programming (OOP) language. In VB6, objects could be regarded as optional extras. With .NET, by contrast, objects are fundamental. Even variables of basic types such as integers are treated as objects. For example, the integer object has its own ToString() function (or ‘method’ as it is called in OOP terminology). This means that you can convert an integer variable named i to a string like this:
VB.NET’s implementation of object orientation is much more complete than formerly. In VB6 it was not possible to create family trees of objects in which descendents inherit the features of their ancestors. This omission has been rectified in VB.NET to bring it in line with pure OOP languages such as C# and Java.
The class library of .NET is huge. It contains many thousands of special-purpose classes from which objects can be created in your own programs. To help make sense of this, related classes are gathered together into named groups known as ‘namespaces’. The .NET namespaces not only categorise classes but also impose a high level of modularity.
In order to use a class that is defined within a namespace, you must provide a fully qualified path which contains the namespace followed by a full stop, followed by the class name. Some namespaces contain other namespaces. For example, the System namespace contains the Collections namespace, the Drawings namespace, the IO namespace and several more. As a result, your code can become cluttered with lengthy fully qualified class names. To prevent this, and to prevent ambiguities where classes in different namespaces share the same class name, you can specifically define the namespaces you want to use with the ‘imports’ statement.
Import statements appear near the top of a code unit, and are often amongst the first lines of a program. For example, the following statement allows you to reference classes from the System.IO namespace:
This namespace includes a number of useful IO classes such as File and StreamReader. The File class has methods such as Exists() to test whether a specified file can be found, while the StreamReader can be used to save and load data.
For example, assuming that FILE_NAME is a string to which the name of a file is assigned, the following code will either fill a RichEditBox with the text read from the file or, if the file is not found, it will display an error message in the Form’s Caption (Me.Text).
However, if you hadn’t imported the System.IO namespace the code would not compile as the compiler would not be able to resolve the references to the StreamReader and the File classes:
If Not File.Exists(FILE_NAME) Then Me.Text = FILE_NAME + " does not exist." Return End If Dim sr As StreamReader = File.OpenText(FILE_NAME) Dim input As String input = sr.ReadLine() While Not input Is Nothing RichTextBox1.AppendText(input) input = sr.ReadLine() End While
Improved error handling
VB.NET also benefits from object orientated exception handling. Exceptions are returned as objects which can be examined to determine the precise nature of the error. Moreover, each exception has its own string Message property. This string can be used to display information on the error.
If you think that a block of code is liable to produce an exception then you can enclose it between the try and catch keywords. If an exception occurs after the try keyword, the code following catch executes, which allows you to recover from the error. You can have multiple catch clauses to handle different specific types of exception. Optionally, a finally clause can also be added to perform any necessary cleanup operations irrespective of whether or not an exception occurs.
For example, when writing data to disk, the finally clause may need to close the file or stream whether or not the writing operation has generated an error. This is an example of an exception handling block:
Try While True Strings.Add(Stream.ReadLine()) End While Catch IOExcep As System.IO.IOException MsgBox(IOExcep.Message) Strings = Nothing Finally Stream.Close() End Try
Looked at dispassionately, there can be no doubt that this mechanism is superior to the error handling available in previous releases of VB. Nevertheless, if you really don’t like it, you can still use the familiar old ‘On Error GoTo’ statements.
It is not all good news, though. One useful feature of VB6 is no longer available in VB.NET; namely on-the-fly debugging. In VB6, when you hit a breakpoint you are able to edit the source code and then continue running your program without shutting it down and rebuilding it first. Microsoft has promised that this edit-and-continue capability will be added to the next release of VB.NET.
From COM to .NET
If you haven’t yet used .NET, you may be unclear about what exactly it is and why you might need it. Perhaps you’ve read that .NET is a replacement for the Component Object Model (COM) which allows separately compiled programs written in one or more programming languages to work together. Maybe you’ve heard that .NET is fundamentally an object orientated class library which replaces the old Microsoft Foundation Classes (MFC).
In fact, .NET is both of these things and a great deal more besides. The .NET Framework is a huge collection of code units and runtime tools for developing language-independent Windows applications and Web applications. It can even be used to write programs for handheld devices and PDAs running a compact version of the .NET Framework called (unsurprisingly) the .NET Compact Framework. For the time being, VB programmers have the choice of developing Windows applications using either VB6 or VB.NET. However, Microsoft’s future strategy is firmly based upon .NET.
Up to now, if you wanted to create an application comprising code written in two or more different programming languages, you would have needed to use COM. Many VB programmers do this regularly without even realising it. The controls installed in your VB6 toolbox may, in fact, have been written in other languages such as C++. Yet, when you drop those controls onto a form, you can use them from within your own program just as though they had been written in VB. That is thanks to COM.
In the world of COM, separately compiled files (such as DLLs) and controls (OCX files) communicate with one another using a set of predefined ‘interfaces’. In other words, all COM objects agree to work to a specific set of rules which dictate the entrance and exit points through which compiled files are able to communicate.
While this works very well, it has a number of disadvantages. For one thing, programming COM objects can be quite error prone. Moreover, in order to be able to interoperate with other programs, each COM component has to be registered in the Windows Registry. It is all too easy to register multiple and subtly incompatible versions of the same component, which can result in some very obscure bugs.
Assemble and configure
The .NET framework offers a neater alternative to COM. Each application is composed of multiple files which, in addition to an executable file, may also contain controls, DLLs and graphic images. These are grouped together as an ‘assembly’. All the files grouped within an assembly share a common version number. Applications can use their own ‘private’ separately compiled files without any reference to the Windows Registry.
In cases where multiple applications need to use the same compiled file, this file is placed into a shared directory. References to shared files can be maintained in an XML (eXtended Markup Language) configuration or ‘config’ file, which is stored in your application’s directory. If your application uses a specific version of an installed component it may continue to use that specific version, even if a newer version of the component is subsequently installed. The version to be used by your application can be specified in the application’s config file.
Of course, if it needs to use a new version of the component it can, but only if you specifically tell it to do so by editing its config file. No longer will your applications accidentally use incompatible versions of controls due to a mistake hidden deep inside the Windows Registry.
Config files can be used to store all kinds of other information about an application too. For example, if you want to save and restore the precise appearance of a form between sessions, you can simply write data into a config file when the application ends. That data will then be read back in and the form reconfigured, when the application is next run. Furthermore, the .NET Framework provides XML classes to simplify the writing and reading of configuration data in the form of named ‘keys’ and ‘values’.
For example, let’s suppose you want to store the screen location of a form and the last user’s name. The screen location is given by the Top and Left properties of the form. These can be saved as keys called, for example, ‘formtop’ and ‘formleft’. Let’s assume that the user’s name has been entered into a text box. This might be saved with a key called ‘username’. When these keys and values are written to disk, this is how they will appear in the config file:
<configuration> <appSettings> <add key="username" value="Donald Duck" /> <add key="formtop" value="526" /> <add key="formleft" value="640" /> </appSettings> </configuration>
When your application is next run, you can arrange for this data to be automatically read from disk so the Form can be re-positioned at the coordinates given by ‘formtop’ and ‘formleft’, and the string ‘Donald Duck’ can be placed back into a text box.
Mixed language programming
For teams of developers, VB.NET has the major advantage of integrating easily with code written in other languages. All .NET languages share the same class library and runtime environment, so it is quite easy to create a project with some modules written in VB and others written in other .NET languages such as C# or J#.
Creating multi-language programs in .NET could hardly be easier. Let’s say, for instance, that you are developing a program in VB.NET and you want to use some code which another programmer has written in C#. First you import the C# code into your project by making a couple of menu selections. Now you can create VB objects based on the C# classes which you’ve imported. Having done this, you can use the methods of these classes just as though they had been written in VB.NET. It would be equally easy for a C# programmer to import and use code written in VB.NET.
It is also simple to develop, debug and share drag-and-drop controls. Using a Visual Studio .NET wizard, you can design and code controls in much the same way that you would design and code a standalone application. These controls can be installed into the Visual Studio Toolbox. When you want to add a property to a control you enter the ‘property’ keyword into its source code. The VS.NET editor automatically generates the necessary ‘get’ and ‘set’ accessors. Drop the control onto a form in the VS.NET design workspace and these properties will automatically appear in the control’s Properties panel.
Huw Collingbourne has written columns and tutorials on Delphi, Java, VB, C++, C# and several more obscure languages for a variety of computer magazines. He has also written the Rants and Raves opinion column monthly since March 1988, first in Computer Shopper and later for PC Plus. This column now continues online. In addition he is co-founder of SapphireSteel Software.