從VB 6到.NET-探討應用程式的升級問題
作者/蕭育杰
前言
1998年,Visual Basic 6.0發行。Visual Basic 6是Visual Basic .NET至今仍無法完全取代的版本。
2002年,Visual Basic .NET和.NET Framework發行。使用了新的核心和特性,所以很多Visual Basic的程式需要考慮到升級的問題。
2005年,微軟宣佈將不再支援非.NET版本的Visual Basic。
2012年,Visual Basic 2012於8月發行。
2005年,微軟宣佈將不會再對非.NET版本的Visual Basic進行支援。一些資深的Visual Basic使用者還遞交了希望微軟能夠繼續對Visual Basic進行技術支援的請願書。但微軟不願意改變他們的決定。Visual Basic 6的程式幾乎無法執行在Visual Basic .NET中,微軟在Visual Basic .NET新版的IDE中提供了「升級精靈」,但實際上無法執行徹底的轉換。因此開發人員不得不付出相當大的精力來升級程式碼。本文專注於轉換的過程中可能遇到的困難。
Visual Basic 6 與 Visual Basic .NET 比較
Visual Basic的語法和絕大部分語言都不同,可能會讓新的開發人員混淆。例如宣告「Dim a, b, c As Integer」,宣告了 c 為整數變數,但是a, b依然是 Variant型態。如果想宣告3個Integer,必須寫成Dim a As Integer, b As Integer, c As Integer;而直接寫Dim a,後面不寫型態,則自動變成Variant型態,此舉會耗用很大的系統資源。這個問題在Visual Basic .NET以後的版本已經解決,Dim a, b, c As Integer的型態都視為整數。還有一些特性,比如底線字元「_」支援一行代碼分多行寫,除了排版美觀,亦可減少許多開發人員在使用時,因不合規範而引發的錯誤。
Visual Basic(6.0及以前)沒有的特性:
- 繼承:雖然Visual Basic 5之後的版本提供簡化的class支援,但仍然無法滿足開發人員的需求。
- 支援多執行緒:雖然可以使用Windows API完成,不過穩定性及偵錯功能不佳。
- 異常處理:只支援"On Error Goto Label"語句。
- 對指標的支援有限。
- Visual Basic只支援8到32位元的整數,很多語言都有無限制的支援。
- Visual Basic不支援與其它程式語言共用程式碼。
Visual Basic .NET(VB 7.0)以後的版本皆支援上述特性。
因Visual Basic 6仍然保留了一些script語言的特性,例如: 第一次對未宣告型態的變數指定值時,Visual Basic 6會把這個值的型態視作該變數的型態。這種特性對程式的可維護性會有不良的影響,雖然對於初學者的入門學習有正面的幫助,使其更快完成簡單的程式撰寫,而不用考慮到要宣告為哪種型態,但也因此容易養成不良的程式撰寫習慣,所以Visual Basic .NET之後的版本已不保留這種特性。
Visual Basic .NET 的具體變革如下:
- 子程式(函式)的定義與呼叫。
- 陣列的初值設定並需要註明範圍。
- 函式在格式上的改變:不能直接使用Date函式、Time函式、部分數學函式部分及String函式。DatePart、DateAdd、DateDiff函式的第一個參數在定義上有所改變。
- 不再使用保留字Set。
- 以End While取代保留字Wend。
- 新增運運算元:+=、-=、/=、*=和&=。
Visual Basic 6 與 Visual Basic .NET的差異:
- 所有的子程式呼叫都要有括號
Visual Basic 6: MsgBox “Hello World”
Visual Basic .NET: MsgBox(“Hello World”)
- 必須使用ByVal或ByRef
Visual Basic 6: Sub PrintHelloWorld(Cnt As String)
Visual Basic .NET: Sub PrintHelloWorld (ByRef Cnt As String)
- 事件關聯
Visual Basic 6使用_的模式通過名稱與事件關聯。例: 將Click事件與CommandButton 命令相關聯:
Private Sub Command1_Click()
如果EventName改為一個與事件不匹配的名稱,此程式就被視為一個普通的子程式。
- Handles
Visual Basic .NET可不使用名稱關聯事件,而是透過Handles的方式關聯,例: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
End Sub
可改寫為
Private Sub ClickButton(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
End Sub
- 事件參數
在Visual Basic 6中,事件子程式中包含每個參數的名稱和型態;而在Visual Basic .NET中,參數被綁在EventArgs中。例,在Visual Basic 6中:
Private Sub Check1_ItemCheck(Item As Integer)
MsgBox “You checked item: “ & Item
End Sub
而在Visual Basic .NET中:
Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
MsgBox(“You checked item: “ & e.Index)
End Sub
- 陣列必須有0下限
在Visual Basic .NET中不能再宣告一個具有0下限的陣列。
Dim intArray(-5 To 5) As Integer不再合法,在Visual Basic .NET中宣告一個長度11的陣列需改為Dim intArray(10) As Integer。
註: Option Base 1也不能在Visual Basic .NET中使用
不支援固定長度的字串
Dim testStr As String * 32在Visual Basic .NET中不再合法,但可以宣告固定長度的字元,例: Dim testStr2(32) As Char
- 拿掉Variant型態
Visual Basic .NET拿掉Variant的資料型態,提供Object型態,但給值時需要強制轉型,例:
Dim testObj As Object
Dim testStr As String
testObj = "This is a string!"
testStr = CStr(testObj)
- 變數的可見度
在Visual Basic 6中,任何迴圈或If…Then中宣告的變數對於整個函式來說都是可見的,但在Visual Basic .NET中,卻會發生錯誤,並指出此變數尚未宣告,例:
Dim outerFlag As Boolean
outerFlag=False
If outerFlag = False Then
Dim InnerFlag As Long
End If
InnerFlag = 2
升級至.NET的處理
Visual Basic 6大部分項目不能100%的進行升級轉換。若想達到100%的升級,Visual Basic 6和Visual Basic .NET中的各個元素就都必須一一對應。但這種對應性是不存在的。官方文件說明此升級過程的轉換接近於95%,這代表Visual Basic .NET 升級精靈能夠升級應用程式的95%,而想正常執行應用程式,必須去修改應用程式的另外5%。這個數值並非是固定的,某些應用程式的升級會比其他應用程式來的容易,此外,開發人員的經驗也是一個重要的因素。
建議分三個步驟來進行升級:
一、使用升級精靈將應用程式升級到Visual Basic .NET。
二、留意EWI(Errors, Warnings, and Issues)視窗帶來的訊息並逐項解決
三、將無法解決的問題改寫或重新設計
升級精靈會處理下列的Visual Basic語言特性,但建議不要在應用程式中繼續使用:
- DefInt, DefStr, DefObj, DefDbl, DefLng, DefBool, DefCur, DefSng, DefDec, DefByte, DefDate, DefVar
- GoTo [行號]
- Imp, Eqv
下列的特性不能再繼續使用,而且升級精靈會把它們留下來讓開發人員處理:
- GoSub…Return
- LSet(用於使用者自定義的型態)
- VarPtr, ObjPtr, StrPtr
- Null, Empty和非0下限陣列
Visual Basic 2005 (v8.0) 亦不再支援下列的 Visual Basic 6.0 功能。如需詳細資訊,請參閱
<備妥要升級的 Visual Basic 6.0 應用程式>。
9個常見的升級問題
一、Default Properties
CLR(Common language runtime)不再支援default property,如果升級精靈可以確認一個default property,它會自動轉換程式碼,如果無法確認其property,精靈會將程式碼保留,並插入一個警告。
二、Add Item and ToString with COM Objects
Visual Basic .NET中涉及到為ComboBox或ListBox Windows表單控制項的Add方法的參數為物件,而不是字串
三、Deterministic Finalization and Garbage Collection
在COM中,物件使用引用計數來追蹤有效引用的數目以確定其生存期,但Visual Basic .NET通過垃圾回收來進行記憶體管理。
四、Generic Objects (Control/Form/Screen)
generic objects是一種soft binding (註1)的形式。使用諸如ActiveForm或ActiveControl等return物件的方法並將這些型態當做更特定的型態使用時,就會出現問題。
五、Dim…As NeW
As New不再支援陣列的宣告。
六、Sub Main(or Default Form)
在Visual Basic 6中,只要有對話方塊或視窗打開,應用程式就保持活動狀態。在Visual Basic .NET中,應用程式生命週期的定義與Visual Basic 6中的定義截然不同。當啟動的物件結束時,應用程式也就結束了。
七、Font Disparities
在Visual Basic 6中可以使用兩種類型的字體:Raster和TrueType。TrueType字體可升級到Visual Basic .NET,但不再支援Raster字體。
八、Bad Constants
Visual Basic 6允許開發人員使用原本用於不同目的的列舉常數,但Visual Basic .NET更為嚴格,要求正確的列舉常數,因為列舉現在是實際的型態,不是幾個數字的集合。
九、Drag and Drop
Visual Basic 6支援兩種拖放操作。Visual Basic .NET中的拖放操作已統一到同一框架。控制項之間的拖放處理與應用程式之間的拖放處理方式完全相同。
8個需要重新設計的問題
隨著對升級應用程式的步驟,還有使應用程式在Visual Basic .NET中正常運行所需的修改也慢慢熟悉,不過有可能會發現到,在升級過程中有些問題只需要稍微修改即可解決,而有些問題則需要對出錯的地方重新編寫甚至對整個項目重新設計才能解決。
一、Replacing the OLE Container Control
OLE container control的用途是在運行時動態地將物件添加到表單中,但是Visual Basic .NET不支援OLE container control,我們可以ActiveX控制項Web Browser來作到同樣的效果。
二、Replacing Painting Functions
在Visual Basic .NET中圖形相關的函式:Line、Circle、Print、PaintPicture以及Cls已經從表單和PictureBox中被捨棄了。取而代之的是,Windows表單可以使用.NET GDI+物件程式庫,而這個程式庫提供了比以前更多的圖形函式
三、Rewriting Clipboard Code
Visual Basic 6中有一個Clipboard物件可以從Window剪貼簿複製文字和圖片。在Visual Basic .NET中,可以通過System.Windows.Forms.Clipboard命名空間來對剪貼簿進行操作。這些Clipboard相關的程式碼無法自動升級。
四、Using the Controls Collectionm
Visual Basic 6中控制項集合沒有IntelliSense(註2)的功能,所以開發人員必須記得要添加的控制項的方法、參數以及ProgID。而且控制項集合是不能進行自動升級的。
五、Using the Forms Collection
Forms collection不能被自動升級,只能重新建立。
六、Upgrading PrintFormCode
Visual Basic 6中使用Form.PrintForm來列印表單。但PrintForm並不完善,某些控制項不能正確列印,而且列印品質也不穩定。Visual Basic .NET沒有PrintForm的對映方法,因此升級精靈不能進行升級,必須使用PrintForm helper來取代。
七、Replacing Property Pages
Visual Basic .NET擁有一個可以編輯任何.NET 變數型態或class的property瀏覽器,也就是說不再需要property pages了
。
八、Eliminating ObjPtr, VarPtr, and StrPtr
這幾個函式很少使用而且可能造成嚴重的安全性問題,雖然無法自動轉換,但是在Visual Basci .NET中有一個方法可以實作同樣的功能。
結語
Visual Basic .NET提供了更多的功能和更高的靈活性,它所提供的資料、表單、事件等方面的物件模型更豐富。但要在.NET 環境中編譯和運行程式,就必須先進行升級,而本文粗略的介紹了升級轉換的步驟和常見的問題,但實際上還是要倚靠開發人員的經驗,進行多次的修改及測試才能將升級完成。
註1: Binding分為Early Binding、Late Binding及 Soft Binding三種。Early Binding指的是物件的行為並是在編譯時期(compileir-time)決定,而不是在程式執行時期(run-time)才動態地決定的。而Late Binding則相反。而Soft Binding則是指Visual Basic在一個強型別的變數上實作Late Binding的機制。
註2: IntelliSense是從Visual Studio .NET的新版IDE開始出現的功能,讓開發人員可以不用記憶保留字或變數的名稱,只要輸入前幾個字就可以得到對應清單,選取後自動填到程式碼當中,此功能明顯地增加開發人員的生產力。
參考資料
維基百科: Visual Basic
升級由舊版 Visual Basic 建立的應用程式
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET