避免命名冲突

当试着创建或使用先前已定义的标识符时，就会发生命名冲突。在某些情况下，命名冲突会生成象“发现二义性的无效名称”或“在当前范围内的声明重复”等错误。命名冲突如果没有被检测出，则会导致代码错误，如此将会生成错误的结果，特别是，在第一次使用之前没有明确声明所有的变量。

可以由了解数据、对象、和过程中标识符的范围特性，来避免大部分的命名冲突。Visual Basic 拥有三个范围级别：过程级别、私有模块级别、和公共模块级别。

当一个标识符有下列情形时可能发生命名冲突：

•	在一个以上范围级别中为可见的。

•	在同一范围级别中具有两种不同的意义。

举例来说，在分离的模块中可能有相同的名称。因此，可以在模块名称为 Mod1 和 Mod2 中定义过程名称为 MySub。如果每一个过程都只被同属于一个模块的程序所调用，则不会有命名冲突发生。然而，如果 MySub 是从第三个模块中调用的，则发生错误，因为没有任何的条件来区别这两个 MySub 过程。

可以在每一个标识符前加上一个限定符，其可由模块名称或是工程名称来组成，如此可解决大部分的命名冲突。例如：

YourProject.YourModule.YourSub MyProject.MyModule.MyVar

前面的代码调用 Sub 过程 YourSub 并且传递 MyVar 来当做参数。可以使用任何限制符组合去区分相同的标识符。

Visual Basic 将每一个对标识符的引用与一个符合标识符的声明做比对。例如，如果 MyID 在工程的两个模块（Mod1 与 Mod2）中被声明为 Public，则在 Mod2 中指定声明的 MyID，并不需要在 Mod2 里加上限制符，但若在 Mod1 中指定上述的 MyID，则必须以 Mod2.MyID 来定位它。当 Mod2 在不同但直接被引用的工程中，则上述方式仍然可行。然而，如果 Mod2 是在一个间接引用的工程中；也就是一个被直接引用工程所引用的工程；则引用 Mod2 中的变量名称 MyID 时需要用工程名来加以限制。如果是从第三个直接引用的模块来引用 MyID，则在匹配时会以第一个找到符合下面规则的声明为主：

•	直接引用的工程，以它们出现在“工具”菜单中的“引用”对话框的顺序为准。

•	每个工程的模块。需注意的是工程的模块中并无固定的顺序。

在不同的范围级别中，不能重复使用主应用程序对象的名称。例如，在 Microsoft Excel 中的 R1C1。

提示   由命名冲突所引起的典型错误包括有仿真两可的名称、重复声明、未声明标识符，以及找不到过程。在模块开头加上 Option Explicit 语句，可以强迫在变量被使用前对变量做明确的声明，如此可以避免一些可能的命名冲突以及和标识符有关的错误。


利用相同的名称来调用程序

可以调用位于相同工程中任何模块内的过程，如同将在活动的模块中调用过程一样。然而如果有两个或更多的模块包含相同的过程名称，必须在调用的语句中指定模块名称，如以下示例所示：

Sub Main()

Module1.MyProcedure

End Sub

如果在两个工程中对两个过程给予相同名称，则在调用那个过程时必须指定工程名。例如，下面的过程调用了 MyProject.vbp 工程里的 MyModule 模块中的 Main 过程。

Sub Main()

[MyProject.vbp].[MyModule].Main

End Sub

注意   不同的应用程序拥有不同的工程名。例如，在 Microsoft Access 中工程被称为数据库 (.mdb)；在 Microsoft Excel 中被称为工作簿 (.xls)。

调用过程的提示

•	如果将模块或工程重新命名，则切记要更改它们在调用语句中的名称，否则 Visual Basic 将不能找到所调用的过程。可以使用“编辑”菜单中的“替换”命令去模块中查找并替换文本。

•	为了避免引用工程时发生命名冲突，可以给于一个程序唯一的名称；如此当调用程序时就不用去指定它是属于哪个模块或工程。


调用属性过程

下表列出了为调用属性过程的语法：

属性过程	语法
Property Let	[object.]propname(arguments)] = argument
Property Get	varname = [object.]propname(arguments)]
Property Set	Set [object.]propname[.(arguments)] = varname
当调用一个 Property Let 或 Property Set 过程时，总是会有一个参数出现在等号（=）的右边。

当用多个参数声明一个 Property Let 或 Property Set 过程时，Visual Basic 传递调用的右边参数，给 Property Let 或 Property Set 声明中的最后一个参数。例如，下图显示了 Property 过程调用中的参数与 Property Let 声明中的参数的关系：

实际上，将属性过程与多个参数合用只有在创建属性的数组时才会使用。


调用 Sub 以及 Function 过程

从其它过程调用一个 Sub 过程时，必须键入过程名称以及任何需要的参数值。而 Call 语句并不需要，不过若使用它，则任何参数必须以括号括起来。

可以使用 Sub 过程去组织其它的过程，因此可以较容易了解并调试它们。在下面的示例中，Sub 过程 Main 传递参数值 56 去调用 Sub 过程 MultiBeep。运行 MultiBeep 后，控件返回 Main，然后 Main 调用 Sub 过程 Message。Message 显示一个信息框；当按“确定”键时，控件会返回 Main，接着 Main 退出执行。

Sub Main()

MultiBeep 56

Message

End Sub

Sub MultiBeep(numbeeps)

For counter = 1 To numbeeps

Beep

Next counter

End Sub

Sub Message()

MsgBox "Time to take a break!"

End Sub

调用具有多个参数的 Sub 过程

下面的示例展示了调用具有多个参数的 Sub 过程的两种不同方法。当第二次调用 HouseCalc 时，因为使用 Call 语句所以需要利用括号将参数括起来。

Sub Main()

HouseCalc 99800, 43100

Call HouseCalc(380950, 49500)

End Sub

Sub HouseCalc(price As Single, wage As Single)

If 2.5 * wage <= 0.8 * price Then

MsgBox "You cannot afford this house."

Else

MsgBox "This house is affordable."

End If

End Sub

在调用 Function 过程时使用括号

为了使用函数的返回值，必须指定函数给变量，并且用括号将参数封闭起来；如下示例所示：

Answer3 = MsgBox("Are you happy with your salary?", 4, "Question 3")

如果不在意函数的返回值，可以用调用 Sub 过程的方式来调用函数。如下面示例所示，可以省略括号，列出参数并且不要将函数指定给变量：

MsgBox "Task Completed!", 0, "Task Box"

小心   在上述例子中若包含括号，则语句会导致一个语法错误。

传递命名参数

Sub 或 Function 过程中的语句可以利用命名参数来传递值给被调用的过程。可以将命名参数以任何顺串行出。命名参数的组成是由参数名称紧接着冒号（:=）以及等号，然后指定一个值给参数。

下面的示例使用命名参数来调用不具返回值的 MsgBox 函数。

MsgBox Title:="Task Box", Prompt:="Task Completed!"

下面的示例使用命名参数调用 MsgBox 函数。将返回值指定给变量 answer3。

answer3 = MsgBox(Title:="Question 3", _

Prompt:="Are you happy with your salary?", Buttons:=4)


生成对象变量

可以将完全相同的对象变量看成所引用的对象。可以设置或返回对象的属性或者使用它所有的方法。

创建对象变量：

1.	声明对象变量。

2.	指定对象变量到某一对象。

声明一个对象变量

使用 Dim 语句或其它的声明语句之一（Public、Private、或 Static）去声明对象变量。一引用对象的变量必须是 Variant、Object，或是一个对象的指定类型。例如，下列声明是有效的：

'声明 MyObject 为 Variant 数据类型。

Dim MyObject

'声明 MyObject 为 Object 数据类型。

Dim MyObject As Object

'声明 MyObject 为 Font 类型。

Dim MyObject As Font

注意   如果使用对象变量前没有声明它，则对象变量缺省的数据类型是 Variant 类型。

当需等到过程运行才知道指定的对象类型时，可以利用 Object 数据类型来声明。使用 Object 数据类型来创建对任何对象的一般的引用。

如果知道指定的对象类型，必须将对象变量声明成所知道的对象类型。例如，如果应用程序包含 Sample 对象类型，则可以用下列的语句来声明一个对象变量为 Sample 对象类型：

Dim MyObject As Object	'声明为一般的对象。

Dim MyObject As Sample	'只声明为 Sample 对象。

声明指定的对象类型提供自动的类型检查，更快的代码，并增加可读性。

赋值对象变量给对象

使用 Set 语句可以赋值一个对象给对象变量。可以赋值对象表达式或是 Nothing 。例如，下列的对象变量赋值是有效的：

Set MyObject = YourObject	' 赋值对象引用。

Set MyObject = Nothing	' 中断关联。

可以同时使用 New 关键字和 Set 语句来声明对象变量，并赋值一对象给它。例如：

Set MyObject = New Object	' 创建和赋值

设置一个对象变量等于 Nothing，会中断此对象变量与任何特定对象的关联，如此可预防因意外的改变变量而更改对象。在关闭关联对象后，对象变量总是设置为 Nothing，所以可以检测对象变量是否指到有效的对象。例如：

If Not MyObject Is Nothing Then

' 变量引用有效的对象。

. . .

End If

当然，该检测不能绝对的决定用户是否已关闭包含对象变量所引用对象的应用程序。

