Dale Oberg
ArtinSoft.com
适用于:
Microsoft Visual Studio 2005
Microsoft Visual Studio 2005 Tools for the Microsoft Office System
Microsoft Visual Basic .NET
Microsoft Visual Basic for Applications
Microsoft Office 2003 Editions
Microsoft Office Excel 2003
Microsoft Office Word 2003
摘要:向 Microsoft Visual Studio 2005 Tools for the Microsoft Office System 迁移时,将代码从 Visual Basic for Applications 转换为 Visual Basic .NET。本文档重点说明迁移原因、主要的代码转换问题,以及有关进一步详细信息的其他资源。
注 本文是预发布文档,所描述内容在将来的版本中有可能会更改。Microsoft Visual Studio 2005 Tools for the Microsoft Office System 的 Beta 版包含在 Microsoft Visual Studio 2005 的 Beta 版之中。
Visual Studio 2005 Tools for Office 简介 | |
为什么要迁移到 Visual Studio 2005 Tools for Office? | |
将 VBA 代码转换为 Visual Studio 2005 Tools for Office 中的 Visual Basic .NET 代码 | |
小结 | |
其他资源 | |
关于作者 |
Microsoft Visual Basic for Applications (VBA) 是已经使用多年的 Microsoft Office 应用程序的环境和语言。Microsoft Office 2003 Editions 包括一个用于构建应用程序的新环境,称为 Microsoft Visual Studio Tools for Office(Visual Studio Toolsfor Office),它基于 Microsoft .NET Framework。
与 VBA 相比,Microsoft Visual Studio Tools for the Microsoft Office System 2003 版具有更多优势,而 Microsoft Visual Studio 2005 Tools for the Microsoft Office System 增强了这些功能,从而提高用户的工作效率。
本文探究将 VBA 代码迁移到 Microsoft Visual Basic .NET 和 Visual Studio 2005 Tools for Office 时需要解决的各种编码问题。本系列的后续文章会重点介绍如何将全部项目从 VBA 迁移到 Visual Studio 2005 Tools for Office,还会讨论为了充分利用 Visual Studio 2005 Tools for Office 应该为 VBA 项目考虑的体系结构问题。
从 VBA 迁移到 Visual Studio 2005 Tools for Office 可以使您获得许多好处,例如:
提高了开发效率。从 VBA 迁移到 Visual Studio 2005 Tools for Office 的一个原因是可以访问 Visual Studio 2005 Tools for Office 和 Microsoft Visual Studio 2005 之间的集成开发环境。Visual Studio 是最丰富、最成熟的可用开发环境之一,它可以提高编码和测试的效率。
改进了安全模型。内置于公共语言运行库 (CLR) 中的安全模型有助于托管解决方案的实施。
可以更轻松地进行部署和版本控制。托管解决方案允许更灵活的部署选项,以及简化的部署和更新。
添加了来自 Microsoft .NET Framework 的功能。对 CLR 基类库的访问使您能够利用其新功能,例如 XML 读取器、ADO.NET 以及 Web 服务的简化使用。
提高了代码重用率。Visual Basic .NET 是一种完全面向对象的语言,有助于代码重用。
可以更轻松地进行集成。通过 Web 服务,.NET Framework 促进了与其他应用程序的集成。
下面列出了 VBA代码和 Visual Studio 2005 Tools for Office 中的 Visual Basic .NET 代码之间的部分差异。
数据类型
在 Visual Basic .NET 中,某些数据类型(如 Variant、Integer、Long、Currency 以及其他类型)已经更改或过时。例如,VBA 中的 Integer 等效于 Visual Basic .NET 中的 Short。另外,VBA 中的 Long 等效于 Visual Basic .NET 中的 Integer。
固定长度字符串
由于更改后允许 Visual Basic .NET 数组和结构(先前称为用户定义类型)完全兼容其他 Visual Studio 语言,因此固定长度字符串在该语言中不再受支持。如果固定长度字符串不需要确切长度,则可以将其转换为常规的 Visual Basic .NET String,如以下代码所示。
' VBAcode Dim MyFixedLengthString As String * 100 ' Visual Basic .NETcode Dim MyFixedLengthString As String
然而,如果固定长度字符串必须是特定的字节长度,则可以将其转换为字节数组,如以下代码所示。
' Visual Basic .NETcode Dim MyFixedLengthString(100) As Byte
文本值取代 Windows 常量
如果您使用文本值取代基于 Microsoft Windows 的已定义常量,则在向 Visual Studio 2005 Tools for Office 迁移时必须执行更多的工作。在使用文本值的情况下,您必须确定基于 Windows 的常量,然后再使用基于 Visual Studio 2005 Tools for Office 的等效常量。例如:
' VBAcode btnRecalculate.MousePointer = 10 ' This is the literal constant for vbUpArrow ' Visual Basic .NETcode btnRecalculate.Cursor = System.Windows.Forms.Cursors.UpArrow
枚举
在 Visual Basic .NET 中,您必须完全限定枚举常量。在转换 VBA 代码时,您必须将完全限定的枚举名称添加到枚举常量中。例如:
' VBAcode Application.ActiveDocument.Paragraphs(1).Alignment = wdAlignParagraphRight ' Visual Basic .NETcode ThisApplication.ActiveDocument.Paragraphs(1).Alignment = _ Word.WdParagraphAlignment.wdAlignParagraphRight
数组
在 Visual Basic .NET 和 VBA 中,数组维数的默认下限为 0。在 VBA 中,您可以使用 Option Base 将下限值更改为另一个数字,通常是 1。Visual Basic .NET 不支持 Option Base 语句。
对带有 Option Base 1 的数组进行迁移的一种方法是,将 1 添加到数组维数,并且目标代码在索引 0 处包含一个额外插槽。大多数情况下,基于 .NET Framework 的代码会消耗少量内存,不过可以继续工作。
下面是使用这种数组的一个代码示例。
' VBAcode Option Base 1 Private Sub Test() Dim myArr(10) As Integer ' array is indexed 1..10 addOne myArr End Sub Sub addOne(arr) For i = 1 To 10 arr(i) = arr(i) + 1 Next i End Function
您可以将这段代码转换为 Visual Basic .NET,如下所示:
' Visual Basic .NETcode Private Sub Test() ' array is indexed 0 to 10 and has an unused element at 0. Dim myArr(11) As Short addOne(myArr) End Sub Sub addOne(ByRefarr() As Short) Dim i As Integer For i = 1 To 10 arr(i) = arr(i) + 1 Next i End Sub
不可以这样做的唯一情况是,VBA 代码依赖于值为 1 的数组下限,而不是 0。例如,代码可以使用 LBOUND 函数确定数组的第一个索引,也可以使用 LBOUND 和 UBOUND 函数组合确定数组的大小。
当然,对使用 Option Base 的数组进行迁移的另一个选择是重写所有数组索引值,以使它们都从零开始。这可以最有效地利用内存,不过在迁移时可能需要更多工作,而且要更加小心。
数组的另一个问题是,在 Visual Basic .NET 中,对先前未设置维数的数组(使用 Dim)不能再重新设置维数(使用 ReDim)。在 Visual Basic .NET 中,使用新秩重新声明数组时会出现其他的 ReDim 问题。例如,下面的代码可以在 VBA 中运行,但无法轻松地将其迁移到 Visual Basic .NET。
' VBAcode Private Sub Form_Load() Dim a1(10,10) a1(2, 2) = 5 ReDim a1(10, 10, 10) a1(9, 9, 9) = 44 End Sub
将这段代码迁移到 Visual Basic .NET 的一种可能方法是,先声明一个新数组,然后将原数组的内容复制到新数组中,如以下代码所示。
' Visual Basic .NETcode Private Sub Form_Load() Dim a1(10, 10) As Integer a1(2, 2) = 5 Dim a2(10, 10, 10) For Dimension1 As Integer = 0 To a1.GetLength(0) - 1 For Dimension2 As Integer = 0 To a1.GetLength(1) - 1 a2(Dimension1, Dimension2, 0 ) = a1(Dimension1, Dimension2) Next Next a2(9, 9, 9) = 44 End Sub
日期
您可以将 VBA 日期作为整数使用。您可以使用数字运算符将它们与其他值相组合。您可以在日期中添加或减去一个整数,结果是另一个日期变量。所有其他使用数字进行运算的日期用法均会产生数值。
下面是一个来自 Microsoft Office Excel 2003 工作簿的 VBA 代码示例,它有两个已命名范围:SuperconductorBeginDate 和 SuperconductorEndDate。此示例说明了如何组合日期和整数。
' VBAcode Private Sub CalculateAverageDate() Dim currentProjectBeginDate As Date Dim currentProjectEndDate As Date currentProjectBeginDate = Range("SuperconductorBeginDate").Value currentProjectEndDate = Range("SuperconductorEndDate").Value averageDate = AvgDate(currentProjectBeginDate, currentProjectEndDate) End Sub Function AvgDate(dateBegin, dateEnd) numDays = dateEnd - dateBegin ' difference between two dates in days If numDays > 21 Then ' calculate midpoint between two dates dateBegin = dateBegin + (dateEnd - dateBegin) / 2 Else dateBegin = dateBegin + 7 ' calculate a week from this date End If AvgDate = dateBegin End Function
在迁移代码时,您需要考虑 Date 变量的所有这些使用类型。您需要识别 VBA 解释为隐式 Date 操作的表达式,并使用 FromOADate 和 ToOADate 方法将它们转换为 Visual Basic .NET 中需要的显式强制转换操作。您可以迁移下面这段代码。
' Visual Basic .NETcode Private Sub CalculateAverageDate() Dim averageDate As Date ' New type declaration added Dim currentProjectBeginDate As Date Dim currentProjectEndDate As Date currentProjectBeginDate = Range("SuperconductorBeginDate").Value currentProjectEndDate = Range("SuperconductorEndDate").Value averageDate = AvgDate(currentProjectBeginDate, currentProjectEndDate) End Sub ' Improved function declaration Function AvgDate(ByRefdateBegin As Date, ByRefdateEnd As Date) As Date Dim numDays As Double ' New type declaration added ' Compute the difference between two dates in days numDays = dateBegin.ToOADate - dateEnd.ToOADate If numDays > 21 Then ' Calculate midpoint between two dates dateBegin = System.Date.FromOADate(dateBegin.ToOADate + _ System.Date.FromOADate(dateEnd.ToOADate - _ dateBegin.ToOADate).ToOADate / 2) Else ' Calculate a week from this date dateBegin = System.Date.FromOADate(dateBegin.ToOADate + 7) End If AvgDate = dateBegin End Function
范围
Visual Basic .NET 现在支持变量范围限定。在 VBA 中,在一个方法中任何位置声明的任何变量都可以从该方法的任何位置访问,并且不管它在何处声明,都会在该方法的开始处实例化。这意味着,VBA 中的所有局部变量都有方法范围。然而,在 Visual Basic .NET 中,如果一个变量是在 For 或 While 循环内部声明的,则只能在 For 或 While 循环的范围内访问它。例如:
' VBAcode Public Function GetSumTotal(ByValLastNum As Integer) Dim X As Integer For X = 1 To LastNum ' Total is instantiated when the function is called Dim Total As Integer Total = Total + X Next X ' This will not generate an error because Total is in scope GetSumTotal = Total End Function ' Visual Basic .NETcode Public Function GetSumTotal(ByValLastNum As Integer) Dim X As Integer ' The Total declaration has been moved to function scope Dim Total As Integer For X = 1 To LastNum Total = Total + X Next X GetSumTotal = Total End Function
在过程调用中使用圆括号
在 VBA 子例程或函数中,有时难以确定何时使用(或不使用)圆括号 ( ) 将参数列表括起来。
例如,在 VBA 中,不接收参数的子例程或函数不需要圆括号。否则,在声明中需要圆括号。在调用子例程时,可以直接通过名称调用子例程,也可以使用 Call 语句调用。在直接调用子例程时,不要使用圆括号。在使用 Call 语句调用接收参数的函数时,必须使用圆括号。在使用 Call 语句调用不接收参数的函数时,不要使用圆括号。这些规则在使用函数和将函数调用的结果分配给变量时有所不同。
在 Visual Basic .NET 中,在方法调用中传递参数时需要圆括号。另外,包含带有圆括号的函数调用的语句与包含不带圆括号的函数调用的语句是以不同方式计算的。这有两个原因:
• |
函数参数以不同方式计算。 |
• |
圆括号的使用也决定了函数是否返回值。 |
下面是调用带参数和不带参数的子例程或函数的一些示例。
表 1. VBA 和 Visual Basic .NET 的子例程和函数调用语法 | ||
描述 | VBA 代码 | Visual Basic .NET 代码 |
不带参数的子例程调用 |
ProcessPayments |
ProcessPayments() |
不带参数但使用 Call 语句的子例程调用 |
Call ProcessPayments |
Call ProcessPayments() |
带参数的子例程调用 |
ProcessClient "Akers, Kim" |
ProcessClient("Akers, Kim") |
带参数且使用 Call 语句的子例程调用 |
Call ProcessClient("Akers, Kim") |
Call ProcessClient("Akers, Kim") |
带参数和结果赋值的函数调用 |
TotalPaymentAmount = GetTotalPaymentAmount("Akers, Kim") |
TotalPaymentAmount = GetTotalPaymentAmount("Akers, Kim") |
带参数但不赋值的函数调用 |
GetTotalPaymentAmount "Akers, Kim" |
GetTotalPaymentAmount("Akers, Kim") |
参数传递
在 VBA 中,默认情况下通过引用传递参数。在 Visual Basic .NET 中,默认情况下通过值传递参数。
例如,下面的代码显示了一些带 ByRef 和 ByVal 参数的函数。
' VBAcode Sub myMethodByRef(name) ' parameter passed by reference name = "myMethodByRef" ' original argument changed End Sub Sub myMethodByRef(ByRefname) ' parameter passed by reference name = "myMethodByRef" ' original argument changed End Sub Sub myMethodByVal(ByValname) ' parameter passed by value name = "myMethodByVal" ' change has no effect on original argument End Sub Private Sub Button_Click() Dim value value = "Nothing" myMethodByRefvalue MsgBox (value) ' Displays "myMethodByRef" myMethodByRefvalue MsgBox (value) ' Displays "myMethodByRef" myMethodByValvalue MsgBox (value) ' Displays "myMethodByRef" End Sub
将这段代码迁移到 Visual Basic .NET 时,必须适当地限定参数并指定参数类型。
' Visual Basic .NETcode Sub myMethodByRef(ByRefname_parameter As String) ' parameter passed by reference name_parameter = "myMethodByRef" ' original argument changed End Sub Sub myMethodByRef(ByRefname_parameter As String) ' parameter passed by reference name_parameter = "myMethodByRef" ' original argument changed End Sub Sub myMethodByVal(ByValname_parameter As String) ' parameter passed by value name_parameter = "myMethodByVal" ' change has no effect on original argument End Sub Private Sub Button_Click() Dim value As String value = "Nothing" myMethodByRef(value) MsgBox(value) ' Displays "myMethodByRef" myMethodByRef(value) MsgBox(value) ' Displays "myMethodByRef" myMethodByVal(value) MsgBox(value) ' Displays "myMethodByRef", argument will not be changed End Sub
默认属性
在 VBA 中,通过消除默认属性,键入代码时可以使用快捷方式。而在 Visual Basic .NET 中,只有当属性带有参数时才支持默认属性。在所有使用早期绑定并知道赋值中使用的对象类型的情况中,通过适当扩展默认属性可以解决这个问题。
这是可能的,因为这些晚期绑定修补程序允许根据标识符在代码中的使用来解析它的类型。当您知道类型以后,就可以确定它的默认属性。
下面的代码读取名为 GrandTotal2005 的 Excel 区域的值。Range 对象的默认属性是 Value 属性,因此 grandTotal 被赋予 Range 对象的值。
' VBAcode Dim grandTotal grandTotal = Range("GrandTotal2005") ' Default Property of Range is Value ' Visual Basic .NETcode Dim grandTotal As Single = Range("GrandTotal2005").Value
赋值
在 VBA 中,您需要 Set 关键字来区分对象赋值和该对象的默认属性赋值。由于 Visual Basic .NET 不支持默认属性,所以不需要 Set 关键字,它也不再受支持。在迁移时,您应该删除 Set 关键字。另外,Visual Basic .NET 不再需要 Let 关键字。例如:
' VBAcode Dim ParagraphFormat1 As New Word.ParagraphFormat Dim ParagraphFormat2 As New Word.ParagraphFormat Dim WordWrapOn As Boolean Set ParagraphFormat1 = ParagraphFormat2 ParagraphFormat1.WordWrap = False Let WordWrapOn = ParagraphFormat2.WordWrap ' Assigns False to WordWrapOn ' Visual Basic .NETcode Dim ParagraphFormat1 As New Microsoft.Office.Interop.Word.ParagraphFormat Dim ParagraphFormat2 As New Microsoft.Office.Interop.Word.ParagraphFormat Dim WordWrapOn As Boolean ParagraphFormat1 = ParagraphFormat2 ' No Set Keyword ParagraphFormat1.WordWrap = False ' No Let Keyword WordWrapOn = ParagraphFormat2.WordWrap ' Assigns False to WordWrapOn
TypeOf/TypeName
在 VBA 中,TypeOf 函数用在 If. . .Then. . .Else 语句中,以确定对象引用是否为指定的对象类型。在 Visual Basic .NET 中,这仍然有效,但用户定义的类型(现在称为结构)不再是对象类型,并且不能通过 TypeOf 函数计算。
' VBAcode Type Account balance As Integer End Type Dim clientAccount As Account If TypeOfclientAccount Is Account Then ProcessAccount(clientAccount) End If ' Visual Basic .NETcode Public Structure Account Dim balance As Integer End Structure Dim clientAccount As Account ' For structure type checking the following syntax can be used If clientAccount.GetType Is GetType(Account) Then ProcessAccount(clientAccount) End If
TypeName 函数与此类似,但它返回字符串而不是对象类型。问题在于,在 Visual Basic .NET 中,这些字符串改变了,所以可能无法产生预期的结果。例如,在下面的代码中,VBA 代码将 "Workbook" 显示为 TypeName,但 Visual Basic .NET 代码则显示 "ThisWorkbook"。
' VBAcode Sub TypeOfDemo() Set myType = Workbooks(1) If TypeOfmyType Is Excel.Workbook Then MsgBox TypeName(myType) End If End Sub ' Visual Basic .NETcode Sub TypeOfDemo() Dim myType As Object myType = Globals.ThisWorkbook If TypeOfmyType Is Excel.Workbook Then MsgBox(TypeName(myType)) End If End Sub
控制结构
在 Visual Basic .NET 中,大多数控制结构与 VBA 中的一样,唯一不同的是 While 语句。在 VBA 中,While 语句以 WEnd 关键字结束。而在 Visual Basic .NET 中,While 语句以 EndWhile 语句结束。Visual Basic .NET 不再支持 GoSub. . .Return 和 On. . .GoSub 语句。在许多情况下,您可以将 GoSub 语句替换为新函数。幸运的是,GoSub、GoTo 和 Return 语句在 VBA 应用程序中很少使用,而且 VBA 开发人员指南不建议使用它们。因此,您在必须迁移的 VBA 代码中可能不会发现太多 GoSub 和 GoTo 语句。VBA 和 Visual Basic .NET 都支持 GoTo,它在这两种环境下具有相同的行为。然而,在为 GoTo 语句创建标签时,请记住 Error 是 Visual Basic .NET 中的关键字,因此不能作为标签的名称。以下是如何迁移带有“Error”标签的 GoTo 语句的示例,这种标签在 VBA 代码中很常用。
' VBAcode Sub GoToDemo() Dim Num Num = 1 If Num > 0 Then GoTo Error MsgBox Num Exit Sub Error: MsgBox "Error!!!" End Sub ' Visual Basic .NETcode Sub GoToDemo() Dim Num As Integer Num = 1 If Num > 0 Then GoTo ErrorLabel MsgBox(Num) Exit Sub ErrorLabel: MsgBox("Error!!!") End Sub
异常处理
Visual Basic .NET 引入了一个全新的错误处理机制,称为异常处理,它使用 Try、Catch 和 Finally 关键字。在 Visual Basic .NET 中,异常处理是处理绝大多数错误的首选方法。例如:
' Visual Basic .NETcode Dim averageCost As Integer Try averageCost = Range("TotalCost").Value / Range("TotalProjects").Value Catch ex As Exception averageCost = 0 Finally ' This code will be executed every time regardless of whether an Exception happens RecordAverageCost( averageCost ) End Try
这段代码示例试图计算平均成本,但如果由于某种原因失败,则会将 averageCost 设置为 0。该代码示例可捕获所有异常,但它并不总是最适当的编码做法。更好的编码做法是只捕获已知会引发的特定异常。在本例中,如果引发一个较普通的异常,那么它会由一个更高级的 catch 捕获,而这个 catch 可能更适合处理该异常。不管是否引发异常,Finally 语句始终会执行。
晚期绑定和早期绑定
在 VBA 中,可以声明无类型的变量。所有隐式声明的变量都是 Variant 类型。例如:
' VBAcode Dim numParagraphs ' Late binding to a VariantLong type numParagraphs= Application.ActiveDocument.Paragraphs.Count Dim numParagraphsAs Long ' Early binding of numParagraphsto a Long type numParagraphs= Application.ActiveDocument.Paragraphs.Count
在赋值为 Application.ActiveDocument.Paragraphs.Count 时,变量 numParagraphs 会晚绑定到 VariantLong 类型。声明时,变量 numParagraphs 会早绑定到 Long 类型,因为在您创建它的实例时,该类型是已知的。从技术上讲,Visual Basic .NET 中没有晚期绑定。
' Visual Basic .NETcode Dim numParagraphs ' Early binding to an Object type numParagraphs= Me.Paragraphs.Count Dim numParagraphsAs Long ' Early binding to a Long type numParagraphs= Me.Paragraphs.Count
当您在 Visual Basic .NET 中编译这段代码时,会出现以下情况:
1. |
变量 numParagraphs 被声明为 Object 类型。 |
2. |
值 Me.Paragraphs.Count 被置入堆中的对象,而不是栈中的对象。 |
3. |
numParagraphs 变量存储堆中对该对象的引用。 |
对于 numParagraphs 这种情况,使用 numParagraphs 变量的代码执行速度要慢于计数器在栈中执行的速度。因此,在迁移晚绑定的 VBA 值类型变量时,如果在实例化时显式声明了它们的类型,则性能会略有改善。这是在 VBA 和 Visual Basic .NET 中始终应该声明所有变量的类型的原因之一。
多个变量声明
在 VBA 中,可以用相同的语句声明不同类型的变量,但必须指定每个变量的数据类型或者默认为 Variant。下面的示例显示了多个变量声明及其产生的数据类型:
' VBAcode Dim I, J As Integer ' I is Variant, J is Integer. Dim L As Integer, M As Integer ' L is Integer, M is Integer.
在 Visual Basic .NET 中,可以声明相同数据类型的多个变量,而不必重复类型关键字。您可以按如下方式迁移这些声明:
' Visual Basic .NETcode Dim I As Object Dim J As Short ' J is Short. Dim L, M As Short ' L is Short, M is Short.
变量数组
在向 Visual Basic .NET 迁移时,未声明类型的数组或者类型为 Variant 的数组可得益于晚绑定修补程序。解决方案是,根据数组的使用将数组类型更改为特定类型。
如果代码在使用这些数组时不一致或者在数组中存储不同类型的数据,则会产生问题,如以下示例所示。
' VBAcode Dim A1(10) A1(1) = Range("WirelessNetworkTitle").Comment 'first element is a String A1(2) = 1 'second element is an Integer
解决这个问题的一种方法是,分析数组中存储的类型所共享的类层次结构,然后选择能够表示这两种类型的最具体的超类。如果除了 Object(它是所有类的超类)以外没有其他超类,则可以确定是否可以将一种类型直接转换成另一种类型。例如:
' Visual Basic .NETcode Dim A1(10) As String A1(1) = Range("WirelessNetworkTitle").Comment A1(2) = CStr(1)
Windows API
调用外部 Win32 API 的 VBA 代码在 Visual Basic .NET 中仍然有效,但可能需要更改其中的一些数据类型。下面的代码声明了一个外部函数,该函数在调用时就像一个正常的 VBA 函数。在 Visual Basic .NET 中,声明和调用是相同的。
' VBAcode Declare Function GetTickCount Lib "kernel32" () As Long Sub APIsDemo() L = GetTickCount() End Sub ' Visual Basic .NETcode ' A Long in VBAis an Integer in Visual Basic .NET Declare Function GetTickCount Lib "kernel32" () As Integer Sub APIsDemo() Dim L As Integer L = GetTickCount() End Sub
虽然从 VBA 调用 Win32 API 应该与在 Visual Basic .NET 中一样,但将大量 Win32 API 调用转换为基于 .NET Framework 的等效框架可能是最理想的选择。
有关 .NET Framework 等效框架的更多信息,请参阅 MicrosoftWin32to Microsoft.NET FrameworkAPIMap。
Printer 对象和 Printers Collection 对象
Visual Basic.NET 不支持 VBA Printer 对象和 Printers Collection 对象。在代码中使用这些功能来打印的应用程序需要进行大量的重写工作。将 VBA Printer 对象迁移到 Visual Basic.NET 的一种方法是使用 System.Drawing.Printing 对象来打印。
剪贴板
您可以将读写剪贴板的 VBA 代码映射到 Visual Basic .NET 中的 My.Computer.Clipboard 对象。例如:
' VBAcode Dim tempData As DataObject Dim clipboardString As String Set tempData = New DataObject ' Clears the clipboard tempData.SetText "" tempData.PutInClipboard ' Puts the text from an Excel cell into the clipboard clipboardString = Range("WirelessNetworkTitle").Value tempData.SetText clipboardString tempData.PutInClipboard ' Gets the text on the clipboard into a string variable tempData.GetFromClipboard clipboardString = "" clipboardString = tempData.GetText ' Visual Basic .NETcode Dim clipboardString As String ' Clears the clipboard My.Computer.Clipboard.Clear() ' Puts the text from an Excel cell into the clipboard My.Computer.Clipboard.SetText( _ Range("WirelessNetworkTitle").Value.ToString()) ' Gets the text on the clipboard into a string variable clipboardString = My.Computer.Clipboard.GetText()
Microsoft Office 2003 对象模型
Microsoft Office 2003 对象模型是基于 COM 的,而相同的 COM 组件在 VBA 或 Visual Basic .NET 中都可用。然而,要从 Visual Basic .NET 访问 Microsoft Office 2003 对象模型,您需要在基于 .NET Framework 的代码中对 COM 组件进行包装,然后再从您的 Visual Basic .NET 程序调用它们。Microsoft Office 2003 Editions 提供了以下包装类(称为主 interop 程序集),以便您可以从基于 .NET Framework 的代码中访问 Office 对象模型。主 interop 程序集可能会更改 COM 组件的调用方式,以优化从 Visual Basic .NET 的调用。然而,大部分功能基本是一样的,您可以将对 Office 2003 对象模型的 VBA 调用映射为 Visual Basic .NET 中的等效调用。
VBA 对象模型
VBA 对象模型包含 350 多个函数,对这些函数来说,没有主 interop 程序集。您必须将这些函数映射为 Visual Basic .NET 等效函数。您可以将 VBA 对象模型的大部分元素迁移到 Visual Basic .NET 等效元素(除了下表中所列的对象模型)。
表 2. 没有基于 .NET Framework 的 Visual Basic 等效函数的 VBA 对象模型函数 | |
VBA 对象模型函数 | 描述 |
vba._HiddenModule.InputB |
用于在二进制级别访问文件 |
vba._HiddenModule.InputB$ |
用于在二进制级别访问文件 |
vba._HiddenModule.ObjPtr |
用于处理指针的未文档化函数 |
vba._HiddenModule.StrPtr |
用于处理指针的未文档化函数 |
vba._HiddenModule.VarPtr |
用于处理指针的未文档化函数 |
vba.Conversion.CVErr |
创建用户定义的错误 |
vba.Conversion.MacID |
在 Macintosh 计算机中用于替代通配符 |
vba.DateTime.Calendar |
用于处理非公历日历 |
VBA.VbCalendar.vbCalGreg |
用于处理非公历日历 |
VBA.VbCalendar.vbCalHijri |
用于处理非公历日历 |
vba.Strings.AscB |
用于操作非 Unicode 字符串 |
vba.Strings.ChrB |
用于操作非 Unicode 字符串 |
vba.Strings.ChrB$ |
用于操作非 Unicode 字符串 |
vba.Strings.InStrB |
用于操作非 Unicode 字符串 |
vba.Strings.LeftB |
用于操作非 Unicode 字符串 |
vba.Strings.LeftB$ |
用于操作非 Unicode 字符串 |
vba.Strings.LenB |
用于操作非 Unicode 字符串 |
vba.Strings.MidB |
用于操作非 Unicode 字符串 |
vba.Strings.MidB$ |
用于操作非 Unicode 字符串 |
vba.Strings.RightB |
用于操作非 Unicode 字符串 |
vba.Strings.RightB$ |
用于操作非 Unicode 字符串 |
VBA.VbCompareMethod.vbDatabaseCompare |
Enum、String Compare、String 函数 |
VBA.VbFileAttribute.vbAlias |
Dir、Get、Set 属性 |
VBA.VbMsgBoxStyle.vbDefaultButton4 |
用于指定对话框中的第四个按钮为默认按钮。 |
VBA.VbStrConv.vbFromUnicode |
与 StrConv 函数结合用于与 Unicode 相互转换 |
VBA.VbStrConv.vbUnicode |
与 StrConv 函数结合用于与 Unicode 相互转换 |
VBA.VbVarType.vbDataObject |
不支持 IDispatch 接口的对象 |
App 对象
VBA 中的 App 对象在 Visual Basic .NET 中没有直接的等效对象。您可以使用其他类似的 Visual Basic .NET 功能来迁移某些 App 对象功能。例如,您可以将 App.LogEvent 映射为 Visual Basic .NET 中的 My.Application.Log.WriteEntry 方法,如以下示例所示:
' VBAcode App.LogEvent "Error", vbLogEventTypeError App.LogEvent "Warning", vbLogEventTypeWarning App.LogEvent "Information", vbLogEventTypeInformation ' Visual Basic .NETcode My.Application.Log.WriteEntry("Error", _ System.Diagnostics.TraceEventType.Error) My.Application.Log.WriteEntry("Warning", _ System.Diagnostics.TraceEventType.Warning) My.Application.Log.WriteEntry("Information", _ System.Diagnostics.TraceEventType.Information)
Forms Collection 对象
VBA 中的 FormsCollection 对象在 Visual Basic .NET 中没有直接的等效对象。然而,您可以将 Forms Collection 迁移到 Visual Basic .NET 中的 My.Application.Forms object。例如,以下代码可以将 VBA Forms Collections 对象的一部分迁移到 Visual Basic .NET My.Application.Forms 对象:
' VBAcode Form2.Show i = Forms.Count Forms(1).Caption = "Trey Research Budget Projections" Forms.Item(1).Caption = "Project Details" ' Visual Basic .NETcode Dim x As Integer Form2.Show () x = My.Application.OpenForms.Count My.Application.OpenForms.Item(1).Text = "Trey Research Budget Projections" My.Application.OpenForms.Item(1).Text = "Project Details"
UserForms
Visual Basic .NET 不支持 VBA UserForms。您应该将这些迁移到 Windows Forms。
VBA Form 的核心是 MSForms 类型库。Visual Basic .NET Form 的核心是 Visual Basic .NET 类型库。这两个包非常类似,都包含 Control coclass 和 IControl 接口。对于 VBA 和 Visual Studio 2005 Tools for Office 中的大多数控件,Label 控件、TextBox 控件甚至事件都是一样的。
Visual Studio 2005 Tools for Office 中某些控件的名称改变了,但功能通常都保持一致。您可以使用以下从 VBA 到 Windows Forms 的映射来进行迁移。
表 3. 将 VBA 控件映射为 Visual Studio 2005 Tools for Office 控件 | |
VBA 控件 | Visual Studio 2005 Tools for Office 控件 |
MSForms.Label |
System.Windows.Forms.Label |
MSForms.TextBox |
System.Windows.Forms.TextBox |
MSForms.Frame |
System.Windows.Forms.GroupBox |
MSForms.ComboBox |
System.Windows.Forms.ComboBox |
MSForms.ListBox |
System.Windows.Forms.ListBox |
MSForms.CheckBox |
System.Windows.Forms.CheckBox |
MSForms.OptionButton |
System.Windows.Forms.RadioButton |
MSForms.ToggleButton |
System.Windows.Forms.CheckBox |
MSForms.CommandButton |
System.Windows.Forms.Button |
MSForms.TabStrip |
System.Windows.Forms.TabControl |
MSForms.MultiPage |
System.Windows.Forms.TabControl |
MSForms.ScrollBar (Horizontal) |
System.Windows.Forms.HscrollBar |
MSForms.ScrollBar (Vertical) |
System.Windows.Forms.VscrollBar |
MSForms.SpinButton |
System.Windows.Forms.DomainUpDown |
MSForms.Image |
System.Windows.Forms.PictureBox |
Microsoft.Vbe.Forms.RefEdit |
Microsoft.Vbe.Forms.RefEdit |
从功能上说,大多数控件的行为是一样的。然而,对于 Multipage 和 SpinButton 控件,您可能需要兼容类来实现在 VBA 中的相同功能。
Visual Basic .NET 不再支持某些在 VBA Forms 中受支持的事件;也就是说,它们无法直接映射为 Visual Basic .NET 事件,而是必须进行替换。例如,您可能需要将许多 VBA 控件中出现的 Error 事件替换为另一种错误处理机制,例如 Visual Basic .NET 异常处理。
拖放
用于拖放功能的模型有很大不同,所以您必须重新编写执行拖放操作的所有代码。每个基于 .NET 的 Windows Forms 控件都有四个用于拖放的事件:DragDrop、DragEnter、DragLeave 和 DragOver。有关实现拖放的更多信息,请参阅 Implementing Drag and Drop in Visual Basic .NET。
动态数据交换 (DDE)
在 VBA 中,动态数据交换 (DDE) 是在应用程序之间交换信息的机制。Visual Basic .NET 不再支持 DDE 方法。您应该修改依赖于 DDE 的应用程序,以使用另一种在应用程序间通信的方法,或者将它们留在 VBA 中。Microsoft .NET Remoting 框架是一种在 Visual Basic .NET 中常用的应用程序间通信形式,您可以使用它来替代 DDE 功能。
ActiveX 数据对象、数据访问对象和远程数据对象
Visual Basic .NET 引入了一个增强版的 ActiveX 数据对象 (ADO),称为 ADO.NET,它为处理分布式应用程序中的数据而进行了优化,在分布式应用程序中使用时,它能够提供比 ADO 更高的性能。下面是从 ADO 转换为 ADO.NET 的示例。
' VBAcode Sub Test1() Dim con As New ADODB.Connection con.ConnectionString = "Provider=SQLOLEDB.1;Integrated" + _ "Security=SSPI;Persist Security Info=False;Initial" + _ "Catalog=Northwind" con.Open Dim com As New ADODB.Command com.ActiveConnection = con Dim rec As ADODB.Recordset com.CommandText = "Select * from Employees" Set rec = com.Execute While Not rec.EOF Dim var As Variant var = rec.Fields.Item(1).Value 'Do Something rec.MoveNext Wend End Sub ' Visual Basic .NETcode Sub Test1() Dim con As New System.Data.SqlClient.SqlConnection con.ConnectionString = "Integrated Security=SSPI;Persist Security" + _ "Info=False;Initial Catalog=Northwind" con.Open() Dim com As New System.Data.SqlClient.SqlCommand com.Connection = con Dim rec As System.Data.SqlClient.SqlDataReader com.CommandText = "Select * from Employees" rec = com.ExecuteReader While rec.Read Dim var As Object var = rec.Item(1) 'Do Something End While End Sub
在 Visual Basic .NET 中,经过一些修改仍然可以在代码中使用数据访问对象 (DAO)、远程数据对象 (RDO) 和 ADO。然而,Visual Basic .NET 不支持 DAO 和 RDO 数据绑定到控件、数据控件或 RDO 用户连接。如果您想要在 .NET Framework 的 Windows Forms 中使用 ADO 数据绑定,则必须在将项目升级到 Visual Basic .NET 之前,将 DAO 或 RDO 数据绑定转换为 ADO。
有关 ADO 和 ADO.NET 的更多信息,请参阅以下文章:
• |
Migrating from ADO to ADO.NET |
• |
ADO.NET for the ADO Programmer |
• |
Comparison of ADO.NET and ADO |
本文讨论在向 Visual Studio 2005 Tools for Office 迁移时,将代码从 VBA 转换到 Visual Basic .NET 时可能会遇到的许多问题。迁移到 Visual Basic .NET 的好处明显,对许多 VBA 项目来说非常值得考虑。然而,进行这个过程要非常谨慎。自动化工具使得这个迁移过程更加系统化、更加不容易出错,并且更加快速。
Visual Studio 2005 Tools for Office
• |
Visual Studio 2005 Tools for Office 网络日记 |
• |
Visual Studio Tools for Office 新闻组:microsoft.public.vsnet.vstools.office |
迁移 VBA 代码
• |
Converting Code from VBA to Visual Basic .NET |
• |
Converting Microsoft Office VBA Macros to Visual Basic .NET and C# |
• |
Migrating Word VBA Solutions to Visual Studio Tools for Office |
VBA
• |
Visual Basic for Applications |
Microsoft Office 对象模型
• |
Understanding the Excel Object Model from a .NET Developer's Perspective |
• |
Understanding the Word Object Model from a .NET Developer's Perspective |
主 Interop 程序集
• |
Primary Interop Assemblies |
迁移
• |
Migrating on the Visual Basic Developer Center |
自 1993 年起,ArtinSoft 就一直在帮助全球客户在升级到新平台(主要是 Microsoft .NET Framework)时使用和保护他们对当前应用程序的投资。Microsoft 在 Visual Studio.NET 中提供了 ArtinSoft 创建的迁移产品,并指定它作为 Microsoft 全球客户升级服务的首选供应商。您可以在 www.artinsoft.com 中找到有关 ArtinSoft 的更多信息,或者通过电子邮箱 [email protected] 与 ArtinSoft 联系。
转到原英文页面
返回页首 |