Основы офисного программирования и язык VBA

         

Вызовы процедур Sub


Вызов обычной процедуры Sub из другой процедуры можно оформить по-разному. Первый способ:

имя список-фактических-параметров

где имя - имя вызываемой процедуры, а список-фактических-параметров - список аргументов, передаваемых процедуре; он должен соответствовать списку аргументов, заданному в описании процедуры. Задать этот список можно разными способами. В простейшем случае в нем перечисляются через запятую значения передаваемых процедуре аргументов в том же порядке, что и в списке аргументов из заголовка процедуры.

Может оказаться, что в одном проекте несколько модулей содержат процедуры с одинаковыми именами. Для различения этих процедур нужно при их вызове указывать имя процедуры через точку после имени модуля, в котором она определена. Например, если каждый из двух модулей Mod1 и Mod2 содержит определение процедуры ReadData, а в процедуре MyProc нужно воспользоваться процедурой из Mod2, этот вызов имеет вид:

Sub Myproc() ... Mod2.ReadData ... End Sub

Если требуется использовать процедуры с одинаковыми именами из разных проектов, добавьте к именам модуля и процедуры имя проекта. Например, если модуль Mod2 входит в проект MyBook, тот же вызов можно уточнить так:

MyBooks.Mod2.ReadData

Второй способ вызова процедур связан с использованием оператора Call. В этом случае вызов процедуры выглядит так:

Call имя(список-фактических-параметров)

Обратите внимание на то, что в этом случае список-фактических-параметров заключен в круглые скобки, а в первом случае - нет. Попытка вызывать процедуру без оператора Call, но с заданием круглых скобок является источником синтаксических ошибок особенно для разработчиков с большим опытом программирования на Паскале или С, где списки параметров всегда заключаются в скобки. Следует обратить внимание на одну важную и, пожалуй, неприятную особенность вызова процедур VBA. Если процедура VBA имеет только один параметр, то она может быть вызвана без оператора Call и с использованием круглых скобок, не сообщая об ошибке вызова. Это было бы не так страшно, если бы возвращался правильный результат.
К сожалению, это не так, проиллюстрируем сказанное примером:

Public Sub MyInc(ByRef X As Integer) X = X + 1 End Sub

Public Sub TestInc() Dim X As Integer X = 1 'Вызов процедуры с параметром, заключенным в скобки, 'синтаксически допустим, но работает не корректно! MyInc (X) Debug.Print X

'Корректный вызов MyInc X Debug.Print X

'Это тоже корректный вызов Call MyInc(X) Debug.Print X

End Sub

Вот результаты ее работы:

1 2 3

Хотя при первом вызове процедура нормально вызывается и увеличивает значение результата, но по завершении ее работы значение аргумента не изменяется. В этой ситуации не действует описатель ByRef, вызов идет так, будто параметр описан с описателем ByVal.

Если же процедура имеет более одного параметра, то попытка вызвать ее, заключив параметры в круглые скобки и не предварив этот вызов ключевым словом Call, приводит к синтаксической ошибке. Вот простой пример:

Public Sub SumXY(ByVal X As Integer, ByVal Y As Integer, ByRef Z As Integer) Z = X + Y End Sub

Public Sub TestSumXY() Dim a As Integer, b As Integer, c As Integer a = 3: b = 5 'SumXY (a, b, c) 'Синтаксическая ошибка SumXY a, b, c Debug.Print c

End Sub

В этом примере некорректный вызов процедуры SumXY будет обнаружен на этапе проверки синтаксиса.

Рассмотрим еще одну особенность вызова VBA процедур, связанную с аргументами, передаваемыми по ссылке. Как правило, в языках программирования для таких аргументов возможное значение фактического параметра ограничивается, - он должен быть именем переменной, ссылка на которую передается процедуре. VBA допускает возможность задания для таких аргументов констант и выражений в момент вызова. Все эти допущения делают язык менее надежным и чреваты серьезными ошибками. Именно поэтому мы останавливаем на них Ваше внимание.

Пусть, например, процедура CompVal c 4 аргументами, которая в зависимости от положительности z возвращает в переменной y либо увеличенное, либо уменьшенное на 100 значение x и сообщает об этом в строковой переменной w, определена следующим образом.



Sub CompVal(ByVal x As Single, ByRef y As Single, _ ByVal z As Integer, ByRef w As String)

If z > 0 Then ' увеличение y = x + 100 w = "increase" Else ' уменьшение y = x - 100 w = "decrease" End If End Sub

Рассмотрим процедуру TestCompVal, в которой несколько раз вызывается процедура CompVal:

Sub TestCompVal() Dim a As Single Dim b As Single Dim n As Integer Dim S As String

n = 5: a = 7.4 ' значения параметров CompVal a, b, n, S ' 1-ый вызов Debug.Print b, S

CompVal 7.4, b, 5, S ' 2-ой вызов Debug.Print b, S

CompVal 0, 0, 0, S ' 3-ий вызов Debug.Print b, S

CompVal 0, 0, 0, "В чем дело?" ' 4-ый вызов Debug.Print b, S End Sub

В результате выполнения этой процедуры будут напечатаны следующие результаты:

107,4 increase 107,4 increase 107,4 decrease 107,4 decrease

Первые два вызова корректны. Следующие два вызова хотя и допустимы в языке VBA, но приводят к тому, что параметры, переданные по ссылке, не меняют своих значений в ходе выполнения процедуры и, по существу, вызов ByRef по умолчанию заменяется вызовом ByVal. Конечно, было бы лучше, если бы эта программа выдавала ошибки на этапе проверки синтаксиса.


Содержание раздела