引用对象的当前实例

Me 关键字可用来引用对象的当前实例，而此为代码正在执行的对象。所有与当前对象关联的过程都可以通过 Me 来引用。使用 Me 来传递关于对象的当前实例信息到其它模块中的过程显得特别有用。例如，假设在模块中有以下这些过程：

Sub ChangeObjectColor(MyObjectName As Object)

MyObjectName.BackColor = RGB(Rnd * 256, Rnd * 256, Rnd * 256)

End Sub

使用以下语句，可以调用过程并将对象的当前的实例当做参数来传递：

ChangeObjectColor Me


创建递归过程

过程会指定一有限的空间给变量使用。当过程每次调用它本身时，则会用掉更多的空间。一个过程调用它本身则称之为递归过程。递归过程若不断的调用它自身，则最后会导致错误发生。例如：

Function RunOut(Maximum)

RunOut = RunOut(Maximum)

End Function

当两个过程不是很明确的互相调用，或是在某些情况下会限制递归不会执行到上述情形，则上述错误可能不很明显。不过递归也有它的用处； 例如，下面的过程使用递归函数去计算因子：

Function Factorial (N)

If N <= 1 Then	' 到达递归调用的末尾。

Factorial = 1

Else	' 如果 N > 0 再调用 Factorial 。

Factorial = Factorial(N - 1) * N

End If

End Function

必须去检测的递归过程，以确保它没有调用它本身太多次，如此才不会执行到内存不足。如果得到一个错误，则确认过程并没有模糊的调用它本身。如此之后，则可试着以下列方式去节省内存：

•	消除不是必须的变量。

•	使用数据类型而不使用 Variant。

•	重新评估过程的逻辑，则常可用嵌套循环来替代递归。


声明数组

数组的声明方式和其它的变量是一样的，它可以使用 Dim、Static、Private 或 Public 语句来声明。标量变量（非数组）与数组变量的不同在于通常必须指定数组的大小。若数组的大小被指定的话，则它是个固定大小数组。若程序运行时数组的大小可以被改变，则它是个动态数组。

数组是否从 0 或 1 索引是根据 Option Base 语句的设置。如果 Option Base 没有指定为 1，则数组索引从零开始。

声明固定大小的数组

下面这行代码声明了一个固定大小的数组，它是个 11 行乘以 11 列的 Integer 数组：

Dim MyArray(10, 10) As Integer

第一个参数代表的是行；而第二个参数代表的是列。

与其它变量的声明一样，除非指定一个数据类型给数组，否则声明数组中元素的数据类型为 Variant。数组中每个数组的数字型 Variant 元素占用 16 个字节。每个字符串型 Variant 元素占用 22 个字节。为了尽可能使写的代码简洁明了，则要明确声明的数组为某一种数据类型而非 Variant。下面的这几行代码比较了几个不同数组的大小：

' 整型数组使用 22 个字节（11 元素* 2 字节）

ReDim MyIntegerArray(10) As Integer

' 双精度数组使用 88 个字节（11 元素 * 8 字节）。

ReDim MyDoubleArray(10) As Double

' 变体型数组至少使用 176 字节（11 元素 * 16 字节）。

ReDim MyVariantArray(10)

' 整型数组使用 100 * 100 * 2 字节（20,000 字节）。

ReDim MyIntegerArray (99, 99) As Integer

' 双精度数组使用 100 * 100 * 8 字节（80,000 字节）。

ReDim MyDoubleArray (99, 99) As Double

' 变体型数组至少使用 160,000 字节（100 * 100 * 16 字节）。

ReDim MyVariantArray(99, 99)

数组变量的最大值，是以的操作系统与有多少可用内存为基础。若使用的数组大小超过了系统中可用内存总数的话，则速度会变慢，因为必须从磁盘中读写回数据。

声明动态数组

若声明为动态数组，则可以在执行代码时去改变数组大小。可以利用 Static、Dim、Private 或 Public 语句来声明数组，并使括号内为为空，如下示例所示。

Dim sngArray() As Single

注意   可以在过程中使用 ReDim 语句来做隐含性的数组声明。当使用 ReDim 语句时要小心点，不要拼错数组的名称。否则即使在模块中有包含 Option Explicit 语句，仍然会因此而生成第二个数组。

对于过程中的数组范围，可以使用 ReDim 语句去改变它的维数，去定义元素的数目以及每个维数的底层绑定。每当需要时，可以使用 ReDim 语句去更改动态数组。然而当做这个动作时，数组中存在的值会丢失。若要保存数组中原先的值，则可以使用 ReDim Preserve 语句来扩充数组。例如，下列的语句将 varArray 数组扩充了10 个元素，而原本数组中的当前值并没有消失掉。

ReDim Preserve varArray(UBound(varArray) + 10)

注意   当对动态数组使用 Preserve 关键字时，只可以改变最后维数的上层绑定，而不能改变维数的数目。


声明常数

通过声明一个常数，可以将有意义的名称赋予一个值。使用 Const 语句去声明一个常数，并且设置它的值；而在常数声明完之后，则不能加以更改或赋予新值。

在声明部分，可以在过程中或者在模块顶部声明常数。模块级别中的常数缺省为私有的。若要声明一个公共模块级别常数，则可以在 Const 语句前加上 Public 这个关键字。也可以利用在 Const 语句前加上 Public 关键字来明确的声明一个私有的常数，使得我们可更容易的去读取并且解释代码。若需更多信息，请参阅 Visual Basic 帮助中的“了解范围与可见性”。

下面的示例，声明了一个 Public 常数 conAge 为 Integer 类型，并且指定它的值为 34。

Public Const conAge As Integer = 34

常数可以声明成下列数据类型中的一种：Boolean、Byte、Integer、Long、Currency、Single、Double、Date、String 或 Variant。因为已经知道常数的值，所以可以指定 Const 语句中的数据类型。关于数据类型的详细信息，请参阅 Visual Basic 帮助中的“数据类型总结”。

可以在一个语句中声明数个常数。为了指定数据类型，必须将每一个常数的数据类型包含进来。在下面的语句中，常数 conAge 和 conWage 被声明为 Integer 类型。

Const conAge As Integer = 34, conWage As Currency = 35000


声明变量

通常会使用 Dim 语句来声明变量。一个声明语句可以放到过程中以创建属于过程的级别的变量。或在声明部分可将它放到模块顶部，以创建属于模块级别的变量。

下面的示例创建了变量 strName 并且指定为 String 数据类型。

Dim strName As String

如果该语句出现在过程中，则变量 strName 只可以在此过程中被使用。如果该语句出现在模块的声明部分，则变量 strName 可以被此模块中所有的过程所使用，但是不能被同一工程中不同的模块所含过程来使用。为了使变量可被工程中所有的过程所使用，则在变量前加上 Public 语句，如以下的示例：

Public strName As String

关于命名变量的详细信息，请参阅 Visual Basic 帮助中的“Visual Basic 命名规则”。

变量可以声明成下列数据类型中的一种：Boolean、Byte、Integer、Long、Currency、Single、Double、Date、String（变长字符串）、String * length （定长字符串）、Object 或 Variant。如果未指定数据类型，则 Variant 数据类型被赋予缺省。也可以使用 Type 语句来创建用户自定义类型。关于数据类型的详细信息，请参阅 Visual Basic 帮助中的“数据类型总结”。

可以在一个语句中声明几个变量。而为了指定数据类型，必须将每一个变量的数据类型包含进来。在下面的语句中，变量 intX、intY、与 intZ 被声明为 Integer 类型。

Dim intX As Integer, intY As Integer, intZ As Integer

在下面的语句中，变量 intX 与 intY 被声明为 Variant 类型 ；只有 intZ 被声明为 Integer 类型。

Dim intX, intY, intZ As Integer

在声明语句中，不一定要提供变量的数据类型。若省略了数据类型，则会将变量设成 Variant 类型。

使用 Public 语句

可以使用 Public 语句去声明公共模块级别变量。

Public strName As String

公有变量可用于工程中的任何过程。如果公有变量是声明于标准模块或是类模块中，则它也可以被任何引用到此公有变量所属工程的工程中使用。

使用 Private 语句

可以使用 Private 语句去声明私有的模块级别变量。

Private MyName As String

私有变量只可使用于同一模块中的过程。

注意   在模块级别中使用 Dim 语句与使用 Private 语句是相同的。不过使用 Private 语句可以更容易的读取和解释代码。

使用 Static 语句

当使用 Static 语句取代 Dim 语句时，所声明的变量在调用时仍保留它原先的值。

使用 Option Explicit 语句

在 Visual Basic 中可以简单地通过一个赋值语句来隐含声明变量。所有隐含声明变量都为 Variant 类型，而 Variant 类型变量比大多数其它类型的变量需要更多的内存资源。如果显示地声明变量为指定的数据类型，则应用程序将更有效。显示声明所有变量减少了命名冲突以及拼写错误的发生率。

如果不想使 Visual Basic 生成隐含声明，可以将 Option Explicit 语句放置于模块中所有的过程之前。这一个语句要求对模块中所有的变量做显示地声明。如果模块包含 Option Explicit 语句，则当 Visual Basic 遇到一个先前未定界的变量或拼写错误，它会发生编译时间的错误。

