Virtual Developer Workshop: Containerized Development with Docker
Microsoft Visual Basic has had many evolutions since its original release, Visual Basic 1.0. The release of Visual Basic .NET is the biggest evolution yet. The language has been redesigned to take advantage of the .NET Framework. By leveraging the features that the .NET Framework provides, Visual Basic supports language features such as code inheritance, visual forms inheritance, and multi-threading. The object model is more extensive than earlier versions, and Visual Basic .NET totally integrates with the .NET Framework. Therefore, interaction between components written in other .NET languages is very efficient.
Advantages of Upgrading
Visual Basic .NET is the next version of Visual Basic. Rather than simply adding some new features to Visual Basic 6.0, Microsoft has reengineered the product to make it easier than ever before to write distributed applications such as Web and enterprise n-tier systems. Visual Basic .NET has two new forms packages (Windows Forms and Web Forms); a new version of ADO for accessing disconnected data sources; and streamlined language, removing legacy keywords, improving type safety, and exposing low-level constructs that advanced developers require.
Visual Basic .NET is now fully integrated with the other Microsoft Visual Studio .NET languages. Not only can you develop application components in different programming languages, your classes also can now inherit from classes written in other languages using cross-language inheritance. With the unified debugger, you can now debug multiple language applications, irrespective of whether they are running locally or on remote computers. Finally, whatever language you use, the Microsoft .NET Framework provides a rich set of APIs for Microsoft Windows® and the Internet.
There were two options to consider when designing Visual Basic .NET—retrofit the existing code base to run on top of the .NET Framework, or build from the ground up, taking full advantage of the platform. To deliver the features most requested by customers (for example, inheritance and threading), to provide full and uninhibited access to the platform, and to ensure that Visual Basic moves forward into the next generation of Web applications, the right decision was to build from the ground up on the new platform.
For example, many of the new features found in Windows Forms could have been added to the existing code base as new controls or more properties. However, this would have been at the cost of all the other great features inherent to Windows Forms, such as security and visual inheritance.
One of our major goals was to ensure Visual Basic code could fully interoperate with code written in other languages, such as Microsoft Visual C# or Microsoft Visual C++, and enable the Visual Basic developer to harness the power of the .NET Framework simply, without resorting to the programming workarounds traditionally required to make Windows APIs work. Visual Basic now has the same variable types, arrays, user-defined types, classes, and interfaces as Visual C++ and any other language that targets the Common Language Runtime; however, we had to remove some features, such as fixed-length strings and non-zero based arrays from the language.
Visual Basic is now a true object-oriented language; some unintuitive and inconsistent features such as GoSub/Return and DefInt have been removed from the language.
The result is a re-energized Visual Basic, which will continue to be the most productive tool for creating Windows-based applications, and is now positioned to be the best tool for creating the next-generation Web sites.
When we start developing any new software solution, certain steps are taken. We begin with a plan, identify processes, gather requirements, and eventually build the architecture of the solution. Once things start taking shape, we start with development. Why do we choose this path? We all know that the path for doing the analysis and design up front has been proven to save a lot of time and cost for software development. In order to migrate projects from any prior version of Visual Basic, the path for analysis and design up front yields the best results.
The analysis part is slightly different in this case. We begin by studying the current application, and try to identify code blocks that require changes. In order to migrate your VB applications, it is not recommended that you directly convert your existing applications to .NET and fix the converted code in .NET. It is always better to take the existing application to the "Migration Ready" stage.
Here are the steps for migrating applications:
- Evaluate the project and create a migration strategy.
- Make the changes in VB 6.0 project and create a "Migration Strategy."
- Migrate using the Visual Basic .NET Migration tool.
- If the changes are not at par, make more changes and use the Migration tool (repeat Steps 2 and 3 as necessary).
- Get developers at speed and make changes in .NET.
- Build the .NET solution.
Description of the Technique
If you upgrade a Visual Basic 6.0 project group or an n-tier application to Visual Basic .NET, you must upgrade one project or tier at a time.
If your three-tier application includes a client component, a business component, and a data access component, you should upgrade the application in the following order:
- Client component, Business component, Data access component
- Business component, Data access component
- Data access component
In an n-tier application, always upgrade the client tier first, and then upgrade other tiers on the dependency tree. You should follow this order for two reasons:
- This approach allows you to keep the application working. When you upgrade the client, you break and work with only one component of the application. All of the other components continue to work the same way that they did previously. With this approach, you isolate the work area. Alternately, if you upgrade the data tier first, suddenly you break the data tier and the components that depend on the data tier.
- Visual Basic 6.0 locks type libraries (TypeLibs). This creates a problem if you need to rebuild the TypeLib or recompile the underlying dynamic-link library (DLL). If you upgrade the business tier first and then upgrade the client, you must continually stop and restart Visual Basic 6.0 every time you change the middle tier. Consider the following workflow:
- Upgrade the middle tier. Change the Visual Basic 6.0 client to access the middle tier. Run the middle tier.
- Change the Visual Basic 6.0 client to access the middle tier. Run the middle tier.
- Run the middle tier.
If you want to change the .NET DLL, you must then close Visual Basic 6.0, recompile in .NET, restart Visual Basic 6.0, and so on. You can avoid this problem if you upgrade the client first and then upgrade the middle tier.
To upgrade each Visual Basic 6.0 application, use the Upgrade tool that is included with Visual Basic .NET. The Upgrade tool is started when you use Visual Basic .NET to open a Visual Basic 6.0 project. When you use the Upgrade tool, the Visual Basic 6.0 project is not changed, and a new Visual Basic .NET project is created. Before you upgrade a Visual Basic 6.0 project, it is best to prepare it for upgrade.
Do's And Don'ts
When your code is upgraded, Visual Basic .NET creates a new upgraded project and makes most of the required language and object changes for you. The following sections provide a few examples of how your code is upgraded.
Variant to Object
Previous versions of Visual Basic supported the Variant data type, which could be assigned to any primitive type (except fixed-length strings), Empty, Error, Nothing, and Null. In Visual Basic .NET, the functionality of the Variant and Object data types is combined into one new data type: Object. The Object data type can be assigned to primitive data types, Empty, Nothing, Null, and as a pointer to an object.
When your project is upgraded to Visual Basic .NET, all variables declared as Variant are changed to Object. Also, when code is inserted into the editor, the Variant keyword is replaced with Object.
Integer to Short
In Visual Basic .NET, the data type for 16-bit whole numbers is now Short, and the data type for 32-bit whole numbers is now Integer (Long is now 64 bits). When your project is upgraded, the variable types are changed:
Dim x As Integer dim y as Long
is upgraded to:
Dim x As Short dim y as Integer
Visual Basic .NET introduces a more intuitive syntax for properties, which groups Get and Set together. Your property statements are upgraded as shown in the following example:
Property Get MyProperty() As Integer MyProperty = m_MyProperty End Property Property Let MyProperty(NewValue As Integer) m_MyProperty = NewValue End Property
is upgraded to:
Property MyProperty() As Short Get MyProperty = m_MyProperty End Get Set m_MyProperty = Value End Set End Property
Visual Basic Forms to Windows Forms
Visual Basic .NET has a new forms package, Windows Forms, which has native support for accessibility and has an in-place menu editor. Your existing Visual Basic Forms are upgraded to Windows Forms.
Figure 2. Windows Forms in-place menu editor.
In previous versions of Visual Basic, interfaces for public classes were always hidden from the user. In Visual Basic .NET, they can be viewed and edited in the Code Editor. When your project is upgraded, you choose whether to have interface declarations automatically created for your public classes.
Upgrade Report and Comments
After your project is upgraded, an upgrade report is added to your project, itemizing any changes you will need to make to your upgraded code. Additionally, comments are added to your code to alert you to any potential problems. These comments show up automatically in the Visual Studio .NET Task List.
Figure 3. Upgrade comments are added to Visual Basic code as well as the Task List.
This section provides recommendations for how you should write code to minimize the changes you will need to make after upgrading your project to Visual Basic .NET.
Both Visual Basic 6.0 and Visual Basic .NET support late-bound objects, which is the practice of declaring a variable as the Object data type and assigning it to an instance of a class at run time. However, during the upgrade process, late-bound objects can introduce problems when resolving default properties, or in cases where the underlying object model has changed and properties, methods, and events need to be converted. For example, suppose you have a Form called Form1 with a label called Label1; the following Visual Basic 6.0 code would set the caption of the label to "SomeText":
Dim o As Object Set o = Me.Label1 o.Caption = "SomeText"
In Visual Basic .NET Windows Forms, the Caption property of a label control is now called Text. When your code is upgraded, all instances of the Caption property are changed to Text, but because a late-bound object is type-less, Visual Basic cannot detect what type of object it is, or if any properties should be translated. In such cases, you will need to change the code yourself after upgrading. If you rewrite the code using early-bound objects, it will be upgraded automatically:
Dim o As Label Set o = Me.Label1 o.Caption = "SomeText"
Where possible, you should declare variables of the appropriate object type rather than simply declaring them as the Object data type.
In the cases where you do use Object and Variant variables in your Visual Basic 6.0 code, we recommend you use explicit conversions when you assign the variables, perform operations on the variables, or pass the variables to a function. For example, the intention of the "+" operation in the following code is unclear:
Dim Var1 As Variant Dim Var2 As Variant Dim Var3 As Variant Var1 = "3" Var2 = 4 Var3 = Var1 + Var2 'UNCLEAR: What is the intention?
Should Var1 and Var2 be added as strings or integers?
The above example may result in a run-time error in Visual Basic .NET. Rewriting the final line to use explicit conversions ensures the code will work:
Var3 = CInt(Var1) + CInt(Var2) 'GOOD: explicit conversion
Visual Basic .NET supports overloading functions based on parameter type. For example, the Environ function now has two forms:
Environ( Expression As Integer) As String Environ( Expression As String ) As String
Visual Basic .NET determines which function to call based on the parameter type. If you pass an integer to Environ(), the integer version is called; if you pass a string, the string version is called. Code that passes a Variant or Object data type to an overloaded function may cause a compile or runtime error. Using an explicit conversion, as in the following example, will mean your code will work as intended after it is upgraded to Visual Basic .NET:
Dim a As String Dim v As Variant v = "Path" a = Environ(CStr(v)) 'GOOD: explicit conversion
Using explicit conversions of late-bound objects is good coding practice. It makes the intention of the code easy to determine, and makes it easier for you to move your project to Visual Basic .NET.
Use Date for Storing Dates
Earlier versions of Visual Basic supported using the Double data type to store and manipulate dates. You should not do this in Visual Basic .NET because dates are not internally stored as doubles. For example, the following is valid in Visual Basic 6.0, but may cause a compile error in Visual Basic .NET:
Dim dbl As Double Dim dat As Date dat = Now dbl = dat 'VB.NET: Double can't be assigned to 'a date dbl = DateAdd("d", 1, dbl) 'VB.NET: Can't use Double in date 'functions dat = CDate(dbl) 'VB.NET: CDate can't convert double 'to date
The .NET framework provides the ToOADate and FromOADate functions to convert between doubles and dates. However, when your project is upgraded to Visual Basic .NET, it is difficult to determine the intention of code that uses doubles to store dates. To avoid unnecessary modifications to your code in Visual Basic .NET, always use the Date data type to store dates.
Resolve Parameterless Default Properties
In Visual Basic 6.0, many objects expose default properties that can be omitted as a programming shortcut. For example, Textbox has a default property of Text, so instead of writing:
you use the shortcut:
The default property is resolved when the code is compiled. In addition, you also could use default properties with late-bound objects, as in the following example:
Dim obj As Object Set obj = Form1.Text1 MsgBox obj
In the late-bound example, the default property is resolved at run time, and the MsgBox displays the value of the default property of the Textbox as Text1.
Visual Basic .NET does not support parameterless default properties, and consequently does not allow this programming shortcut. When your project is upgraded, Visual Basic .NET resolves the parameterless default properties, but late-bound usages that rely on run-time resolution cannot be automatically resolved. In these cases, you will have to change the code yourself. An additional complication is that many libraries implement default properties using a property called _Default. _Default acts as a proxy, passing calls to the real default property. So, when your project is upgraded, some default properties will be resolved to _Default. The code will still work as usual, but it will be less understandable than code written explicitly using the actual property. For these reasons, try to avoid using parameter less default properties in your Visual Basic 6.0 code. Instead of writing:
Dim obj As Object Set obj = Me.Text1 MsgBox obj 'Relying on default property MsgBox Me.Text1 'Relying on default property
Dim obj As Object Set obj = Me.Text1 MsgBox obj.Text 'GOOD: Default property is resolved MsgBox Me.Text1.Text 'GOOD: Default property is resolved
While parameterless default properties are not supported in Visual Basic .NET, default properties with parameters are supported. To understand the difference between the two types, consider that parametered default properties always have an index. An example is the default property of ADO recordset: the Fields collection. The code:
Dim rs As ADODB.Recordset rs("CompanyName") = "SomeCompany" rs!CompanyName = "SomeCompany"
is actually a shortcut for:
Dim rs As ADODB.Recordset rs.Fields("CompanyName").Value = "SomeCompany" rs.Fields!CompanyName.Value = "SomeCompany"
In this case, the Fields property is parametered, and so the usage is valid in Visual Basic .NET; however, the default property of the Fields property, Value, is parameterless, so the correct usage in Visual Basic .NET is:
Dim rs As ADODB.Recordset rs("CompanyName").Value = "SomeCompany" rs!CompanyName.Value = "SomeCompany"
This example and most other default properties are resolved for you when the project is upgraded, so resolving them in Visual Basic 6.0 is simply a good programming practice. However, you should avoid using default properties with the Object and Variant datatypes; these cannot be resolved and you will have to fix the code yourself in the upgraded project.
Avoid Null Propagation
Previous versions of Visual Basic supported Null propagation. Null propagation supports the premise that when null is used in an expression, the result of the expression will itself be Null. In each case in the following example, the result of V is always Null.
Dim V V = 1 + Null V = Null + Right$("SomeText", 1) V = Right("SomeText", 0)
Null propagation is not supported in Visual Basic .NET. The statement 1+Null will generate a type mismatch in Visual Basic .NET. Additionally, where Visual Basic 6.0 had two versions of the Left function—Left$ returning a string, Left returning a variant which could be Null—Visual Basic .NET only has one version, Left, which always returns a string.
In order to be compatible with both Visual Basic 6.0 and Visual Basic .NET, you should always write code to test for Null instead of relying on Null propagation. Furthermore, in Visual Basic .NET, the following functions will no longer return Null:
Null propagation is commonly used in database applications, where you need to check whether a database field contains Null. In these cases, you should check results by using the function IsNull() and performing the appropriate action.
A related issue involves concatenating a string with a Null value. When programming with database objects, it is common practice to concatenate an "empty string" to a field to ensure that Null values are coerced to an empty string. For example:
MyString = rs!Field1 & ""
This technique is still supported in Visual Basic .NET. When a Null value is concatenated with an empty string (using the & operator), the result is an empty string.
Use Zero Bound Arrays
Visual Basic 6.0 allowed you to define arrays with lower and upper bounds of any whole number. You could also use ReDim to reassign a variant as an array. To enable interoperability with other languages, arrays in Visual Basic .NET must have a lower bound of zero, and ReDim cannot be used unless the variable was previously declared with Dim As Array. Although this restricts the way arrays can be defined, it does allow you to pass arrays between Visual Basic .NET and any other .NET language. The following example shows the restriction:
Dim a(1 To 10) As Integer 'LBound must be 0 in VB.NET Dim v ReDim v(10) 'Can't use ReDim without Dim in VB.NET Dim b(10) As Integer 'GOOD: Creates an array of 11 integers ReDim b(5) As Integer 'GOOD: Can ReDim previously Dimed var
A side effect is that Option Base 0|1 is removed from the language.
When your project is upgraded to Visual Basic .NET, any option base statements are removed from your code. If the array is zero bound, it is left unchanged. However, if an array is non-zero bound, the lower bound is removed and a warning is inserted into the code, as in the following example:
Dim a(1 To 10) As Integer
'UPGRADE_WARNING: Lower Bound of array a was changed from 1 to 0 Dim a(10) As Integer
In many cases, the upgraded code will work as it did before. However, if your application logic relies on the lower bound being 1, you will need to make some modifications. Dim, ReDim, and LBound statements are marked with warnings to help you review the changes.
For this reason, you should use zero bound arrays in your Visual Basic 6.0 code, avoid using ReDim as an array declaration, and avoid using Option Base 1.
Use Constants Instead of Underlying Values
When writing code, try to use constants rather than relying on their underlying values. For example, if you are maximizing a form at run time, use:
Me.WindowState = vbMaximized 'Good: Constant name used
Me.WindowStyle = 2 'Avoid using underlying value Me.WindowStyle = X 'Avoid using variables
Likewise, use True and False instead of -1 and 0.
In Visual Basic .NET, the values and in some cases the names of some properties and constants have changed. When your project is upgraded to Visual Basic .NET, most constants are changed automatically for you; however, if you use underlying values or variables instead of the constant names, many cases cannot be upgraded automatically. Using constant names minimizes the number of modifications you have to do.
Arrays and Fixed-Length Strings in User-Defined Types
Due to changes made that allow Visual Basic .NET arrays and structures to be fully compatible with other Visual Studio .NET languages, fixed-length strings are no longer supported in the language. In most cases this is not a problem, because there is a compatibility class which provides fixed-length string behavior, so the code:
Dim MyFixedLengthString As String * 100
upgrades to the following:
Dim MyFixedLengthString As New VB6.FixedLengthString(100)
However, fixed-length strings do cause a problem when used in structures (also known as user-defined types). The problem arises because the fixed-length string class is not automatically created when the user-defined type is created. An additional problem is that fixed-size arrays are not created, either, when the user-defined type is created.
When your code is upgraded, user-defined types with fixed-length strings or arrays will be marked with a comment telling you to initialize the fixed-length string or array before using the user-defined type. However, you can shield yourself from this modification by changing your Visual Basic 6.0 user-defined types to use strings instead of fixed-length strings, and uninitialized arrays instead of fixed-size arrays. For example:
Private Type MyType MyArray(5) As Integer MyFixedString As String * 100 End Type Sub Bar() Dim MyVariable As MyType End Sub
can be changed to:
Private Type MyType MyArray() As Integer MyFixedString As String End Type Sub Bar() Dim MyVariable As MyType ReDim MyVariable.MyArray(5) As Integer MyVariable.MyFixedString = String$(100, " ") End Sub
Avoid Legacy Features
Because they have been removed from the language, you should avoid using the following keywords:
- Computed GoTo/GoSub
- Option Base 0|1
- VarPtr, ObjPtr, StrPtr
These are explained in more detail below.
In previous versions of Visual Basic, DefBool, DefByte, DefInt, DefLng, DefCur, DefSng, DefDbl, DefDec, DefDate, DefStr, DefObj and DefVar were used in the declarations section of a module to define a range of variables as a certain type. For example:
defined all variables beginning with the letter A, B, or C as an integer. Instead of using Def
Computed GoTo/GoSub statements take this form:
On x GoTo 100, 200, 300
These are not supported in Visual Basic .NET. Instead, you should use If statements, and Select Case constructs.
GoSub and Return statements are not supported in Visual Basic .NET. In most cases, you can replace these with functions and procedures.
Option Base 0|1
Option Base 0|1 was used to specify the default lower bound of an array. As mentioned previously, this statement has been removed from the language because Visual Basic .NET natively only supports arrays with a zero lower bound. Non-zero lower bound arrays are supported through a wrapper class.
VarPtr, ObjPtr, StrPtr
VarPtr, VarPrtArray, VarPtrStringArray, ObjPtr, and StrPtr were undocumented functions used to get the underlying memory address of variables. These functions are not supported in Visual Basic .NET.
In Visual Basic 6.0, the LSet statement could be used to assign a variable of one user-defined type to another variable of a different user-defined type. This functionality is not supported in Visual Basic .NET.
Many APIs can be used exactly as they were in Visual Basic 6.0, with the caveat that you have to adjust your data types accordingly. The Visual Basic 6.0 Long datatype is now the Visual Basic .NET Integer datatype, and the Visual Basic 6.0 Integer datatype is now the Visual Basic .NET Short datatype. During the upgrade, these changes are made for you, and simple APIs work exactly the same as they did in Visual Basic 6.0. For example:
Private Declare Function GetVersion Lib "kernel32" () As Long Function GetVer() Dim Ver As Long Ver = GetVersion() MsgBox ("System Version is " & Ver) End Function
Private Declare Function GetVersion Lib "kernel32" () As Integer Function GetVer() Dim Ver As Integer Ver = GetVersion() MsgBox("System Version is " & Ver) End Function
In addition to numeric datatype upgrades, Visual Basic 6.0 had a fixed-length string data type that is not supported in Visual Basic .NET, and that is upgraded to a fixed-length string wrapper class. In many cases in Visual Basic 6.0, you can perform the same action using a normal string. For example:
Private Declare Function GetUserName Lib "advapi32.dll" Alias _ "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Long) As Long Function GetUser() Dim Ret As Long Dim UserName As String Dim Buffer As String * 25 Ret = GetUserName(Buffer, 25) UserName = Left$(Buffer, InStr(Buffer, Chr(0)) - 1) MsgBox (UserName) End Function
can be better written using a normal string explicitly set to length 25 instead of a fixed-length string:
Dim Buffer As String Buffer = String$(25, " ")
This is upgraded to Visual Basic .NET as follows:
Declare Function GetUserName Lib "advapi32.dll" Alias _ "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Integer) As Integer Function GetUser() Dim Ret As Integer Dim UserName As String Dim Buffer As String Buffer = New String(CChar(" "), 25) Ret = GetUserName(Buffer, 25) UserName = Left(Buffer, InStr(Buffer, Chr(0)) - 1) MsgBox(UserName) End Function
In some cases, Visual Basic .NET better handles passing strings to APIs because you can optionally declare how you want strings to be passed using the ANSI and UNICODE keywords.
There are three cases where you may need to make some changes. The first is passing user-defined types that contain fixed-length strings or byte arrays to APIs. In Visual Basic .NET, you may need to change your code, adding the MarshallAs attribute (from System.Runtime.InteropServices) to each fixed-length string or byte array in the user-defined type. The second case is using the As Any variable type in a Declare statement. This is not supported in Visual Basic .NET. Variables of the As Any type were often used to pass a variable that was either a string or Null; you can replace this Visual Basic 6.0 usage by declaring two forms of the API, one with longs, one with strings. For example, the GetPrivateProfileString API has a parameter lpKeyName of type As Any:
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
You can remove the As Any by replacing the Declare with two versions: one that accepts a long, and one that accepts a string:
Private Declare Function GetPrivateProfileStringKey Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long Private Declare Function GetPrivateProfileStringNullKey Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Long, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
When you wish to pass the value Null to the API, you use the GetPrivateProfileStringNullKey version. Doing it this way means that the function upgrades to Visual Basic .NET.
The final area where you may need to make some changes is if you are using APIs that perform thread creation, Windows subclassing, message queue hooking, and so on. Some of these functions will cause a run-time error in Visual Basic .NET. Many of these APIs have equivalents in Visual Basic .NET or the .NET Framework. You will have to fix these on a case-by-case basis.
Considerations for Forms and Controls
Visual Basic .NET has a new forms package, Windows Forms. Windows Forms is largely compatible with the forms package found in Visual Basic 6; however, there are some key differences that are outlined below:
- Windows Forms does not support the OLE container control; you should avoid using this control in your Visual Basic 6.0 applications.
- There is no shape control in Windows Forms. Square and rectangular shapes will be upgraded to labels; ovals and circles cannot be upgraded. You should avoid using these in your applications.
- There is no line control in Windows Forms. Horizontal and vertical lines are upgraded to labels. Diagonal lines are not upgraded, and you should avoid using them.
- Windows Forms has a new set of graphics commands that replace the Form methods Circle, CLS, PSet, Line, and Point. Because the new object model is quite different from Visual Basic 6.0, these methods cannot be upgraded.
- For the Timer control, setting the Interval property to 0 does not disable the timer; instead, the interval is reset to 1. In your Visual Basic 6.0 projects, you should set Enabled to False instead of setting the Interval to 0.
- Windows Forms has two menu controls, MainMenu and ContextMenu, whereas Visual Basic 6.0 has one menu control, Menu, which can be opened as a MainMenu or a ContextMenu. Menu controls are upgraded to MainMenu controls, but you will not be able to use them as ContextMenus; you will have to re-create your ContextMenus.
- Windows Forms has no support for Dynamic Data Exchange (DDE).
- Windows Forms does not support the Form.PrintForm method.
- Although Windows Forms has support for drag-and-drop functionality, the object model is quite different from Visual Basic 6.0. Therefore, the Visual Basic 6.0 drag-and-drop properties and methods cannot be upgraded.
- The .NET framework has an improved Clipboard object (System.Windows.Clipboard) that offers more functionality and supports more clipboard formats than the Visual Basic 6.0 Clipboard object. However, because of differences between object models, clipboard statements cannot be automatically upgraded.
- To ensure your forms are upgraded to the right size, you should always use the default ScaleMode of twips in your applications. During the upgrade, Visual Basic .NET transforms your forms coordinates from twips to pixels.
- Windows Forms only supports true-type and open-type fonts. If your application uses other fonts, these fonts will be changed to the system's default font, and all formatting (size, bold, italic, underline) will be lost. This applies to the default VB6 font MS Sans Serif(MS recommend you use Arial instead of MS Sans Serif).