可以设置 Visual Basic 程序环境中的某个选项，使得自动在所有新的模块中包含 Option Explicit 语句。请参阅应用程序的文档来得知如何更改 Visual Basic 环境选项，请注意这个选项并不会改变已写好的存在的代码。

注意   必须显示地声明固定大小的数组与动态数组。

为自动化声明一个对象变量

当使用一个应用程序去控制另外一个应用程序的对象时，应该设置一个对于其它应用程序的类型库的引用。若设置一个引用，则可以根据它们最常指定的类型来声明对象变量。例如，如果是在 Microsoft Word 中，当对 Microsoft Excel 类型库做一引用设置时，可以在 Microsoft Word 中声明 Worksheet 类型的变量来表示 Microsoft Excel 中的 Worksheet 对象。

如果使用其它的应用程序去控制 Microsoft Access 对象，在多数情况下，可以根据它们最常指定的类型来声明对象变量。也可以使用关键字 New 去自动生成一个对象的新实例。然而，可能要指示它是 Microsoft Access 对象。例如，当在 Microsoft Visual Basic 里面声明一个对象变量去表示 Microsoft Access form 时，必须区别它是 Microsoft Access Form 对象或是 Visual Basic Form 对象。所以在声明变量的语句中必须要包含类型库的名称，如下面示例所示：

Dim frmOrders As New Access.Form

某些应用程序并不能识别特别的 Microsoft Access 对象类型。既使已经在这些应用程序中设置了一个对 Microsoft Access 类型库的引用，必须声明所有 Microsoft Access 对象变量为 Object 类型。不能使用 New 关键字去创建这个对象的新实例。下面的示例显示了，不能识别 Microsoft Access 对象类型的应用程序，如何去声明一个变量用来表示 Microsoft Access Application 对象。然后应用程序创建一个 Application 对象的实例。

Dim appAccess As Object

Set appAccess = CreateObject("Access.Application")

若想知道应用程序支持那些语法，请参阅应用程序的文档。


当设置属性时执行代码

可以创建 Property Let、Property Set 与 Property Get 过程且它们共享相同的名称。如此做之后，可以创建一组相关的过程且它们会一起执行。一旦某一名称被某个 Property 过程所用，此名称仍旧可以用来做为 Sub、Function 过程、变量或用户自定义类型的名称。

Property Let 语句允许创建设置属性值的过程。该示例是一个 Property 过程，它会对窗体上的位图创建一个反转的属性。以下是用来调用 Property Let 过程的语法：

Form1.Inverted = True

在窗体上反转位图的实际工作，其实是在 Property Let 过程里执行的：

Private IsInverted As Boolean

Property Let Inverted(X As Boolean)

IsInverted = X

If IsInverted Then

...

(statements)

Else

(statements)

End If

End Property

窗体级变量 IsInverted 保存属性的设置。如果声明为 Private，则用户只能使用 Property Let 过程改变它的设置。使用一个名称可以易于识别变量是用于某属性。

Property Get 过程是用来返回 Inverted 属性的当前状态：

Property Get Inverted() As Boolean

Inverted = IsInverted

End Property

属性过程使得在设置属性的值同时执行代码变得较容易。可以使用属性过程来执行下面步骤：

•	在设置一个属性前要先决定它的属性值。

•	在属性值设置之后，就要以此新的属性值为基础。


通过代码做循环

使用条件语句与循环语句（又称控制结构），可以写出生成决定与重复动作的 Visual Basic 代码。其它有用的控制结构，With 语句可让执行一系列的语句，而不用重新描述对象。

使用条件语句来生成决定

条件语句评估一个条件式是 True 或 False，然后根据结果来执行一贯或多个指定的语句。通常，条件式是一个表达式，它会使用比较运算符来和其它的比较一个值或变量。

选择一个条件语句来使用

•	If...Then...Else：当条件是 True 或 False 时会生成分支

•	Select Case：从一个条件设置中选择某一分支

使用循环去重复代码

循环允许重复执行一组语句。某些循环重复执行语句直到条件为 False；而有些循环重复执行语句直到条件为 True。也有某些循环执行一指定次数的语句或是集合中的每一个对象。

选择一个循环来使用

•	Do...Loop：循环重复执行语句直到或当条件为 True 时

•	For...Next：使用一个计数器来运行一指定次数的语句

•	For Each...Next：在集合中对每个对象的一组的语句重复

在同一对象中运行几个语句

在 Visual Basic 中，通常在执行它的某一个方法或改变它的属性之前必须指定对象。可以使用 With 语句去指定一完整系列的语句给某一对象。

•	With：在同一对象中运行一系列的语句。


使 For...Next 循环更加快速

整型所占用的内存比 Variant 数据类型少，并且有稍快的更新速度。然而，此不同处只有在执行数千个操作时才会引人注目。例如：

Dim CountFaster As Integer	' 第一种情况，使用 Integer。

For CountFaster = 0 to 32766

Next CountFaster

Dim CountSlower As Variant	'第二种情况，使用 Variant。

For CountSlower = 0 to 32766

Next CountSlower

在上述的示例中，第一种情况运行时间比第二种情况运行时间稍少些。然而，如果 CountFaster 的值超过 32,767 则会生成一个错误。为了处理此问题，可以将 CountFaster 更改成 Long 数据类型如此可以接受更大范围的整数。一般来说，较小的数据类型，在更新时所用的时间少。Variants 则会稍慢于它对等的各种数据类型。


有效率地传递参数

所有的参数传递给过程都是按地址的，除非有特别指定的别的方法。此法是比较有效率的，因为在过程内所有按地址传递的参数所花费的传递时间与空间的总数（4 字节）都是一样的，而不管参数的数据类型。

可以按值的来传递参数，只要在过程的声明中包含 ByVal 关键字。按值传递参数会在过程内部消耗掉 2 至 16 字节，此取决于参数的数据类型。对于大的数据类型按值传递会比小的数据类型需要稍长的时间。因此，String 和 Variant 数据类型通常不按值来传递参数。

使用按值的方法时会将原来的变量复制一份，当做参数传递过去。改变过程内部的参数时将不会影响到原来的变量。例如：

Function Factorial (ByVal MyVar As Integer)	' Function declaration.

MyVar = MyVar - 1

If MyVar = 0 Then

Factorial = 1

Exit Function

End If

Factorial = Factorial(MyVar) * (MyVar + 1)

End Function

' 调用因子与变量 S。

S = 5

Print Factorial(S)	' 显示 120 （5 的因子）。

Print S	'显示 5。

在函数的声明时若未包含 ByVal，则上述的 Print 语句将会显示出 1 和 0。这是因为 MyVar 会参考到变量 S，而它会一直减 1 直到其值为 0。

因为 ByVal 生成了参数的复制，所以它允许传递一个变体型 给上述的 Factorial 函数。若过程所声明参数是别的数据类型，将不能按地址来传递一个变体型。


从函数中返回字符串

某些函数具有两种版本：一种返回 Variant 数据类型，而另一种返回 String 数据类型。Variant 版本较为方便因为变形体会自动地处理不同类型间的传输。它们同时也允许 Null 通过表达式来发送。String 版本较具有效率，因为它们使用较少的内存。

当有下列之情形时可考虑使用 String 版本：

•	程序很大并且使用很多的变量。

•	将数据直接写到随机存取文件中。

当在函数名称后面加上一个美元符号（$）时，下列的函数会对于 Sting 变量返回一个数值。这些函数若不加上美元符号用法与语法与 Variant 相等。

Chr$	ChrB$	*Command$
CurDir$	Date$	Dir$
Error$	Format$	Hex$
Input$	InputB$	LCase$
Left$	LeftB$	LTrim$
Mid$	MidB$	Oct$
Right$	RightB$	RTrim$
Space$	Str$	String$
Time$	Trim$	UCase$
* 并非在所有的应用程序中都是变量。


了解条件式编译

可以使用条件编译的方式，来选择性地运行代码块，例如，调试语句会去比较对于相同的程序任务使用不同方法的速度，或是通过不同的语言来本地化一个应用程序。

可利用 #Const 指令在代码中声明一个条件编译常数。并且可以利用#If...Then...#Else 指令来指示代码块做条件编译。下列示例中是以 conDebug 变量为基础，来运行调试代码或者产生代码。

' 在声明区声明公用编辑常数。

#Const conDebug = 1

Sub SelectiveExecution()

#If conDebug = 1 Then

.	'用调试语句运行代码。

.

.

#Else

.	' 运行常规代码。

.

.

#End If

End Sub


了解变量的存活期

变量保留其值的这段时间，称为生存周期。变量的值可能在整个生存周期都在改变，但它仍然保留着一些值。当变量失去了范围之后，它也就不再保存着任一个值。

当过程开始运行时，所有的变量都会被初始化。一个数值变量会初始化成 0，变长字符串被初始化成零长度的字符串 ("")，而定长字符串会被填满 ASCII 字符码 0 所表示的字符或是 Chr(0)。Variant变量会被初始化成 Empty。用户自定义类型中每一个元素变量会被当成个别变量来做初始化。

当声明一个对象变量时，内存中虽有保留空间，但它的值会被设置成 Nothing，直到利用 Set 语句对它指定一个对象引用。

如果在代码的运行期间，变量的值一直没有改变，则它会继续保有它的初始值直到它丢失范围为止。

Dim 语句声明过程的级别变量将保留一个值，直到此过程退出为止。如果该过程调用其它的过程，则在这些过程正在运行的同时，属于调用者过程的变量也保留它的值。

如果过程的级别变量是用 Static 关键字来声明的，则只要代码正在任何模块中运行此变量仍会保留它的值。而当所有的代码都完成运行后，变量会失去它的范围和它的值。所以它的存活期和模块级别的变量是一样的。

模块级别的变量与静态变量是不同的。在标准模块或类模块中变量会保留它的值，直到停止运行代码。在对象类模块中，只要仍有一个属于此对象类的实例存在，则变量会一直保留它的值。模块级别的变量会一直占用内存资源，直到重新设置它们的值，所以只有在必要时才使用它们。

如果在 Sub 或 Function 语句前加上 Static 关键字，则在此过程中所有过程级别的变量的值被保留在调用期间。


了解命名参数与可选的参数

当调用 Sub 或 Function 过程时，可以根据位置来提供参数，也就是出现在过程定义时的顺序，或者根据名称来提供参数，如此就不用管它的位置。

例如，下面的 Sub 程序接受三个参数：

Sub PassArgs(strName As String, intAge As Integer, dteBirth As Date)

Debug.Print strName, intAge, dteBirth

End Sub

可以在正确的位置上提供其参数来调用该过程，每个参数之间都以逗点来区隔，如下列的示例所示：

PassArgs "Mary", 29, #2-21-69#

也可以有提供命名参数的方式来调用过程，每个参数之间也是以逗点来间隔。

PassArgs intAge:=29, dteBirth:=#2/21/69#, strName:="Mary"

命名参数是由参数名称接着冒号和一个等号（:=）最后加上参数值所组成。

命名参数在调用具有可选的参数过程时显得特别有用。如果使用命名参数，则不必利用逗号去区分出失去位置的参数。使用命名参数可以很容易的追踪出传递和省略了那些参数。

在过程的定义中，可选的参数前会有一个 Optional 关键字。在过程的定义中也可以指定一个缺省值赋予可选的参数。例如：

Sub OptionalArgs(strState As String, Optional strCountry As String = "USA")

. . .

End Sub

当在调用具有可选的参数的过程时，可以选择是否要对可选的参数给于一个值（如果没有的话则会采用缺省值）。如果没有指定缺省值，则此参数可以是属于所指定类型的任何变量。

下列过程包含一个可选的参数，varCountry 变量。而 IsMissing 函数可以决定一个可选的参数是否已经传递给过程。

Sub OptionalArgs(strState As String, Optional intRegion As Integer, _

Optional strCountry As String = "USA")

If IsMissing(intRegion) And IsMissing(strCountry) Then

Debug.Print strState

ElseIf IsMissing(strCountry) Then

Debug.Print strState, intRegion

ElseIf IsMissing(intRegion) Then

Debug.Print strState, strCountry

Else

Debug.Print strState, intRegion, strCountry

End If

End Sub

可以使用命名参数来调用上述程序；如下示例所示：

OptionalArgs strCountry:="USA", strState:="MD"

OptionalArgs strState:= "MD", intRegion:=5


了解对象、属性、方法和事件

对象代表应用程序中的元素，比如，工作表、单元格、图表、窗体，或是一份报告。在 Visual Basic 的代码中，可在使用对象的任一方法或改变它的属性之一的值之前，必须去识别对象。

对象集合是一个包含几个其他对象的对象，而这些对象通常但并不总是相同的类型。例如，在 Microsoft Excel 中的 Workbooks 对象包含了所有已打开的 Workbook 对象。而 Visual Basic 中的 Forms 集合则包含了所有在它所属应用程序中的 Form 对象。

集合中的项目可以通过号码或名称来做识别。例如，在下面的过程中 Workbooks(1) 会识第一个打开的 Workbook 对象。

Sub CloseFirst()

Workbooks(1).Close

End Sub

下面的过程使用一个指定为字符串的名称来识别 Form 对象。

Sub CloseForm()

Forms("MyForm.frm").Close

End Sub

如果对象共享共同的方法，则可以操作整个对象集合。例如，下列的过程会关闭所有打开的窗体。

Sub CloseAll()

Forms.Close

End Sub

方法指的是对象能执行的动作。例如，Add 是属于 ComboBox 对象的一个方法，因为它会增加一个新项到下拉式列表框中。

下面的程序使用 Add 方法，增加一个新的工程到 ComboBox 中。

Sub AddEntry(newEntry as String)

Combo1.Add newEntry

End Sub

属性是一个对象的属性，它定义了对象的特征，诸如大小、颜色或屏幕位置，或某一方面的行为，诸如对象是否有激活或可见的。可以通过修改对象的属性值来改变对象的特性。

若要设置属性值，则在对象的引用后面加上一个复合句，它是由属性名加上等号 (=) 以及新的属性值所组成的。例如，下面的过程通过设置窗体中的 Caption 属性来更改 Visual Basic 窗体的标题。

Sub ChangeName(newTitle)

myForm.Caption = newTitle

End Sub

有些属性并不能设置。每一个属性的帮助主题，会指出是否可以设置此属性（读与写），或只能读取此属性（只读），还是只能写入此属性（只写）。

可以通过属性的返回值，来检索对象的信息。下列的过程使用一个消息框来标题，它显示在当前活动窗体顶部。

Sub GetFormName()

formName = Screen.ActiveForm.Caption

MsgBox formName

End Sub

事件是一个对象可以辨认的动作，像单击鼠标或按下某键等，并且可以写某些代码针对此述动作来做响应。用户做动作或程序代码的结果可能导致事件的发生，或是由系统引发。

返回对象

每个应用程序都有返回它所包含的对象的方法，然而这些对象并非都相同，所以必须参考所使用的应用程序的对象或者集合的帮助主题，才会知道如何返回对象。


了解自动化

自动化（从前的 OLE 自动化）是部件对象模式（COM）的特征，它是一种工业标准技术，其应用程序可用来显露其对象为发展工具、宏语言和其他支持自动化的应用程序。例如，电子数据表应用程序能显露工作表、图表、单元格或单元格范围等每个不同类型的对象。一个字处理器可能显露如应用程序、文档、段落、句子、书签或选项的对象。

当一个应用程序支持自动化时，它所显露的对象应用程序就可以被 Visual Basic 访问。使用 Visual Basic 调用对象的方法或者取得并设置对象的属性，来操作这些对象。例如，可以创建命名为 MyObj 的自动化对象，并利用下面所写的代码来访问此对象：

MyObj.Insert "Hello, world."	' 放置文本。

MyObj.Bold = True	' 文本格式。

If Mac = True	'检查平台常数

MyObj.SaveAs  "HD:\WORDPROC\DOCS\TESTOBJ.DOC"	'保存对象(Macintosh)。

Else

MyObj.SaveAs  "C:\WORDPROC\DOCS\TESTOBJ.DOC"	'保存对象。

(Windows)

使用下面的函数访问自动化对象：

函数	描述
CreateObject	创建指定类型的新对象。
GetObject	从文件中检索对象。
若要知道应用程序所支持的属性与方法的详细资料，请参阅应用程序文档。应用程序所支持的对象、函数、属性与方法通常被定义于该应用程序的对象库中。


了解参数数组

参数数组可用来传递数组的参数给过程。所以当定义过程时就不用知道数组中的元素个数。

使用 ParamArray 关键字来指示一个参数数组。而此数组必须被声明为 Variant 类型的数组，并且此数组必须是过程定义中最后面那个参数。

下面的示例可告诉如何定义一个包含参数数组的过程。

Sub AnyNumberArgs(strName As String, ParamArray intScores() As Variant)

Dim intI As Integer

Debug.Print strName; "    Scores"

' 用 UBound 函数决定数组的上限。

For intI = 0 To UBound(intScores())

Debug.Print "          "; intScores(intI)

Next intI

End Sub

下面的示例可告诉如何调用这个过程。

AnyNumberArgs "Jamie", 10, 26, 32, 15, 22, 24, 16

AnyNumberArgs "Kelly", "High", "Low", "Average", "High"


了解范围与可见性

范围指的是变量、常数或过程被其它过程使用的可用性。有三个范围级别：过程的级别、私有模块级别和公共模块级别。

当声明一个变量时已决定了它的范围。将所有的变量做显示地声明是一个好主意，它可以避免不同范围中变量之间的命名冲突错误。

定义过程的级别范围

定义于程序内变量或常数是不能从过程外看到的。只有声明此变量的过程可以使用它们。在下面的示例中，第一个过程显示一个包含字符串的信息框。而第二个过程则显示一个空白的信息框，因为变量 strMsg 对于第一个程序是本地的。

Sub LocalVariable()

Dim strMsg As String

strMsg = "This variable can't be used outside this procedure."

MsgBox strMsg

End Sub

Sub OutsideScope()

MsgBox strMsg

End Sub

定义私有模块级别的范围

在模块的声明部分中，可以定义模块级别变量和常数。模块级别变量可以是私有或公有的。在工程中，公有变量对于所有模块中的所有过程是可用的；而私有变量只对于属模块中的过程是可用的。由 Dim 语句在声明部分中所声明变量，其范围的缺省值为私有。然而，若在变量的前面加上 Private 关键字，则其在代码中的范围将更为明显。

在下面的示例中，字符串变量 strMsg 可被定义在此模块中的任何过程使用。 当第二个过程被调用时，它会在对话框中显示出字符串变量 strMsg 的内容。

' 添加下面的到模块的声明部分。

Private strMsg sAs String

Sub InitializePrivateVariable()

strMsg = "This variable can't be used outside this module."

End Sub

Sub UsePrivateVariable()

MsgBox strMsg

End Sub

注意   公共过程若是在标准模块或对象类模块中的话，则任何引用工程都可以使用它。为了限制当前工程中模块内的所有过程，可以在模块的 声明部分加上 Option Private Module 语句。如此则公有变量和过程仍然可被当前工程中的其它过程所使用，但不能被引用工程所使用。

定义公共模块级别的范围

如果声明一个模块级别变量为公用，它将可被工程中的所有过程使用。在下面的示例中，字符串变量 strMsg 可被工程中模块的所有过程使用。

' 包括在模块的声明部分中。

Public strMsg As String

除了事件过程之外，所有过程的缺省值都是公共的。当 Visual Basic 创建一个事件过程时，在过程的声明前面会自动的加上 Private 关键字。对于其它的过程来说，若不想使它为公共的，必须利用 Private 关键字来显示地声明过程。

可以从引用的工程中，去使用它定义在标准模块或类模块中的公共过程、变量，以及常数。然而，必须先设置一个对它们所定义工程的引用。

公共过程、变量以及常数若不是定义在标准模块或类模块中，例如窗体模块或报表模块，都不可以被引用工程所使用，因为这些模块对于所驻留的工程而言是私有的。


了解变体

当声明常数、变量或参数时，若无指定数据类型则会自动的指定成 Variant 数据类型。声明成 Variant 数据类型的变量包含有字符串、日期、时间、Boolean或数值，并且它们自动包含的值会转换。数值型 Variant 值需要 16 字节的内存（此点只有在大型的过程或复杂的模块才较具意义），并且在访问时会比任何显示地定义的数据类型来得慢。很少使用 Variant 数据类型来表示常数字符串 Variant 值需要 22 字节的内存。

下面的语句创建一个 Variant 变量：

Dim myVar

Dim yourVar As Variant

theVar = "This is some text."

最后的语句中并没有显示地声明变量 theVar，但是会声明隐含性的或自动性的变量。所谓隐含性的声明变量就是指定成 Variant 数据类型。

提示   如果指定了变量或参数的数据类型，但却使用了错误的数据类型，如此则会发生数据类型错误。不管使用隐含性的变量（Variant 数据类型）或是显示地声明所有的变量并指定数据类型，都要避免数据类型错误。一般较喜欢用后者。


了解 Visual Basic 语法

Visual Basic 帮助主题中有关方法、语句或是Function 过程的语法，展示了正确使用语句、方法或是函数所需要的元素。在这个主题中的示例，解释了如何去解释最常见的语法元素。

Activate 方法的语法

object.Activate

在 Activate 方法语法中，斜体字 object 是一个所提供信息的占位符，在此例中的代码会返回一个对象。在键入粗体字时必须完全象上面的例子一样。例如，下面的过程会在活动的文档中激活第二个窗口。

Sub MakeActive()

Windows(2).Activate

End Sub

MsgBox 函数的语法

MsgBox(prompt[, buttons] [, title] [, helpfile, context])

在 MsgBox 函数的语法中，粗体的斜体字是此函数的命名参数。方括号所包含的参数是选择性的。（在 Visual Basic 码中不用键入方括号）。在 MsgBox 函数中，唯一必须提供的参数（prompt）是做为提示的文本。

在代码中可以利用位置或名称来指定函数与方法的参数。若利用位置来指定参数，则必须根据语法中的顺序，利用逗号来分隔每一个参数，例如：

MsgBox "Your answer is correct!",0,"Answer Box"

若以名称来指定参数，则须使用参数名称或跟着冒号与等号（:=），最后再加上参数值。可以任何的顺序来指定命名参数，例如：

MsgBox Title:="Answer Box", Prompt:="Your answer is correct!"

函数以及某些方法的语法会利用圆括号将参数封闭起来。这些函数和方法会返回值，所以必须用圆括号将参数封闭起来，才可以赋值给变量。如果忽略返回值或是没有传递所有的参数，则可以不用圆括号。方法若不返回值，则不用将参数用圆括号封闭起来。上述准则不管是使用命名参数或位置参数都适用。

在下面的示例中，MsgBox 函数的返回值是一个号码，它被存储在变量 myVar 中，以用来指示选择的按钮。因为需要用到返回值，所以调用时必须使用圆括号。而另一个消息框则是用来显示变量的值。

Sub Question()

myVar = MsgBox(Prompt:="I enjoy my job.", _

Title:="Answer Box", Buttons:="4")

MsgBox myVar

End Sub

选项语句的语法

Option Compare {Binary | Text | Database}

在 Option Compare 语句的语法中，大括号和垂直线指示三项中的强制性选择。（在 Visual Basic 的语句中不用键入大括号）。例如，下列的语句指出在模块中，字符串的比较是根据文本的排序顺序而不区分大小写。

Option Compare Text

Dim 语句的语法

Dim varname[([subscripts])] [As type] [, varname[([subscripts])] [As type]] . . .

在 Dim 语句的语法中，Dim 是必备的关键字。而唯一必备的元素是 varname（变量名）。例如，下列的语句创建三个变量：myVar、nextVar 和 thirdVar。它们会自动被声明成 Variant 变量。

Dim myVar, nextVar, thirdVar

下面的示例声明了一个为 String 的变量。它包含了数据类型，如此可以节省内存并且帮助从代码中找出错误。

Dim myAnswer As String

若在一个语句中声明好几个变量，则必须包含每一个变量的数据类型。变量在声明时若少了数据类型，则会自动的声明成 Variant 。

Dim x As Integer, y As Integer, z As Integer

在下列的语句中，x 与 y 都被指定成 Variant 数据类型，只有 z 被指定成 String 数据类型。

Dim x, y, z As Integer

如果声明一个数组变量，则必须包含圆括号，但下标则是可选的。下列的语句中定义了一个动态数组 myArray。

Dim myArray()


使用数组

可以声明一个数组来代表一群具有相同数据类型的值。数组是单一类型的变量，它具有很多的隔室来存储很多值，而常规的变量只有一个存储隔室，所以只能存储一个值。但要引用所保持的所有值时，可以引用整个数组或是只引用数组的个别元素。

例如，若要存储一年中每天的支出，可以声明一个具有 365 个元素的数组变量，而不是 365 个变量。数组中的每一个元素都包含一个值。下列的语句声明数组变量 curExpense 具有 365 个元素。按照缺省规定，数组的索引是从零开始，所以此数组的上标界是 364 而不是 365。

Dim curExpense(364) As Currency

若要设置个别元素的值，必须指定元素的索引。下面的示例对于数组中的每个元素都赋予一个初始值 20。

Sub FillArray()

Dim curExpense(364) As Currency

Dim intI As Integer

For intI = 0 to 364

curExpense(intI) = 20

Next

End Sub

更改数组的底层绑定

可以在模块的顶部使用 Option Base 语句，将第一个元素的缺省索引值从 0 改成 1。在下面的示例中，Option Base 语句改变数组第一个组件的索引值，接着 Dim 语句声明数组变量 curExpense 具有 365 个元素。

Option Base 1

Dim curExpense(365) As Currency

也可以利用 To 子句来对数组的底层绑定做显示地声明，如下面的示例所示：

Dim curExpense(1 To 365) As Currency

Dim strWeekday(7 To 13) As String

在数组中存储 Variant 值

有两种方式可以创建 Variant 值的数组。第一种方式是声明 Variant 数据类型的数组，如下面的示例所示：

Dim varData(3) As Variant

varData(0) = "Claudia Bendel"

varData(1) = "4242 Maple Blvd"

varData(2) = 38

varData(3) = Format("06-09-1952", "General Date")

另一种方式是指定 Array 函数所返回的数组为一个 Variant 变量，如下示例所示。

Dim varData As Variant

varData = Array("Ron Bendel", "4242 Maple Blvd", 38, _

Format("06-09-1952", "General Date"))

对于元素类型为 Variant 的数组，可以利用索引来识别各元素，而不管用何种方式创建此数组。例如，下列的语句可以被加到上述的示例中。

MsgBox "Data for " & varData(0) & " has been recorded."

使用具有多重维数的数组

在 Visual Basic 中最多可以声明变量到 60 个维数。例如，下列的语句声明一个 5 乘 10 的两维数组。

Dim sngMulti(1 To 5, 1 To 10) As Single

如果将数组想成矩阵，则第一个参数代表行，而第二个参数代表列。

可以使用嵌套的 For...Next 语句去处理多重维数数组。下列的过程将一个两维数组的所有元素都填入 Single 值。

Sub FillArrayMulti()

Dim intI As Integer, intJ As Integer

Dim sngMulti(1 To 5, 1 To 10) As Single

' 用值填入数组。

For intI = 1 To 5

For intJ = 1 To 10

sngMulti(intI, intJ) = intI * intJ

Debug.Print sngMulti(intI, intJ)

Next intJ

Next intI

End Sub


使用常数

您的代码可能包含经常出现的常数值，或可能某些数值是非常难以记忆并且无明确意义的。使用常数可使代码更容易读取与维护。常数是一个有意义的名称，它可以替换一个号码或字符串而且值不会改变。不能修改一个常数或如同操作变量般的赋一个新值给常数。

有三种类型的常数：

•	固有的常数或系统定义的常数是由应用程序与控件提供的。提供对象库的其它的应用程序如 Microsoft Access, 、Microsoft Excel Microsoft Project 以及 Microsoft Word ，也提供常数列表，这些常数可与它们所属的对象，方法以及属性等一起使用。可以获得个别为对象浏览器中的对象库所提供的常数列表。

Visual Basic 的常数都列在  Visual Basic for Applications类型库以及 Data Access Object（DAO）程序库之中。

注意   Visual Basic 仍会对之前的 Visual Basic 或 Visual Basic for Applications 所定义的常数做识别。可以提升常数到 Object Browser 之中。在 Object Browser 中所列的常数，不用在的应用程序中声明。

•	符号或用户自定义的常数都是利用 Const 语句来声明。

•	条件编译常数都是利用 #Const 语句来声明。

在早期版本的 Visual Basic 中，常数的名称都是用大写字符串加上一横下划线而成，例如：

TILE_HORIZONTAL

固有的常数当前被限定来避免一个混淆，即具有相同名称的常数存在于多个对象库中，而这些常数可能具有不同的值所造成的。有两种方法来限定常数名称：

•	通过前缀

•	通过库引用

用前缀限定常数

所有对象提供的固有的常数都以混合大小写格式显示，以两个字符为前缀来指出定义这些常数的对象库。例如，由Visual Basic for Applications 对象库而来的常数都会以“vb”为开端；而由 Microsoft Excel 对象库而来的常数都会以“xl”为开端。下面的示例解释了如何应用前缀字符于自定义控件，其通常是与类型库相关的。

•	vbTileHorizontal

•	xlDialogBorder

用库引用限定常数

也可利用下列的语法来限定对常数的引用：

[libname.] [modulename.]constname

限定常数的语法包含下面部分：

单元	描述
libname	可选的。定义此常数的类型库。对于多数的自定义控件 (在Macintosh)中不可用来说，它也是控件的类名。如果忘掉了控件的类名，可将鼠标的光标移动到工具箱中此控件的位置。该类名会显示在“工具提示”中。
modulename	可选的。定义此常数的类型库，所包含的模块的名称。可以利用“对象浏览器”来找到模块的名称。
constname	在类型库中定义的常数名称。
例如：

Threed.LeftJustify


有效的使用数据类型

除非有其它的指定，否则未声明变量会被指定成 Variant 数据类型。这个数据类型可使写程序变得较容易，但它并不总是使用中最有效率的数据类型。

若有下列情形时必须考虑使用其它的数据类型：

•	程序非常大并且使用很多变量。

•	程序的执行速度必须尽可能的快。

•	将数据直接写到随机存储文件中。

除了 Variant 之外，支持的数据类型包括 Byte、Boolean、Integer、Long、Single、Double、Currency、Decimal、Date、Object 以及 String。可使用 Dim 语句去声明一个指定类型的变量，例如：

Dim X As Integer

上述语句声明变量 X 是一个整型，其范围介于 -32,768 到 32,767 之间。如果试着去设置超出此范围的数值给 X ，则会有错误发生。如果试着去指定一个分数给 X，则此分数会自动四舍五入。例如：

X = 32768	' 产生错误。

X = 5.9	' 设置 x = 6。


使用 Do...Loop 语句

可以使用 Do...Loop 语句去运行语句的块，而它所用掉的时间是不确定的。当条件为 True 或直到条件变成 True 时，此语句会一直重复。

直到条件为 True 时重复语句

当使用 While 关键字去检查 Do...Loop 语句中的条件时，可以有两种方法。可以在进入循环之前检查条件式，也可以在循环至少运行一次之后才检查条件式。

在下面的 ChkFirstWhile 过程中，在进入循环之前检查条件。如果将 myNum 的值由 20 替换成 9，则循环中的语句将永远不会运行。 在ChkLastWhile 过程中，在条件变成 False 之前循环中的语句只执行一次。

Sub ChkFirstWhile()

counter = 0

myNum = 20

Do While myNum > 10

myNum = myNum - 1

counter = counter + 1

Loop

MsgBox "The loop made " & counter & " repetitions."

End Sub

Sub ChkLastWhile()

counter = 0

myNum = 9

Do

myNum = myNum - 1

counter = counter + 1

Loop While myNum > 10

MsgBox "The loop made " & counter & " repetitions."

End Sub

直到条件变成 True 才重复语句

当使用 Until 关键字去检查 Do...Loop 语句中的条件时，可以使用两种方法。可以在进入循环之前检查条件（如同 ChkFirstUntil 过程所示），也可以在循环至少运行一次之后才检查条件（如同 ChkLastUntil 过程所示）。当条件仍然为 False 时，循环继续。

Sub ChkFirstUntil()

counter = 0

myNum = 20

Do Until myNum = 10

myNum = myNum - 1

counter = counter + 1

Loop

MsgBox "The loop made " & counter & " repetitions."

End Sub

Sub ChkLastUntil()

counter = 0

myNum = 1

Do

myNum = myNum + 1

counter = counter + 1

Loop Until myNum = 10

MsgBox "The loop made " & counter & " repetitions."

End Sub

从循环内退出 Do...Loop 语句

可以使用 Exit Do 语句来退出 Do...Loop 语句。例如，为了退出无穷循环，可以在 If...Then...Else 语句或是 Select Case 语句的 True 语句块中使用 Exit Do 语句。如果条件为 False，则循环会象通常那样运行。

在下面的示例中，myNum 被赋予一个会造成无穷循环的值。而 If...Then...Else 语句会去检查这个情况然后退出，以避免无穷循环。

Sub ExitExample()

counter = 0

myNum = 9

Do Until myNum = 10

myNum = myNum - 1

counter = counter + 1

If myNum < 10 Then Exit Do

Loop

MsgBox "The loop made " & counter & " repetitions."

End Sub

注意   可以按 ESC 或 CTRL+BREAK 键来终止无穷循环。


使用 For...Next 语句

可以使用 For...Next 语句去重复一个语句块，而它的次数的数字是指定的。For 循环使用一个计数变量，当重复每个循环时它的值会增加或减少。

下面的过程会让计算机发出哔声 50 次。For 语句会指定计数变量 x 的开始与结束值。Next 语句会将计数变量的值加 1。

Sub Beeps()

For x = 1 To 50

Beep

Next x

End Sub

使用 Step 关键字，可以由所指定的值增加或减少计数变量。在下面的示例中，计数变量 j 会在每次循环重复时加上 2。当循环完成时，total 的值为 2、4、6、8 和 10 的总合。

Sub TwosTotal()

For j = 2 To 10 Step 2

total = total + j

Next j

MsgBox "The total is " & total

End Sub

为了减少计数变量的值，可以使用负的 Step 值。为了减少计数变量的值，必须指定一个小于开始值的结束值。在下面的示例中，计数变量 myNum 会在每次循环重复时减去 2。当循环完成时，total 的值为 16、14、12、10、8、6、4 和 2 的总合。

Sub NewTotal()

For myNum = 16 To 2 Step -2

total = total + myNum

Next myNum

MsgBox "The total is " & total

End Sub

注意  在 Next 语句后面不必包含计数变量的名称。上述的示例中，因为要具有可读性才加上计数变量的名称。

可以在计数变量到达它的结束值之前，使用 Exit For 语句来退出 For...Next 语句。例如，当错误发生时，可以使用在 If...Then...Else 语句或是 Select Case 语句的 True 语句块中的 Exit For 语句，它是专门用来检查此错误的。如果没有错误发生，则 If...Then...Else 语句的值为 False，循环会象预期那样的运行。


使用 For Each...Next 语句

For Each...Next 语句会重复一个语句块，而它是作用于集合中的每个对象或是数组中的每个元素。当循环执行一次则 Visual Basic 会自动设置一个变量。例如，下面的过程会关闭所有的窗体，除了窗体包含的过程正在运行以外。

Sub CloseForms()

For Each frm In Application.Forms

If frm.Caption <> Screen. ActiveForm.Caption Then frm.Close

Next

End Sub

下面的代码会在数组的每个元素中循环，并且将每个值设置成它的索引变量 I 的值。

Dim TestArray(10) As Integer, I As Variant

For Each I In TestArray

TestArray(I) = I

Next I

对某范围的单元格做循环

可以使用 For Each...Next 循环对某范围的单元格做循环。下面的过程会对于 Sheet1 中的 A1:D10 范围做循环，并将任何绝对值小于 0.01 的号码设为 0。

Sub RoundToZero()

For Each myObject in myCollection

If Abs(myObject.Value) < 0.01 Then myObject.Value = 0

Next

End Sub

在完成前退出 For Each...Next 循环

可以使用 Exit For 语句来退出 For Each...Next 循环。例如，当错误发生时可以在 If...Then...Else 语句或是 Select Case 语句的 True 语句块中使用 Exit For 语句，它是专门用来检查此错误的。如果没有错误发生，If...Then...Else 语句的值为 False，则循环会象预期那样运行。

下面的示例，测试在 A1:B5 范围内找出第一个不含数值的单元。如果有找到此类单元，则会有信息显示并用 Exit For 语句退出循环。

Sub TestForNumbers()

For Each myObject In MyCollection

If IsNumeric(myObject.Value) = False Then

MsgBox "Object contains a non-numeric value."

Exit For

End If

Next c

End Sub


使用 If...Then...Else 语句

根据条件的值，可使用 If...Then...Else 语句运行指定的语句或一个语句块。If...Then...Else 语句可根据需要嵌套多级。然而，为了可读性可能会使用 Select Case 语句而不使用多嵌套级的 If...Then...Else 语句。

如果条件为 True 则运行语句

当条件为 True 时，若只要执行一个语句，则可以使用单行的 If...Then...Else 语法。下列的示例显示了单行语法，省略了 Else 关键字：

Sub FixDate()

myDate = #2/13/95#

If myDate < Now Then myDate = Now

End Sub

为了运行多行代码，必须使用多行的语法。而此语法包含 End If 语句，如同下面示例所示：

Sub AlertUser(value as Long)

If value = 0 Then

AlertLabel.ForeColor = "Red"

AlertLabel.Font.Bold = True

AlertLabel.Font.Italic = True

End If

End Sub

如果条件为 True，运行某些语句；条件为 False，运行其它的语句

使用 If...Then...Else 语句可以定义两个可执行的语句块：其中一个块会在条件为True 时执行；而另一个块会在条件为 False 时执行。

Sub AlertUser(value as Long)

If value = 0 Then

AlertLabel.ForeColor = vbRed

AlertLabel.Font.Bold = True

AlertLabel.Font.Italic = True

Else

AlertLabel.Forecolor = vbBlack

AlertLabel.Font.Bold = False

AlertLabel.Font.Italic = False

End If

End Sub

如果第一个条件为 False 时，测试第二个条件

如果第一个条件为 False，则可以在 If...Then...Else 语句中加上 ElseIf 语句来测试第二个条件。例如，下列的函数过程根据工作分类来计算奖金。如果所有 If 和 ElseIf 语句中条件都是 False，则会运行跟在 Else 语句之后的语句。

Function Bonus(performance, salary)

If performance = 1 Then

Bonus = salary * 0.1

ElseIf performance = 2 Then

Bonus = salary * 0.09

ElseIf performance = 3 Then

Bonus = salary * 0.07

Else

Bonus = 0

End If

End Function


在代码中使用括号
在代码中使用圆括号

Sub 过程、内置语句、以及某些方法不会返回值，所以它的参数不必用圆括号封闭起来。例如：

MySub "stringArgument", integerArgument

Function 过程、内置函数、以及某些方法会返回值，但也可以忽略这些返回值。如果忽略这些返回的值，不必包括圆括号。调用函数时只要如同调用 Sub 过程即可。省略圆括号，列出所需的参数，并且不赋值函数给变量。例如：

MsgBox "Task Completed!", 0, "Task Box"

若要使用函数的返回值，则用圆括号封闭参数，如下示例所示：

Answer3 = MsgBox("Are you happy with your salary?", 4, "Question 3")

Sub 或 Function 过程中的语句可以使用命名参数的来传递值给调用的过程。不管是否使用命名参数，圆括号的使用准则一样适用。当使用命名参数时，可以用任何的顺序来列出参数名称，并且可以省略可选的参数。命名参数后面总是接着冒号和等号（:=），最后加上参数值。

下面的示例使用命名参数来调用 MsgBox 函数，但省略了返回值：

MsgBox Title:="Task Box", Prompt:="Task Completed!"

下面的示例使用命名参数来调用 MsgBox 函数，并且指定返回值给变量answer：

answer3 = MsgBox(Title:="Question 3", _

Prompt:="Are you happy with your salary?", Buttons:=4)


使用 Select Case 语句

当一个表达式与几个不同的值相比较时，可以使用 Select Case 语句来交替使用在 If...Then...Else 语句中的 ElseIf。If...Then...Else 语句会计算每个 ElseIf 语句的不同的表达式，在控制结构的顶部，Select Case 语句只计算表达式一次。

在下面的示例中，Select Case 语句会计算发送给此过程的参数performance。请注意，每个 Case 语句可以包含一个以上的值，一个值的范围，或是一个值的组合以及比较运算符。如果 Select Case 语句与Case 语句的任何值相匹配，则可选的 Case Else 语句运行。

Function Bonus(performance, salary)

Select Case performance

Case 1

Bonus = salary * 0.1

Case 2, 3

Bonus = salary * 0.09

Case 4 To 6

Bonus = salary * 0.07

Case Is > 8

Bonus = 100

Case Else

Bonus = 0

End Select

End Function


使用 With 语句

With 语句让您指定一系列的语句中的一个对象或用户自定义类型。With 语句使过程运行得更快并且帮助避免反复的键入代码。

下面的示例将某一范围的单元格都填入 30，字体使用黑体格式，并将内部单元格颜色设置成黄色。

Sub FormatRange()

With Worksheets("Sheet1").Range("A1:C10")

.Value = 30

.Font.Bold = True

.Interior.Color = RGB(255, 255, 0)

End With

End Sub

可以将 With 语句嵌套的使用，如此将更具有效率。下面的示例在 A1 这个存储单元格中插入一个公式，然后格式化字体。

Sub MyInput()

With Workbooks("Book1").Worksheets("Sheet1").Cells(1, 1)

.Formula = "=SQRT(50)"

With .Font

.Name = "Arial"

.Bold = True

.Size = 8

End With

End With

End Sub


Visual Basic 命名规则
Visual Basic 的命名规则

当在 Visual Basic 的模块中为过程、常数、变量以及参数命名时，可以使用下列的规则：

•	第一个字符必须使用英文字母。

•	不能在名称中使用空格、句点（.）、惊叹号（!）、或 @、&、$，# 等字符。

•	名称的长度不可以超过 255 个字符。

•	通常，使用的名称不能与 Visual Basic 本身的 Function 过程、语句以及方法的名称相同。必须退出使用与程序语言的关键字相同的名称。若所使用的内在语言函数，语句或方法与所指定的名称相冲突，则必须显示地识别它。常规会将内建函数，语句或方法的名称之前加上关联的类型库的名称。例如，如果有一个名为 Left 的变量，则只能用 VBA.Left 来调用 Left 函数。

•	不能在范围的相同层次中使用重复的名称。例如，不能在同一过程中声明两个命名为 age 的变量。然而，可以在同一模块中声明一个私有的命名为 age 的变量和过程的级别的命名为 age 的变量。

注意   Visual Basic 不区分大小写，但它会在名称被声明的语句处保留大写。


在应用程序间交叉运作

Visual Basic 可以从很多的 Microsoft 应用程序中创建新的对象以及检索已存在的对象。其它的应用程序也可能提供用于创建 Visual Basic 的对象。详细信息，请参阅应用程序文档。

若要创建新的对象或是从其它应用程序中获取已存在的对象，可以使用 CreateObject 函数或是 GetObject 函数：

'启动 Microsoft Excel 和创建新的 Worksheet 对象。

Set ExcelWorksheet = CreateObject("Excel.Sheet")

'启动 Microsoft Excel 和打开一个存在的 Worksheet 对象。

Set ExcelWorksheet = GetObject("SHEET1.XLS")

'启动 Microsoft Word。

Set WordBasic = CreateObject("Word.Basic")

大多数的应用程序会提供 Exit 或 Quit 方法来关闭应用程序，而不必管它是否为可见的。关于应用程序所提供的对象、方法、属性的详细信息，请参阅应用程序文档。

某些应用程序允许使用 New 关键字来创建一个存在于类型库中的类的对象。例如：

Dim X As New Field

在此事例中，Field 是一个在数据访问类型库中类的示例。使用该语法创建一个 Field 对象的新实例。关于用该方法创建对象类的详细信息，请参阅应用程序的文档。


写 Function 过程
写一个 Function 过程

Function 过程是一系列由 Function 和 End Function 语句所包含起来的 Visual Basic 语句。Function 过程和 Sub 过程很类似，但函数可以返回一个值。Function 过程可经由调用者过程通过传递参数，例如常数、变量、或是表达式等来调用它。如果一个 Function 过程没有参数，它的 Function 语句必须包含一个空的圆括号。函数会在过程的一个或多个语句中指定一个值给函数名称来返回值。

在下面的示例中，Celsius 函数会根据华式温度来计算摄氏温度。当 Main 过程调用此函数时，会有一包含参数值的变量传递给此函数。而计算的结果会返回到调用的过程，并且显示在一个消息框中。

Sub Main()

temp = Application.InputBox(Prompt:= _

"Please enter the temperature in degrees F.", Type:=1)

MsgBox "The temperature is " & Celsius(temp) & " degrees C."

End Sub

Function Celsius(fDegrees)

Celsius = (fDegrees - 32) * 5 / 9

End Function


写一个属性过程

Property 过程是一系列的 Visual Basic 语句，它允许程序员去创建并操作自定义的属性。

•	Property 过程可以用来为窗体，标准模块，以及类模块创建只读属性。

•	Property 过程可被用来在代码中代替 Public 变量，当设置属性值时上述动作应被执行。

•	与 Public 变量不同，在“对象浏览器”中 Property 过程会有一些的帮助字符串指定给它们。

当创建一个 Property 过程时，它会变成此过程所包含的模块的一个属性。Visual Basic 提供下列三种类型的 Property 过程：

程序	描述
Property Let	用来设置属性值的过程。
Property Get	用来返回属性值的过程。
Property Set	用来设置对对象引用的过程。
声明 Property 过程的语法如下所示：

[Public | Private] [Static] Property {Get | Let | Set} propertyname_ [(arguments)] [As type]

statements

End Property

Property 过程通常是成对使用的：Property Let 与 Property Get 一组，而 Property Set 与 Property Get 一组。单独声明一个 Property Get 过程就象声明只读属性。三个 Property 过程一起使用时，只有对 Variant 变量有用，因为只有 Variant 才能包含一个对象或其它数据类型的信息。Property Set 本意是使用在对象上；而 Property Let 则不是。

在 Property 过程声明中所需要的参数都列在下表中：

程序	声明语法
Property Get	Property Get propname(1, ..., n) As type
Property Let	Property Let propname(1, ...,,,, n, n+1)
Property Set	Property Set propname(1, ..., n, n+1)
在具有相同名称的 Property 过程中，从第一个到最后一个参数（1, ..., n）都必须共享相同的名称与数据类型。

Property Get 过程声明时所需的参数比相关的 Property Let 以及 Property Set 声明少一个。Property Get 过程的数据类型必须与相关的 Property Let 以及 Property Set 声明中的最后 (n+1) 个参数的类型相同。例如，如果声明下列的 Property Let 过程，则 Property Get 声明所使用参数的名称与数据类型必须 Property Let 过程中所用一样。

Property Let Names(intX As Integer, intY As Integer, varZ As Variant)

' Statement here.

End Property

Property Get Names(intX As Integer, intY As Integer) As Variant

' Statement here.

End Property

在 Property Set 声明中，最后一个参数的数据类型必须是对象类型或是 Variant。


写 Sub 过程
写一个 Sub 过程

Sub 过程是一系列由 Sub 和 End Sub 语句所包含起来的 Visual Basic 语句，它们会执行动作却不能返回一个值。Sub 过程可有参数，例如常数、变量、或是表达式等来调用它。如果一个 Sub 过程没有参数，则它的 Sub 语句必须包含一个空的圆括号。

下面 Sub 过程中，每一行都有注释来解释它的作用：

'声明过程命名为 GetInfo

'该 Sub 过程没有参数

Sub GetInfo()

'声明字符串变量命名为 answer

Dim answer As String

'指定 InputBox 函数的返回值给 answer

answer = InputBox(Prompt:="What is your name?")

'条件 If...Then...Else 语句

If answer = Empty Then

'调用 MsgBox 函数

MsgBox Prompt:="You did not enter a name."

Else

'MsgBox 函数与 answer 变量连接。

MsgBox Prompt:="Your name is " & answer

'结束 If...Then...Else 语句

End If

'结束 Sub 过程

End Sub


写赋值语句

赋值语句指定一个值或表达式给变量或常数。赋值语句通常会包含一个等号（=）。下面示例，指定 InputBox 函数的返回值给变量 yourName。

Sub Question()

Dim yourName As String

yourName = InputBox("What is your name?")

MsgBox "Your name is " & yourName

End Sub

Let 语句是可选的，而通常为省略。例如，上述的赋值语句可以写成：

Let yourName = InputBox("What is your name?")

Set 语句可被用来指定一个对象给已声明成对象的变量。而 Set 关键字是必备的。下面示例中，Set 语句指定 Sheet1 上的一个范围给对象变量 myCell：

Sub ApplyFormat()

Dim myCell As Range

Set myCell = Worksheets("Sheet1").Range("A1")

With myCell.Font

.Bold = True

.Italic = True

End With

End Sub

设置属性值的语句也是一个赋值语句。下面的示例，将设置对于活动单元格 Font 对象的 Bold 属性：

ActiveCell.Font.Bold = True


写声明语句

可以使用声明语句去命名和定义过程、变量、数组以及常数。当声明一个过程、变量或常数时，也同时定义了它的范围，而此范围是取决于声明位置以及用什么关键字来声明它。

下面的示例包含三个声明：

Sub ApplyFormat()

Const limit As Integer = 33

Dim myCell As Range

'更多的语句

End Sub

Sub 语句（与 End Sub 语句相匹配）声明一个过程命名为 ApplyFormat。当 ApplyFormat 过程被调用或运行时，所有包含于 Sub 与 End Sub 中的语句都被执行。

•	写一个 Sub 过程

Const 语句声明常数 limit，指定 Integer 数据类型，其值 33。

•	声明常数

Dim 语句声明变量 myCell。它是一个属于 Microsoft Excel Range 对象的数据类型。可以将变量声明成任何的对象，而此对象显露于正使用的应用程序中。Dim 语句是属于用来声明变量的语句类型之一。其它用来声明的关键字有 ReDim、Static、Public、Private 以及 Const。

•	声明变量


写可执行的语句

一个可执行的语句初始化动作。它可以执行一个方法或者函数，并且可以循环或从代码块中分支执行。可执行的的语句通常包含数学的或条件运算符。

下面的示例使用 For Each...Next 语句来重复名称为 MyRange 范围内的每个单元格，而此范围在活动的 Microsoft Excel 工作簿的 Sheet1 中。

Sub ApplyFormat()

Const limit As Integer = 33

For Each c In Worksheets("Sheet1").Range("MyRange").Cells

If c.Value > limit Then

With c.Font

.Bold = True

.Italic = True

End With

End If

Next c

MsgBox "All done!"

End Sub

示例中的 If...Then...Else 语句检查单元格的值。如果它的值超过 33，则 With 语句设置单元格中 Font 对象的 Bold 和 Italic 属性。而 If...Then...Else 语句会以 End If 结束。

With 语句可以节省代码键入次数，因为所包含的语句会自动的执行于紧接在 With 关键字后面的对象中。

Next 语句会去调用单元格集合中的下一个单元格，而此单元格集合是包含于 MyRange 中。

MsgBox 函数（它显示一个固有的 Visual Basic 对话框）显示一个信息用来指出 Sub 过程已经完成执行。


将数据写到文件中

当工作时中需要用到大量的数据时，将数据从文件中写入或读取是较便利的方式。Open 语句让您直接的创建和访问文件。Open 语句提供三种文件访问类型：

•	顺序访问（Input、Output 和 Append 方式）被用来写入文本文件，比如错误登录和报告。

•	随机访问（Random 方式）被用来读取与写入数据到文件并且没有关闭文件。随机访问文件在记录中保留数据，如此可很快的找出信息所在。

•	二进制访问（Binary 方式）被用来读取或写入数据到文件中任何的字节位置，例如存储或显示一个位图图象。

注意    Open 语句不可以用来打开一个应用程序专属的文件类型。例如，不可使用 Open 去打开一个 Word 文档, a ，Microsoft Excel 的电子数据表，或是 Microsoft Access 数据库。若如此做的话会丢失文件的完整性，并造成文件的毁损。

当从文件读取数据和写入数据到文件时，下表列出了所使用的典型语句。

访问类型	写入数据	读取数据
顺序	Print #, Write #	Input #
随机	Put	Get
二进制	Put	Get


写 Visual Basic 语句

Visual Basic 中的语句是一个完整的命令。它可以包含关键字、运算符、变量、常数，以及表达式。每一个语句都属于下列三种分类之一：

•	声明语句，它会为变量、常数、或程序取名称，并且指定一个数据类型。

写声明语句

•	赋值语句，它会指定一个值或表达式给变量或常数。

写赋值语句

•	可执行语句，它会初始化动作。它可以执行一个方法或是函数，并且可以循环或从代码块中分支执行。可执行的语句通常包含数学的或条件的运算符。

写可执行的语句

将语句连续地写在数行上

通常是将一个语句写在同一行中，但也可以利用一个续行符将语句连续到下一行中。下面的示例中，可执行语句 MsgBox 被接续的写在三行中：

Sub DemoBox()  '该过程声明一个字符串变量，

'指定它值为 Claudia，然后显示一个

'连接的消息。

Dim myVar As String

myVar = "John"

MsgBox Prompt:="Hello " & myVar, _

Title:="Greeting Box", _

Buttons:=vbExclamation

End Sub

添加注释

注释可以为读代码的人解释过程或是特别的命令。Visual Basic 在运行过程时，会忽略掉注释。注释行可由省略符号（'）或 Rem 接着一个空格做为开始，并且可以加在过程的任何地方。为了在语句的同一行中添加注释，必须在语句后面插入一个省略符号，然后加上注释文本。按照缺省规定，注释会以绿色文本显示。

检查语法错误

如果在键入一行代码后按下 ENTER 键，此行代码以红色文本显示（同时可能也显示一个错误信息），则必须找出语句中的错误并更正它。


使用外接程序管理器

使用 “外接程序管理器”对话框加载或卸载外接程序。如果只关闭外接程序的可见部分，例如，双击它的系统菜单或单击它的关闭按钮，该外接程序的窗体会从屏幕上消失，但该外接程序仍在内存中。该外接程序对象本身会一直贮存在内存中，直到通过“外接程序管理器”对话框取消对该外接程序的连接。