Excel vba sub аргументы

Содержание

  1. Встроенные функции VBA
  2. Пользовательские процедуры «Function» и «Sub» в VBA
  3. Аргументы
  4. Необязательные аргументы
  5. Передача аргументов по значению и по ссылке
  6. VBA процедура «Function»
  7. Пример VBA процедуры «Function»: Выполняем математическую операцию с 3 числами
  8. Вызов VBA процедуры «Function»
  9. Вызов VBA процедуры «Function» из другой процедуры
  10. Вызов VBA процедуры «Function» из рабочего листа
  11. VBA процедура «Sub»
  12. VBA процедура «Sub»: Пример 1. Выравнивание по центру и изменение размера шрифта в выделенном диапазоне ячеек
  13. VBA процедура «Sub»: Пример 2. Выравнивание по центру и применение полужирного начертания к шрифту в выделенном диапазоне ячеек
  14. Вызов процедуры «Sub» в Excel VBA
  15. Вызов VBA процедуры «Sub» из другой процедуры
  16. Вызов VBA процедуры «Sub» из рабочего листа
  17. Область действия процедуры VBA
  18. Ранний выход из VBA процедур «Function» и «Sub»

Встроенные функции VBA

Перед тем, как приступить к созданию собственных функций VBA, полезно знать, что Excel VBA располагает обширной коллекцией готовых встроенных функций, которые можно использовать при написании кода.

Список этих функций можно посмотреть в редакторе VBA:

  • Откройте рабочую книгу Excel и запустите редактор VBA (нажмите для этого Alt+F11), и затем нажмите F2.
  • В выпадающем списке в верхней левой части экрана выберите библиотеку VBA.
  • Появится список встроенных классов и функций VBA. Кликните мышью по имени функции, чтобы внизу окна отобразилось её краткое описание. Нажатие F1 откроет страницу онлайн-справки по этой функции.

Кроме того, полный список встроенных функций VBA с примерами можно найти на сайте Visual Basic Developer Centre.

Пользовательские процедуры «Function» и «Sub» в VBA

В Excel Visual Basic набор команд, выполняющий определённую задачу, помещается в процедуру Function (Функция) или Sub (Подпрограмма). Главное отличие между процедурами Function и Sub состоит в том, что процедура Function возвращает результат, процедура Sub – нет.

Поэтому, если требуется выполнить действия и получить какой-то результат (например, просуммировать несколько чисел), то обычно используется процедура Function, а для того, чтобы просто выполнить какие-то действия (например, изменить форматирование группы ячеек), нужно выбрать процедуру Sub.

Аргументы

При помощи аргументов процедурам VBA могут быть переданы различные данные. Список аргументов указывается при объявлении процедуры. К примеру, процедура Sub в VBA добавляет заданное целое число (Integer) в каждую ячейку в выделенном диапазоне. Передать процедуре это число можно при помощи аргумента, вот так:

Sub AddToCells(i As Integer)

...

End Sub

Имейте в виду, что наличие аргументов для процедур Function и Sub в VBA не является обязательным. Для некоторых процедур аргументы не нужны.

Необязательные аргументы

Процедуры VBA могут иметь необязательные аргументы. Это такие аргументы, которые пользователь может указать, если захочет, а если они пропущены, то процедура использует для них заданные по умолчанию значения.

Возвращаясь к предыдущему примеру, чтобы сделать целочисленный аргумент функции необязательным, его нужно объявить вот так:

Sub AddToCells(Optional i As Integer = 0)

В таком случае целочисленный аргумент i по умолчанию будет равен 0.

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

Передача аргументов по значению и по ссылке

Аргументы в VBA могут быть переданы процедуре двумя способами:

  • ByVal – передача аргумента по значению. Это значит, что процедуре передаётся только значение (то есть, копия аргумента), и, следовательно, любые изменения, сделанные с аргументом внутри процедуры, будут потеряны при выходе из неё.
  • ByRef – передача аргумента по ссылке. То есть процедуре передаётся фактический адрес размещения аргумента в памяти. Любые изменения, сделанные с аргументом внутри процедуры, будут сохранены при выходе из процедуры.

При помощи ключевых слов ByVal или ByRef в объявлении процедуры можно задать, каким именно способом аргумент передаётся процедуре. Ниже это показано на примерах:

Sub AddToCells(ByVal i As Integer)

...

End Sub
В этом случае целочисленный аргумент i передан по значению. После выхода из процедуры Sub все сделанные с i изменения будут утрачены.
Sub AddToCells(ByRef i As Integer)

...

End Sub
В этом случае целочисленный аргумент i передан по ссылке. После выхода из процедуры Sub все сделанные с i изменения будут сохранены в переменной, которая была передана процедуре Sub.

Помните, что аргументы в VBA по умолчанию передаются по ссылке. Иначе говоря, если не использованы ключевые слова ByVal или ByRef, то аргумент будет передан по ссылке.

Перед тем как продолжить изучение процедур Function и Sub более подробно, будет полезным ещё раз взглянуть на особенности и отличия этих двух типов процедур. Далее приведены краткие обсуждения процедур VBA Function и Sub и показаны простые примеры.

VBA процедура «Function»

Редактор VBA распознаёт процедуру Function, когда встречает группу команд, заключённую между вот такими открывающим и закрывающим операторами:

Function

...

End Function

Как упоминалось ранее, процедура Function в VBA (в отличие от Sub), возвращает значение. Для возвращаемых значений действуют следующие правила:

  • Тип данных возвращаемого значения должен быть объявлен в заголовке процедуры Function.
  • Переменная, которая содержит возвращаемое значение, должна быть названа так же, как и процедура Function. Эту переменную не нужно объявлять отдельно, так как она всегда существует как неотъемлемая часть процедуры Function.

Это отлично проиллюстрировано в следующем примере.

Пример VBA процедуры «Function»: Выполняем математическую операцию с 3 числами

Ниже приведён пример кода VBA процедуры Function, которая получает три аргумента типа Double (числа с плавающей точкой двойной точности). В результате процедура возвращает ещё одно число типа Double, равное сумме первых двух аргументов минус третий аргумент:

Function SumMinus(dNum1 As Double, dNum2 As Double, dNum3 As Double) As Double

   SumMinus = dNum1 + dNum2 - dNum3

End Function

Эта очень простая VBA процедура Function иллюстрирует, как данные передаются процедуре через аргументы. Можно увидеть, что тип данных, возвращаемых процедурой, определён как Double (об этом говорят слова As Double после списка аргументов). Также данный пример показывает, как результат процедуры Function сохраняется в переменной с именем, совпадающим с именем процедуры.

Вызов VBA процедуры «Function»

Если рассмотренная выше простая процедура Function вставлена в модуль в редакторе Visual Basic, то она может быть вызвана из других процедур VBA или использована на рабочем листе в книге Excel.

Вызов VBA процедуры «Function» из другой процедуры

Процедуру Function можно вызвать из другой VBA процедуры при помощи простого присваивания этой процедуры переменной. В следующем примере показано обращение к процедуре SumMinus, которая была определена выше.

Sub main()

   Dim total as Double
   total = SumMinus(5, 4, 3)

End Sub

Вызов VBA процедуры «Function» из рабочего листа

VBA процедуру Function можно вызвать из рабочего листа Excel таким же образом, как любую другую встроенную функцию Excel. Следовательно, созданную в предыдущем примере процедуру FunctionSumMinus можно вызвать, введя в ячейку рабочего листа вот такое выражение:

=SumMinus(10, 5, 2)

VBA процедура «Sub»

Редактор VBA понимает, что перед ним процедура Sub, когда встречает группу команд, заключённую между вот такими открывающим и закрывающим операторами:

VBA процедура «Sub»: Пример 1. Выравнивание по центру и изменение размера шрифта в выделенном диапазоне ячеек

Рассмотрим пример простой VBA процедуры Sub, задача которой – изменить форматирование выделенного диапазона ячеек. В ячейках устанавливается выравнивание по центру (и по вертикали, и по горизонтали) и размер шрифта изменяется на заданный пользователем:

Sub Format_Centered_And_Sized(Optional iFontSize As Integer = 10)

   Selection.HorizontalAlignment = xlCenter
   Selection.VerticalAlignment = xlCenter
   Selection.Font.Size = iFontSize

End Sub

Данная процедура Sub выполняет действия, но не возвращает результат.

В этом примере также использован необязательный (Optional) аргумент iFontSize. Если аргумент iFontSize не передан процедуре Sub, то его значение по умолчанию принимается равным 10. Однако же, если аргумент iFontSize передается процедуре Sub, то в выделенном диапазоне ячеек будет установлен размер шрифта, заданный пользователем.

VBA процедура «Sub»: Пример 2. Выравнивание по центру и применение полужирного начертания к шрифту в выделенном диапазоне ячеек

Следующая процедура похожа на только что рассмотренную, но на этот раз, вместо изменения размера, применяется полужирное начертание шрифта в выделенном диапазоне ячеек. Это пример процедуры Sub, которой не передаются никакие аргументы:

Sub Format_Centered_And_Bold()

   Selection.HorizontalAlignment = xlCenter
   Selection.VerticalAlignment = xlCenter
   Selection.Font.Bold = True

End Sub

Вызов процедуры «Sub» в Excel VBA

Вызов VBA процедуры «Sub» из другой процедуры

Чтобы вызвать VBA процедуру Sub из другой VBA процедуры, нужно записать ключевое слово Call, имя процедуры Sub и далее в скобках аргументы процедуры. Это показано в примере ниже:

Sub main()

   Call Format_Centered_And_Sized(20)

End Sub

Если процедура Format_Centered_And_Sized имеет более одного аргумента, то они должны быть разделены запятыми. Вот так:

Sub main()

   Call Format_Centered_And_Sized(arg1, arg2, ...)

End Sub

Вызов VBA процедуры «Sub» из рабочего листа

Процедура Sub не может быть введена непосредственно в ячейку листа Excel, как это может быть сделано с процедурой Function, потому что процедура Sub не возвращает значение. Однако, процедуры Sub, не имеющие аргументов и объявленные как Public (как будет показано далее), будут доступны для пользователей рабочего листа. Таким образом, если рассмотренные выше простые процедуры Sub вставлены в модуль в редакторе Visual Basic, то процедура Format_Centered_And_Bold будет доступна для использования на рабочем листе книги Excel, а процедура Format_Centered_And_Sized – не будет доступна, так как она имеет аргументы.

Вот простой способ запустить (или выполнить) процедуру Sub, доступную из рабочего листа:

  • Нажмите Alt+F8 (нажмите клавишу Alt и, удерживая её нажатой, нажмите клавишу F8).
  • В появившемся списке макросов выберите тот, который хотите запустить.
  • Нажмите Выполнить (Run)

Чтобы выполнять процедуру Sub быстро и легко, можно назначить для неё комбинацию клавиш. Для этого:

  • Нажмите Alt+F8.
  • В появившемся списке макросов выберите тот, которому хотите назначить сочетание клавиш.
  • Нажмите Параметры (Options) и в появившемся диалоговом окне введите сочетание клавиш.
  • Нажмите ОК и закройте диалоговое окно Макрос (Macro).

Внимание: Назначая сочетание клавиш для макроса, убедитесь, что оно не используется, как стандартное в Excel (например, Ctrl+C). Если выбрать уже существующее сочетание клавиш, то оно будет переназначено макросу, и в результате пользователь может запустить выполнение макроса случайно.

Область действия процедуры VBA

В части 2 данного самоучителя обсуждалась тема области действия переменных и констант и роль ключевых слов Public и Private. Эти ключевые слова так же можно использовать применительно к VBA процедурам:

Public Sub AddToCells(i As Integer)

...

End Sub
Если перед объявлением процедуры стоит ключевое слово Public, то данная процедура будет доступна для всех модулей в данном проекте VBA.
Private Sub AddToCells(i As Integer)

...

End Sub
Если перед объявлением процедуры стоит ключевое слово Private, то данная процедура будет доступна только для текущего модуля. Её нельзя будет вызвать, находясь в любом другом модуле или из рабочей книги Excel.

Помните о том, что если перед объявлением VBA процедуры Function или Sub ключевое слово не вставлено, то по умолчанию для процедуры устанавливается свойство Public (то есть она будет доступна везде в данном проекте VBA). В этом состоит отличие от объявления переменных, которые по умолчанию бывают Private.

Ранний выход из VBA процедур «Function» и «Sub»

Если нужно завершить выполнение VBA процедуры Function или Sub, не дожидаясь её естественного финала, то для этого существуют операторы Exit Function и Exit Sub. Применение этих операторов показано ниже на примере простой процедуры Function, в которой ожидается получение положительного аргумента для выполнения дальнейших операций. Если процедуре передано не положительное значение, то дальнейшие операции не могут быть выполнены, поэтому пользователю должно быть показано сообщение об ошибке и процедура должна быть тут же завершена:

Function VAT_Amount(sVAT_Rate As Single) As Single

   VAT_Amount = 0
   If sVAT_Rate <= 0 Then
      MsgBox "Expected a Positive value of sVAT_Rate but Received " & sVAT_Rate
      Exit Function
   End If

...

End Function

Обратите внимание, что перед тем, как завершить выполнение процедуры FunctionVAT_Amount, в код вставлена встроенная VBA функция MsgBox, которая показывает пользователю всплывающее окно с предупреждением.

Оцените качество статьи. Нам важно ваше мнение:

Содержание

  1. Sub statement
  2. Syntax
  3. Remarks
  4. Example
  5. See also
  6. Support and feedback
  7. VBA-Урок 9. Процедуры и функции
  8. Public — Private
  9. Запуск процедуры с середины другой процедуры
  10. Аргументы
  11. Необязательные аргументы
  12. ByRef — ByVal
  13. Функции
  14. Оператор Sub
  15. Синтаксис
  16. Замечания
  17. Пример
  18. См. также
  19. Поддержка и обратная связь

Sub statement

Declares the name, arguments, and code that form the body of a Sub procedure.

Syntax

[ Private | Public | Friend ] [ Static ] Sub name [ ( arglist ) ]
[ statements ]
[ Exit Sub ]
[ statements ]
End Sub

The Sub statement syntax has these parts:

Part Description
Public Optional. Indicates that the Sub procedure is accessible to all other procedures in all modules. If used in a module that contains an Option Private statement, the procedure is not available outside the project.
Private Optional. Indicates that the Sub procedure is accessible only to other procedures in the module where it is declared.
Friend Optional. Used only in a class module. Indicates that the Sub procedure is visible throughout the project, but not visible to a controller of an instance of an object.
Static Optional. Indicates that the Sub procedure’s local variables are preserved between calls. The Static attribute doesn’t affect variables that are declared outside the Sub, even if they are used in the procedure.
name Required. Name of the Sub; follows standard variable naming conventions.
arglist Optional. List of variables representing arguments that are passed to the Sub procedure when it is called. Multiple variables are separated by commas.
statements Optional. Any group of statements to be executed within the Sub procedure.

The arglist argument has the following syntax and parts:

[ Optional ] [ ByVal | ByRef ] [ ParamArray ] varname [ ( ) ] [ As type ] [ = defaultvalue ]

Part Description
Optional Optional. Keyword indicating that an argument is not required. If used, all subsequent arguments in arglist must also be optional and declared by using the Optional keyword. Optional can’t be used for any argument if ParamArray is used.
ByVal Optional. Indicates that the argument is passed by value.
ByRef Optional. Indicates that the argument is passed by reference. ByRef is the default in Visual Basic.
ParamArray Optional. Used only as the last argument in arglist to indicate that the final argument is an Optional array of Variant elements. The ParamArray keyword allows you to provide an arbitrary number of arguments. ParamArray can’t be used with ByVal, ByRef, or Optional.
varname Required. Name of the variable representing the argument; follows standard variable naming conventions.
type Optional. Data type of the argument passed to the procedure; may be Byte, Boolean, Integer, Long, Currency, Single, Double, Decimal (not currently supported), Date, String (variable-length only), Object, Variant, or a specific object type. If the parameter is not Optional, a user-defined type may also be specified.
defaultvalue Optional. Any constant or constant expression. Valid for Optional parameters only. If the type is an Object, an explicit default value can only be Nothing.

If not explicitly specified by using Public, Private, or Friend, Sub procedures are public by default.

If Static isn’t used, the value of local variables is not preserved between calls.

The Friend keyword can only be used in class modules. However, Friend procedures can be accessed by procedures in any module of a project. A Friend procedure doesn’t appear in the type library of its parent class, nor can a Friend procedure be late bound.

Sub procedures can be recursive; that is, they can call themselves to perform a given task. However, recursion can lead to stack overflow. The Static keyword usually is not used with recursive Sub procedures.

All executable code must be in procedures. You can’t define a Sub procedure inside another Sub, Function, or Property procedure.

The Exit Sub keywords cause an immediate exit from a Sub procedure. Program execution continues with the statement following the statement that called the Sub procedure. Any number of Exit Sub statements can appear anywhere in a Sub procedure.

Like a Function procedure, a Sub procedure is a separate procedure that can take arguments, perform a series of statements, and change the value of its arguments. However, unlike a Function procedure, which returns a value, a Sub procedure can’t be used in an expression.

You call a Sub procedure by using the procedure name followed by the argument list. See the Call statement for specific information about how to call Sub procedures.

Variables used in Sub procedures fall into two categories: those that are explicitly declared within the procedure and those that are not. Variables that are explicitly declared in a procedure (using Dim or the equivalent) are always local to the procedure. Variables that are used but not explicitly declared in a procedure are also local unless they are explicitly declared at some higher level outside the procedure.

A procedure can use a variable that is not explicitly declared in the procedure, but a naming conflict can occur if anything you defined at the module level has the same name. If your procedure refers to an undeclared variable that has the same name as another procedure, constant or variable, it is assumed that your procedure is referring to that module-level name. To avoid this kind of conflict, explicitly declare variables. Use an Option Explicit statement to force explicit declaration of variables.

You can’t use GoSub, GoTo, or Return to enter or exit a Sub procedure.

Example

This example uses the Sub statement to define the name, arguments, and code that form the body of a Sub procedure.

See also

Support and feedback

Have questions or feedback about Office VBA or this documentation? Please see Office VBA support and feedback for guidance about the ways you can receive support and provide feedback.

Источник

VBA-Урок 9. Процедуры и функции

Public — Private

На данный момент, все процедуры, мы создавали, имеют тип Public , что означает, что они доступны из любого модуля.

Чтобы сделать процедуру доступной только в определенном модуле, используется ключевое слово Private:

Запуск процедуры с середины другой процедуры

Чтобы выполнить процедуру с середины другой процедуры, просто введите ее название.

Здесь есть очень простой пример:

Аргументы

Аргументы делают возможным использование значений из процедуры в под-процедуры (запомните, что по умолчанию, переменные являются доступны только по той процедуры, в которой они были объявлены).

К процедуре «warning» был добавлен аргумент, в данном случае это переменная «var_text» с типом «String» (строка):

Эта процедура требует аргумент, поэтому мы должны поставить значение после «warning», чтобы выполнить ее:

Когда мы хотим прописать несколько аргументов, тогда они должны быть отделены запятыми.

Необязательные аргументы

По умолчанию, если процедура имеет аргументы, то они должны быть обязательно проставлены, и если они не проставлены, тогда процедура не выполнится.

Необязательный аргумент может быть добавлен после обязательного, с помощью ключевого слова Optional . Например:

Теперь эта процедура может быть выполнена с или без опционального аргумента, как здесь:

Аргументы должны быть введены в правильном порядке.

Чтобы протестировать, присутствует ли опциональный аргумент в процедуре, мы используем функцию IsMissing . Эта функция совместима только с некоторыми типами функций (типа Variant) и это является решающим, так как тип необязательно аргументов не был указан в объявлении (необъявленный тип = Variant).

Здесь есть пример, который использует два фрагмента кода, которые рассматривались выше:

См. рисунок ниже (пример 1):

ByRef — ByVal

По умолчанию, аргументы имеют тип ByRef , что означает: если переменная передается как аргумент, ссылка на нее будет также передаваться. Иными словами, если переменная была изменена другой под-процедурой, то она также будет изменена во внешней процедуре, которая вызывает эту под-процедуру.

Чтобы стало понятнее, ниже есть пример того, что произойдет, если макрос будет запущен на выполнение:

Второй метод заключается в использовании ByVal .

В отличие от ByRef , который передает ссылки (ярлык), ByVal передает значение, которое означает, что значение передано как аргумент не было изменено.

Ниже вы можете увидеть как предыдущий код и ByVal работают:

Что вам нужно запомнить: используйте ByVal когда переменная не должна быть изменена .

Функции

Основным отличием между процедурой и функцией является то, что функция возвращает значение.

Вот простой пример:

Функция может быть использована на рабочем листе, подобно любой другой функции в Excel.

Например, чтобы получить квадрат значения, которое введенное в ячейку A1:

Источник

Оператор Sub

Объявляет имя, аргументы и код, формирующий текст процедурыSub.

Синтаксис

[ Частный | Общественного | Друг ] [ Static ] Subname [ ( arglist ) ]
[ операторы ]
[ Exit Sub ]
[ операторы ]
End Sub

Синтаксис оператора Sub состоит из следующих частей:

Part Описание
Public Необязательный параметр. Показывает, что процедура Sub доступна всем другим процедурам во всех модулях. При использовании в модуле, содержащем оператор Option Private, процедура становится недоступной вне проекта.
Private Необязательный параметр. Показывает, что процедура Sub доступна только другим процедурам из модуля, в котором она объявлена.
Friend Необязательный параметр. Используется только в модуле класса. Показывает, что процедура Sub видима по всему проекту, кроме контроллера экземпляра объекта.
Static Необязательный параметр. Показывает, что локальные переменные процедуры Sub сохраняются в промежутках между вызовами. Атрибут Static не влияет на переменные, объявленные вне процедуры Sub, даже если они используются в процедуре.
name Обязательно. Имя процедуры Sub массива; должен соответствовать стандартным правилам именования переменных.
arglist Необязательный параметр. Список переменных, представляющих аргументы, передаваемые в процедуру Sub при ее вызове. В качестве разделителя переменных используется запятая.
Операторы Необязательный параметр. Любая группа операторов, выполняющихся внутри процедуры Sub.

Аргумент arglist имеет следующий синтаксис и элементы:

[ Необязательно ] [ ByVal | ByRef ] [ ParamArray ] varname [ ( ) ] [ Astype ] [ =defaultvalue ]

Part Описание
Необязательное Необязательный параметр. Ключевое слово, которое указывает, что аргумент не является обязательным. Если используется, все последующие аргументы в списке ресурсов также должны быть необязательными и объявляться с помощью ключевого слова Optional . Optional не может использоваться для каких-либо аргументов, если используется ParamArray.
ByVal Необязательный параметр. Указывает, что аргумент передается значением.
ByRef Необязательный параметр. Указывает, что аргумент передается по ссылке. ByRef является значением по умолчанию в Visual Basic.
ParamArray Необязательный параметр. Используется только в качестве последнего аргумента в списке ресурсов , чтобы указать, что окончательный аргумент является необязательныммассивом элементов Variant . Ключевое слово ParamArray позволяет предоставлять произвольное число аргументов. Ключевое слово ParamArray не может использоваться с аргументами ByVal, ByRef или Optional.
варнаме Обязательно. Имя переменной, представляющее аргумент; соответствует стандарту соглашений об именовании переменных.
type Необязательный параметр. Тип данных аргумента, передаваемого процедуре; Может быть byte, Boolean, Integer, Long, Currency, Single, Double, Decimal (в настоящее время не поддерживается), Date, String (только переменная длина), Object, Variant или определенный тип объекта. Если параметр не является Optional, может быть указан определяемый пользователем тип.
Defaultvalue Необязательный параметр. Любая константа или константное выражение. Действительно только для параметров Optional. Если типом является Object, явным значением по умолчанию может быть только Nothing.

Замечания

Если явно не указано с помощью public, private или Friend, процедуры Sub по умолчанию являются общедоступными.

Если static не используется, значение локальных переменных не сохраняется между вызовами.

Ключевое слово Friend может использоваться только в модулях классов. Однако доступ к процедурам Friend может осуществляться в любом модуле проекта. Процедура Friend не отображается в библиотеке типов своего родительского класса; процедура Friend не может быть привязана позднее.

Процедуры Sub могут быть рекурсивными, то есть вызывать сами себя для выполнения определенной задачи. Однако рекурсия может привести к переполнению стека. Как правило, ключевое слово Static не используется с рекурсивными процедурами Sub.

Весь исполняемый код должен находиться в процедурах. Процедуру Sub нельзя объявлять внутри другой процедуры Sub, Function или Property.

Ключевые слова Exit Sub вызывают мгновенный выход из процедуры Sub. Выполнение программы продолжается с оператора, следующего за вызовом процедуры Sub . В процедуре Sub можно использовать сколько угодно операторов Exit Sub.

Как и процедура Function, процедура Sub является отдельной процедурой, которая может принимать аргументы, выполнять последовательность операторов и менять значения своих аргументов. Но в отличие от процедуры Function, которая возвращает значение, процедуру Sub нельзя использовать в выражениях.

Вы вызываете процедуру Sub , используя имя процедуры, за которой следует список аргументов. Дополнительные сведения о вызове процедур Sub см. в инструкции Call.

Переменные, используемые в процедурах Sub, делятся на две категории: объявленные и не объявленные в явном виде внутри процедуры. Переменные, объявленные в явном виде внутри процедуры (с использованием инструкции Dim или ее аналогов) всегда являются локальными для процедуры. Переменные, которые используются, но не были явно объявлены в процедуре, также являются локальными, если они не были объявлены на более высоком уровне вне процедуры.

В процедуре могут использоваться переменные, не объявленные внутри нее в явном виде, однако если на уровне модуля объявлены переменные с такими же именами, может возникнуть конфликт имен. Если процедура ссылается на необъявленную переменную, имя которой совпадает с именем другой процедуры, предполагается, что она ссылается на имя из уровня модуля. Во избежание таких конфликтов рекомендуется объявлять переменные в явном виде. Используйте оператор Option Explicit для принудительного объявления переменных.

Операторы GoSub, GoTo или Return нельзя использовать для входа в процедуру Sub и выхода из нее.

Пример

В приведенном ниже примере оператор Sub используется для определения имени, аргументов и кода, формирующих тело процедуры Sub.

См. также

Поддержка и обратная связь

Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.

Источник

Процедура — это последовательность операторов VBA, расположенная в модуле VBA, доступ к которому можно получить с помощью VBE. Модуль может включать любое количество процедур.[1] Некоторые процедуры получают аргументы. Аргумент — это информация, используемая процедурой в процессе выполнения. Аргументы процедуры во многом подобны аргументам, используемым функциями Excel.

При объявлении процедуры с использованием ключевого слова Sub применяется следующий синтаксис.

[Private | Public][Static] Sub имя([список_аргументов])
    [инструкции]
    [Exit Sub]
    [инструкции]
End Sub

Рис. 1. Запуск процедуры из Visual Basic Editor

Скачать заметку в формате Word или pdf

Private (необязательное ключевое слово). Указывает на то, что процедура доступна только для других процедур в том же модуле.

Public (необязательное ключевое слово). Указывает на то, что процедура доступна для всех остальных процедур во всех модулях рабочей книги. При использовании в модуле, содержащем оператор Option Private Module, процедура будет недоступна за пределами проекта.

Static (необязательное ключевое слово). Указывает на то, что переменные процедуры сохраняются после окончания процедуры.

Sub (обязательное ключевое слово). Обозначает начало процедуры.

Имя. Любое корректное название процедуры.

Список_аргументов. Представляет заключенный в скобки список переменных, содержащих аргументы, которые передаются в процедуру. Для разделения аргументов используется запятая. Если процедура не использует аргументы, то необходимо включить в объявление процедуры пустые скобки.

Инструкции (необязательные). Корректные инструкции VBA.

Exit Sub (необязательный оператор). Вызывает немедленный выход из процедуры до ее формального завершения.

End Sub (обязательный оператор). Указывает на завершение процедуры.

Выполнение процедуры

Основные способы выполнения, или вызова, процедуры VBA.

1-й способ. С помощью команды Run–>Run Sub/UserForm (Выполнить –> Выполнить процедуру/ пользовательскую форму, рис. 1) в VBE. Альтернатива — нажать <F5> либо воспользоваться кнопкой Run Sub/UserForm панели инструментов Standard (Стандартная, рис. 2).

Рис. 2. Кнопка Run Sub/UserForm на панели Standard VBE

2-й способ. Из диалогового окна Макрос в Excel (рис. 3). Чтобы вызвать окно пройдите по меню Разработчик –> Макрос или нажмите Alt+F8.

Рис. 3. Диалоговое окно Макрос в Excel

3-й способ. С помощью комбинации клавиши <Ctrl> и присвоенной процедуре клавиши (если процедуре присвоена комбинация клавиш). Если в момент создания процедуры ей не была присвоена клавиша, сделать это никогда не поздно. Откройте окно Макрос, как описано выше, выделите процедуру в окне Имя макроса, кликните Параметры, и введите букву в окне Сочетание клавиш (рис. 4).

Рис. 4. Присвоение процедуре комбинации клавиш

4-й способ. Щелкнув на кнопке или любой фигуре рабочего листа. Для этого кнопке или фигуре должна быть присвоена процедура (рис. 5).

Рис. 5. Назначение макроса фигуре

5-й способ. Из другой процедуры. Процедуры Sub и Function могут вызывать другие процедуры.

6-й способ. С помощью пользовательского элемента управления, находящегося на ленте. Кроме того, встроенные элементы управления ленты могут быть «перенастроены» для вызова макроса на выполнение.

7-й способ. Из пользовательского контекстного меню.

8-й способ. После выполнения определенного события. Такими событиями могут выступать открытие рабочей книги, сохранение рабочей книги, закрытие рабочей книги, изменение ячейки, переход на другой рабочий лист и многие другие.

9-й способ. Из окна отладки (Immediate) в VBE. Просто введите название процедуры, укажите все необходимые аргументы и нажмите клавишу <Enter>.

Передача аргументов процедурам

Аргументы обеспечивают процедуру данными, использующимися в ее инструкциях. Аргумент может передавать следующие данные: переменная, константа, массив, объект.

Используются два способа передачи аргументов процедуре.

  • По ссылке. При передаче аргумента по ссылке (метод, применяемый по умолчанию) процедуре передается адрес ячейки памяти, в которой хранится переменная. Поэтому изменение аргумента в процедуре приводит к изменению исходной переменной.
  • По значению. Передача аргумента по значению фактически означает передачу процедуре копии исходной переменной. Следовательно, изменение аргумента при выполнении процедуры не отражается на исходной переменной.

В следующем примере аргумент процедуры Process передается по ссылке (по умолчанию). После того как процедура Main присваивает переменной MyValue значение 10, она вызывает процедуру Process и передает MyValue в качестве аргумента. Процедура Process умножает значение своего аргумента (с названием YourValue) на 10. По окончании процедуры Process возобновляется выполнение процедуры Main, а функция MsgBox отображает строку MyValue: 100.

Sub Main ()
    Dim MyValue As Integer
    MyValue = 10
    Call Process(MyValue)
    MsgBox MyValue
End Sub

Sub Process (YourValue)
    YourValue = YourValue * 10
End Sub

Если требуется, чтобы вызываемая процедура не изменяла переменные, полученные как аргументы, измените список аргументов вызываемой процедуры так, чтобы аргументы передавались по значению, а не по ссылке. Для этого добавьте перед аргументом ключевое слово ByVal. Тогда вызываемая процедура будет управлять копией переданных данных, а не самими данными. В следующей процедуре, например, изменения, которые происходят с YourValue в процедуре Process, не влияют на значение переменной MyValue в процедуре Main. В результате функция MsgBox отображает 10, а не 100.

Sub Process(ByVal YourValue)
    YourValue = YourValue * 10
End Sub

Обработка ошибок

Чтобы указать. программе, что должно произойти при возникновении ошибки, используется оператор On Error. Вы вправе выбрать один из двух вариантов.

  • Проигнорировать ошибку и позволить VBA продолжить выполнение программы. После этого можно проанализировать объект Err, чтобы узнать, какая ошибка произошла, и при необходимости принять меры для ее предотвращения.
  • Перейти к специальному разделу кода для обработки ошибок, чтобы выполнить необходимые действия. Этот раздел вводится в конце процедуры и обозначается специальной меткой.

Чтобы программа продолжала выполняться после возникновения ошибки, необходимо вставить в начало процедуры оператор On Error Resume Next. При возникновении ошибки можно использовать объект Err для определения ее номера. Например, на рис. 6 представлена процедура, присваивающая Листу2 имя Исходные данные. Однако, в книге может не быть Листа2. В этом случае появится сообщение об ошибке.

Рис. 6. Процедура присвоения имени Листу Excel, обрабатывающая ошибку

Ссылка на Err эквивалентна обращению к свойству Number объекта Err. Следовательно, два приведенных ниже оператора идентичны:

MsgBox Err
MsgBox Err.Number

Оператор On Error также применяется для определения места в процедуре, к которому должна перейти программа в случае ошибки. Чтобы обозначить это место, используется метка.

On Error GoTo ErrorHandler

Следующая процедура выделяет все ячейки в текущем диапазоне, содержащие формулы, возвращающие число. Процедура также использует оператор If для определения результата: произошла ли ошибка. Оператор On Error GoTo 0 восстанавливает нормальную обработку ошибок перед выходом из процедуры.

Sub SelectFormulas2()
    On Error Resume Next
    Selection.SpecialCells(xlFormulas, xlNumbers).Select
    If Err.Number = 1004 Then MsgBox "He найдены ячейки с формулами."
    On Error GoTo 0
    ' …[код]
End Sub

Если свойство Number объекта Err не равно 0, происходит ошибка. С помощью оператора If проверяется, не равно ли свойство Err.Number 1004, и, если это так, отображается окно сообщения. В рассмотренном примере осуществляется проверка кода на предмет обнаружения ошибки с указанным номером.

В следующем примере кода демонстрируется обработка ошибок путем перехода по метке.

Sub ErrorDemo()
    On Error GoTo Handler
    Selection.Value = 123
Exit Sub
Handler:
    MsgBox "Невозможно присвоить значение выделенному диапазону."
End Sub

В процедуре предпринимается попытка присвоить значение текущему выделенному объекту. Если происходит ошибка (например, не выделен диапазон ячеек или лист защищен), то оператор присваивания выдает ошибку. Оператор On Error задает переход к метке Handler в случае ошибки. Обратите внимание, что перед меткой используется оператор Exit Sub. Программа обработки не выполняется, если ошибок не было.

[1] По материалам книги Джон Уокенбах. Excel 2010. Профессиональное программирование на VBA. – М: Диалектика, 2013. – С. 253–273.

В отличии от языка VBScript, VBA процедуры классифицируются не на два типа (процедура-функция и процедура-подпрограмма), а четырех типов: процедура-функция, процедура-подпрограмма, процедура свойств и обработка событий. Также существуют некоторые дополнения в плане передачи параметров (по значению или по ссылке). Третьим моментом является область видимости – в VBA вызов процедуры может осуществляться как в пределах текущего модуля (макроса), так и за его пределами – во всех проектах. Все это обусловлено тем, что VBA – это не столько язык программирования, сколько программный пакет, с возможностью создания форм и проектов.

Давайте сначала кратко рассмотрим типы VBA процедур:

Подпрограммы – блоки кода заключенные в конструкцию Sub …. End Sub. Сама по себе подпрограмма не возвращает никакого значения, а просто выполняет прописанные в ней команды.

Функции – также блок кода, но прописанный в конструкцию Function … End Function. После выполнения функции возвращается определенное значение, доступ к которому можно получить через имя VBA функции.

Помимо этого, стоит упомянуть про обработку событий (нажатие кнопки клавиатуры или перемещение мыши) и доступ к объектам, но это отдельная тема.

VBA процедуры типа Sub – подпрограммы

После того как вы добавили в проект новый модуль, для объявления процедуры VBA нужно ее заключить в специальную конструкцию:

Sub ИмяПодпрограмм([аргументы])
Операторы
[Exit Sub]
операторы
End Sub

После ключевого слова Sub следует имя подпрограммы, в круглых скобках можно указывать или не указывать аргументы. Аргументы – это переменные (параметры), значение которых может обрабатываться, аргументы разделяются запятыми. Конструкция Exit Sub также не является обязательной, она говорит  том, что нужно произвести выход из подпрограммы и продолжить выполнение кода, следующего после выражения End Sub.

Вызов VBA процедуры осуществляется с помощью ключевого слова call, например, Call MySub.

Давайте напишем простой пример: добавьте в проект новую форму и новый модуль. На поверхность формы добавьте два текстовых поля (TextBox), одну метку (Label) и одну кнопку (CommandButton). Создайте связь между формой и модулем, прописав в редакторе кода для модуля:

Sub SubModule()
    SubForm.Show
End Sub

Я назвал форму SubForm, а модуль – SubModule, за имя отвечает свойство Name.

vba вызов процедуры

Теперь в редакторе кода для формы пропишите:

'************************************
' Вычисление гипотенузы
'************************************
 
' процедура VBA принимает два параметра
Sub Hipotenuze(a, b)
Dim c
    ' Проверка, если значения равны нулю
    If TextBox1.Text = 0 Or TextBox2.Text = 0 Then
        a = 1: b = 1
    End If
    ' вычисление гипотенузы
    c = Sqr(a ^ 2 + b ^ 2)
    Label1.Caption = "Гипотенуза: " & c
End Sub
 
' Обработка нажатия на кнопку
Private Sub CommandButton1_Click()
Dim Ta, Tb
    Ta = TextBox1.Text
    Tb = TextBox2.Text
    ' vba вызов процедуры Hipotenuze
    Call Hipotenuze(Ta, Tb)
End Sub
 
' Настройка свойств при запуске формы
Private Sub UserForm_Initialize()
    Label1.Caption = ""
    Label1.FontSize = 15
    Label1.ForeColor = vbBlue
    CommandButton1.Caption = "Найти"
    TextBox1.Text = 5
    TextBox2.Text = 5
End Sub

Тут все предельно просто, вначале мы объявили процедуру Hipotenuze, которой будут передаваться два аргумента, далее происходит проверка на нулевые значения. Вызов происходит при нажатии на кнопку, находящуюся на форме, параметрами будут значения, хранящиеся в текстовых полях TextBox1 и TextBox2. Результат отображается в метке Label1.

Вызов процедуры VBA может осуществляться и без использования ключевого слова Call, в таком случае, параметры не надо заключать в круглые скобки. Так же, при определении аргументов можно явно указать тип данных, например:

Sub MySub (a As Integer, b As String) … End Sub

Дополнительные особенности:

Static – данное ключевое слово, прописанное перед ключевым словом Sub позволяет сохранять в памяти значения всех переменных после выполнения процедуры. Его мы рассматривали в с статье – переменные VBA.

ParamArray – данное ключевое слово позволяет передавать процедуре переменное количество параметров, оно может использоваться только для последнего элемента в списке аргументов.

Ключевое слово ParamArray

ParamArray нельзя использовать вместе со словами ByRef, ByVal или Optional, например:

'************************************
' Передача параметров
'************************************
 
' процедура VBA принимает два параметра
Sub MyArguments(a As Integer, ParamArray b())
Dim elem, s As String
    Label1.Caption = a
    For Each elem In b
        s = s & elem & " "
    Next
    Label2.Caption = s
End Sub
 
' Обработка нажатия на кнопку
Private Sub CommandButton1_Click()
    MyArguments 1, 5, 6, 100, "строка"
End Sub
 
' Настройка свойств при запуске формы
Private Sub UserForm_Initialize()
    Label1.Caption = ""
    Label1.FontSize = 15
    Label1.ForeColor = vbBlue
 
    Label2.Caption = ""
    Label2.FontSize = 15
    Label2.ForeColor = vbRed
    CommandButton1.Caption = "Вывести"
End Sub

Как видим, мы фактически с помощью ParamArray показываем, что передаем массив, для его обработки мы использовали оператор For …. Each. Тут мы передали при вызове VBA процедуры пять параметров, при этом, первый будет храниться в аргументе a, а остальные в аргументе b, который обрабатывается как массив.

Optional – позволяет указать, что аргумент не является обязательным и одновременно задать значение по умолчанию.

VBA Sub и Function

Например:

'************************************
' Передача параметров
'************************************
 
Sub MyArguments(Optional a As Integer = 5, Optional b As String = " плюс ", Optional c As Integer = 10)
    Label1.Caption = a & b & c
End Sub
 
Private Sub CommandButton1_Click()
    MyArguments
End Sub
Private Sub CommandButton2_Click()
    MyArguments 100, " минус ", 50
End Sub
Private Sub CommandButton3_Click()
    MyArguments 20, , 30
End Sub
 
Private Sub UserForm_Initialize()
    Label1.Caption = ""
    Label1.FontSize = 15
    Label1.ForeColor = vbBlue
 
    CommandButton1.Caption = "Вариант 1"
    CommandButton2.Caption = "Вариант 2"
    CommandButton3.Caption = "Вариант 3"
End Sub

В данном примере на поверхности формы находится всего одна метка и три кнопки. Каждая из кнопок будет производить VBA вызов процедуры MyArguments с различными значениями.

Передача параметров по ссылке и по значению – по умолчанию, при вызове процедуры все параметры ей передаются по ссылке. Передача по ссылке – в простом варианте, это передача адреса по которому хранится значение. При передаче параметра по ссылке, передается не адрес, а копия значения.

Передача VBA параметров по ссылке и по значению

Что бы все стало понятно, рассмотрим следующий пример:

'************************************
' Передача параметров
'************************************
 
Sub MySub1()
Dim MyVar
    MyVar = 100
    Call MySumm1(MyVar)
    Label1.Caption = "Передача по ссылке " & MyVar
End Sub
 
Sub MySub2()
Dim MyVar
    MyVar = 100
    Call MySumm2(MyVar)
    Label2.Caption = "Передача по значению " & MyVar
End Sub
 
Sub MySumm1(ByRef a)
 a = a + 100
End Sub
Sub MySumm2(ByVal a)
 a = a + 100
End Sub
 
Private Sub CommandButton1_Click()
    MySub1
    MySub2
End Sub
 
Private Sub UserForm_Initialize()
    Label1.Caption = ""
    Label1.FontSize = 15
    Label1.ForeColor = vbBlue
 
    Label2.Caption = ""
    Label2.FontSize = 15
    Label2.ForeColor = vbRed
 
    CommandButton1.Caption = "Проверить"
End Sub

MySub1 – тут происходит объявление переменной MyVar и присвоение ей значения 100, далее в теле происходит вызов VBA процедуры MySumm1, ей в качестве параметры мы передаем значение переменной MyVar – 100. Сама процедура MySumm принимает значение по ссылке, на что указывает ключевое слово ByRef, к принятому значению прибавляется число 100. Стоит обратить внимание, что ByRef можно было и не писать. После VBA вызова процедуры MySumm1 происходит запись значения переменной MyVar в свойство Caption объекта Label1, в итоге, отобразится число 200.

MySub2 – аналог предыдущей процедуры, но тут происходит вызов MySumm2, в которой происходит передача параметров по значению, о чем говорит ключевое слово ByVal, в итоге, значение переменной MyVar не изменится.

VBA процедуры типа Function – функции

Пользовательским функциям языка VBA присущи практически те же правила, что и подпрограммам. Общая структура функции:

Function ИмяФункции ([аргументы]) [As ТипДанных]
Операторы
[Exit Function]
Операторы
[ИмяФункции=Выражение]
End Function

Видим, что тут при объявлении функции можно указать ее тип, данный тип будет содержать возвращаемое значение. Что бы функция возвращала значение, в конце нужно его присвоить переменной с именем функции, например:

Function Summ(a As Integer, b As Integer) As Integer
    Summ = a + b
End Function
 
Private Sub CommandButton1_Click()
    Label1.Caption = "Сумма 10 и 20: " & Summ(10, 20)
End Sub
 
Private Sub UserForm_Initialize()
    Label1.Caption = ""
    Label1.FontSize = 15
    Label1.ForeColor = vbBlue
    CommandButton1.Caption = "Сумма"
End Sub

“Computers are useless. They can only give you answers.” – Pablo Picasso.

 
This post provides a complete guide to using the VBA Sub. I also cover VBA functions which are very similar to Subs.

If you want some quick information about creating a VBA Sub, Function, passing parameters, return values etc. then check out the quick guide below.

If you want to understand all about the VBA Sub, you can read through the post from start to finish or you can check out the table of contents below.

Quick Guide to the VBA Sub

Sub Example
Sub

  • Cannot return a value.
Function

  • Can return a value or object.
  • Can run as Worksheet function.
Create a sub Sub CreateReport()

End Sub

Create a function Function GetTotal() As Long

End Function

Create a sub with parameters Sub CreateReport(ByVal Price As Double)

Sub CreateReport(ByVal Name As String)

Create a function with parameters Function GetTotal(Price As Double)

Function GetTotal(Name As String)

Call a sub Call CreateReport
‘ Or
CreateReport
Call a function Call CalcPrice
‘ Or
CalcPrice
Call a sub with parameters Call CreateReport(12.99)

CreateReport 12.99

Call a function with parameters Call CalcPrice(12.99)

CalcPrice 12.99

Call a function and retrieve value
(cannot use Call keyword for this)
Price = CalcPrice
Call a function and retrieve object Set coll = GetCollection
Call a function with params and retrieve value/object Price = CalcPrice(12)
Set coll = GetCollection(«Apples»)
Return a value from Function Function GetTotal() As Long
    GetTotal = 67
End Function
Return an object from a function Function GetCollection() As Collection
    Dim coll As New Collection
    Set GetCollection = coll
End Function
Exit a sub If IsError(Range(«A1»)) Then
     Exit Sub
End If
Exit a function If IsError(Range(«A1»)) Then
     Exit Function
End If
Private Sub/Private Function
(available to current module)
Private Sub CreateReport()
Public Sub/Public Function
(available to entire project)
Public Sub CreateReport()

Introduction

The VBA Sub is an essential component of the VBA language. You can also create functions which are very similar to subs. They are both procedures where you write your code. However, there are differences and these are important to understand. In this post I am going to look at subs and functions in detail and answer the vital questions including:

  • What is the difference between them?
  • When do I use a sub and when do I use a function?
  • How do you run them?
  • Can I return values?
  • How do I pass parameters to them?
  • What are optional parameters?
  • and much more

 
Let’s start by looking at what is the VBA sub?

What is a Sub?

In Excel VBA a sub and a macro are essentially the same thing. This often leads to confusion so it is a good idea to remember it. For the rest of this post I will refer to them as subs.

A sub/macro is where you place your lines of VBA code. When you run a sub, all the lines of code it contains are executed. That means that VBA carries out their instructions.

 
The following is an example of an empty sub

Sub WriteValues()

End Sub

 
You declare the sub by using the Sub keyword and the name you wish to give the sub. When you give it a name keep the following in mind:

  • The name must begin with a letter and cannot contain spaces.
  • The name must be unique in the current workbook.
  • The name cannot be a reserved word in VBA.

 
The end of the Sub is marked by the line End Sub.

 
When you create your Sub you can add some code like the following example shows:

Sub WriteValues()
    Range("A1") = 6
End Sub

What is a Function?

A Function is very similar to a sub. The major difference is that a function can return a value – a sub cannot. There are other differences which we will look at but this is the main one.

You normally create a function when you want to return a value.

 
Creating a function is similar to creating a sub

Function PerformCalc()

End Function

 
It is optional to add a return type to a function. If you don’t add the type then it is a Variant type by default. This means that VBA will decide the type at runtime.

 
The next example shows you how to specify the return type

Function PerformCalc() As Long

End Function

 
You can see it is simple how you declare a variable. You can return any type you can declare as a variable including objects and collections.

A Quick Comparison

Sub:

  1. Cannot return a value.
  2. Can be called from VBAButtonEvent etc.

Function

  1. Can return a value but doesn’t have to.
  2. Can be called it from VBAButtonEvent etc. but it won’t appear in the list of Macros. You must type it in.
  3. If the function is public, will appear in the worksheet function list for the current workbook.

 
Note 1: You can use “Option Private Module” to hide subs in the current module. This means that subs won’t be visible to other projects and applications. They also won’t appear in a list of subs when you bring up the Macro window on the developer tab.

Note 2:We can use the word procedure to refer to a function or sub

Calling a Sub or Function

When people are new to VBA they tend to put all the code in one sub. This is not a good way to write your code.

It is better to break your code into multiple procedures. We can run one procedure from another.

Here is an example:

' https://excelmacromastery.com/
Sub Main()
    
    ' call each sub to perform a task
    CopyData
    
    AddFormulas
    
    FormatData

End Sub

Sub CopyData()
    ' Add code here
End Sub

Sub AddFormulas()
    ' Add code here
End Sub

Sub FormatData()
    ' Add code here
End Sub

 
You can see that in the Main sub, we have added the name of three subs. When VBA reaches a line containing a procedure name, it will run the code in this procedure.

We refer to this as calling a procedure e.g. We are calling the CopyData sub from the Main sub.

There is actually a Call keyword in VBA. We can use it like this:

' https://excelmacromastery.com/
Sub Main()
    
    ' call each sub to perform a task
    Call CopyData
    
    Call AddFormulas
    
    Call FormatData

End Sub

 
Using the Call keyword is optional. There is no real need to use it unless you are new to VBA and you feel it makes your code more readable.

If you are passing arguments using Call then you must use parentheses around them.

For example:

' https://excelmacromastery.com/
Sub Main()
    
    ' If call is not used then no parentheses
    AddValues 2, 4
    
    ' call requires parentheses for arguments
    Call AddValues(2, 4)
End Sub

Sub AddValues(x As Long, y As Long)

End Sub

How to Return Values From a Function

To return a value from a function you assign the value to the name of the Function. The following example demonstrates this:

' https://excelmacromastery.com/
Function GetAmount() As Long
    ' Returns 55
    GetAmount = 55
End Function

Function GetName() As String
    ' Returns John
    GetName = "John"
End Function

 
When you return a value from a function you will obviously need to receive it in the function/sub that called it. You do this by assigning the function call to a variable. The following example shows this:

' https://excelmacromastery.com/
Sub WriteValues()
    Dim Amount As Long
    ' Get value from GetAmount function
    Amount = GetAmount
End Sub

Function GetAmount() As Long
    GetAmount = 55
End Function

 
You can easily test your return value using by using the Debug.Print function. This will write values to the Immediate Window (View->Immediate window from the menu or press Ctrl + G).

' https://excelmacromastery.com/
Sub WriteValues()
    ' Print return value to Immediate Window
    Debug.Print GetAmount
End Sub

Function GetAmount() As Long
    GetAmount = 55
End Function

Using Parameters and Arguments

We use parameters so that we can pass values from one sub/function to another.

The terms parameters and arguments are often confused:

  • A parameter is the variable in the sub/function declaration.
  • An argument is the value that you pass to the parameter.
' https://excelmacromastery.com/
Sub UsingArgs()

    ' The argument is 56
    CalcValue 56
    
    ' The argument is 34
    CalcValue 34

End Sub

' The parameter is amount
Sub CalcValue(ByVal amount As Long)

End Sub

Here are some important points about parameters:

  • We can have multiple parameters.
  • A parameter is passed using either ByRef or ByVal. The default is ByRef.
  • We can make a parameter optional for the user.
  • We cannot use the New keyword in a parameter declaration.
  • If no variable type is used then the parameter will be a variant by default.

The Format of Parameters

Subs and function use parameters in the same way.

The format of the parameter statement is as follows:

' All variables except arrays
[ByRef/ByVal]  As [Variable Type]

' Optional parameter - can only be a basic type
[Optional] [ByRef/ByVal] [Variable name] As <[Variable Type] = 

' Arrays
[ByRef][array name]() As [Variable Type]

Here are some examples of the declaring different types of parameters:

' https://excelmacromastery.com/
' Basic types

Sub UseParams1(count As Long)
End Sub

Sub UseParams2(name As String)
End Sub

Sub UseParams3(amount As Currency)
End Sub

' Collection
Sub UseParamsColl(coll As Collection)
End Sub

' Class module object
Sub UseParamsClass(o As Class1)
End Sub

' Variant
' If no type is give then it is automatically a variant
Sub UseParamsVariant(value)
End Sub

Sub UseParamsVariant2(value As Variant)
End Sub

Sub UseParamsArray(arr() As String)
End Sub

You can see that declaring parameters looks similar to using the Dim statement to declare variables.

Multiple Parameters

We can use multiple parameters in our sub/functions. This can make the line very long

Sub LongLine(ByVal count As Long, Optional amount As Currency = 56.77, Optional name As String = "John")

We can split up a line of code using the underscore (_) character. This makes our code more readable

Sub LongLine(ByVal count As Long _
            , Optional amount As Currency = 56.77 _
            , Optional name As String = "John")

Parameters With a Return Value

This error causes a lot of frustration with new users of VBA.

If you are returning a value from a function then it must have parentheses around the arguments.

The code below will give the “Expected: end of statement” syntax error.

' https://excelmacromastery.com/
Sub UseFunction()
    
    Dim result As Long
    
    result = GetValue 24.99
    
End Sub


Function GetValue(amount As Currency) As Long
    GetValue = amount * 100
End Function
 

 
vba expected end of statement error

 
 
We have to write it like this

result = GetValue (24.99)

ByRef and ByVal

Every parameter is either ByRef or ByVal. If no type is specified then it is ByRef by default

' https://excelmacromastery.com/
' Pass by value
Sub WriteValue1(ByVal x As Long)

End Sub

' Pass by reference
Sub WriteValue2(ByRef x As Long)

End Sub

' No type used so it is ByRef
Sub WriteValue3(x As Long)

End Sub

 
If you don’t specify the type then ByRef is the type as you can see in the third sub of the example.

The different between these types is:

ByVal – Creates a copy of the variable you pass.
This means if you change the value of the parameter it will not be changed when you return to the calling sub/function

ByRef – Creates a reference of the variable you pass.
This means if you change the value of the parameter variable it will be changed when you return to the calling sub/function.

 
The following code example shows this:

' https://excelmacromastery.com/
Sub Test()

    Dim x As Long

    ' Pass by value - x will not change
    x = 1
    Debug.Print "x before ByVal is"; x
    SubByVal x
    Debug.Print "x after ByVal is"; x

    ' Pass by reference - x will change
    x = 1
    Debug.Print "x before ByRef is"; x
    SubByRef x
    Debug.Print "x after ByRef is"; x

End Sub

Sub SubByVal(ByVal x As Long)
    ' x WILL NOT change outside as passed ByVal
    x = 99
End Sub

Sub SubByRef(ByRef x As Long)
    ' x WILL change outside as passed ByRef
    x = 99
End Sub

 
The result of this is:
x before ByVal is 1
x after ByVal is 1
x before ByRef is 1
x after ByRef is 99

 
You should avoid passing basic variable types using ByRef. There are two main reasons for this:

  1. The person passing a value may not expect it to change and this can lead to bugs that are difficult to detect.
  2. Using parentheses when calling prevents ByRef working – see next sub section

A Little-Known Pitfall of ByRef

There is one thing you must be careful of when using ByRef with parameters. If you use parentheses then the sub/function cannot change the variable you pass even if it is passed as ByRef. 

In the following example, we call the sub first without parentheses and then with parentheses. This causes the code to behave differently.

 
For example

' https://excelmacromastery.com/
Sub Test()

    Dim x As Long

    ' Call using without Parentheses - x will change
    x = 1
    Debug.Print "x before (no parentheses): "; x
    SubByRef x
    Debug.Print "x after (no parentheses): "; x

    ' Call using with Parentheses - x will not change
    x = 1
    Debug.Print "x before (with parentheses): "; x
    SubByRef (x)
    Debug.Print "x after (with parentheses): "; x

End Sub

Sub SubByRef(ByRef x As Long)
    x = 99
End Sub

 
If you change the sub in the above example to a function, you will see the same behaviour occurs.

However, if you return a value from the function then ByRef will work as normal as the code below shows:

' https://excelmacromastery.com/
Sub TestFunc()

    Dim x As Long, ret As Long

    ' Call using with Parentheses - x will not change
    x = 1
    Debug.Print "x before (with parentheses): "; x
    FuncByRef (x)
    Debug.Print "x after (with parentheses): "; x
    
    ' Call using with Parentheses and return - x will change
    x = 1
    Debug.Print "x before (with parentheses): "; x
    ret = FuncByRef(x)
    Debug.Print "x after (with parentheses): "; x


End Sub

Function FuncByRef(ByRef x As Long)
    x = 99
End Function

As I said in the last section you should avoid passing a variable using ByRef and instead use ByVal.

This means

  1. The variable you pass will not be accidentally changed.
  2. Using parentheses will not affect the behaviour.

ByRef and ByVal with Objects

When we use ByRef or ByVal with an object, it only affects the variable. It does not affect the actual object.

If we look at the example below:

' https://excelmacromastery.com/
Sub UseObject()
    
    Dim coll As New Collection
    coll.Add "Apple"
    
    ' After this coll with still reference the original
    CollByVal coll
    
    
    ' After this coll with reference the new collection
    CollByRef coll
    
End Sub

Sub CollByVal(ByVal coll As Collection)
    
    ' Original coll will still reference the original
    Set coll = New Collection
    coll.Add "ByVal"

End Sub

Sub CollByRef(ByRef coll As Collection)
    
    ' Original coll will reference the new collection
    Set coll = New Collection
    coll.Add "ByRef"

End Sub

When we pass the coll variable using ByVal, a copy of the variable is created. We can assign anything to this variable and it will not affect the original one.

When we pass the coll variable using ByRef, we are using the original variable. If we assign something else to this variable then the original variable will also be assigned to something else.

You can see find out more about this here.

Optional Parameters

Sometimes we have a parameter that will often be the same value each time the code runs. We can make this parameter Optional which means that we give it a default value.

It is then optional for the caller to provide an argument. If they don’t provide a value then the default value is used.

In the example below, we have the report name as the optional parameter:

Sub CreateReport(Optional reportName As String = "Daily Report")

End Sub

 
If an argument is not provided then name will contain the “Daily Report” text

' https://excelmacromastery.com/
Sub Main()
    
    ' Name will be "Daily Report"
    CreateReport
    
    ' Name will be "Weekly Report"
    CreateReport "Weekly Report"

End Sub

The Optional parameter cannot come before a normal parameter. If you do this you will get an Expected: Optional error.

VBA Expected Optional

 
 
When a sub/function has optional parameters they will be displayed in square parentheses by the Intellisense.

In the screenshot below you can see that the name parameter is in square parentheses.

 

A sub/function can have multiple optional parameters. You may want to provide arguments to only some of the parameters.

There are two ways to do this:
If you don’t want to provide an argument then leave it blank.

A better way is to use the parameter name and the “:=” operator to specify the parameter and its’ value.

The examples below show both methods:

' https://excelmacromastery.com/
Sub Multi(marks As Long _
            , Optional count As Long = 1 _
            , Optional amount As Currency = 99.99 _
            , Optional version As String = "A")
            
    Debug.Print marks, count, amount, version
    
End Sub


Sub UseBlanks()

    ' marks and count
    Multi 6, 5
    
    ' marks and amount
    Multi 6, , 89.99
    
    ' marks and version
    Multi 6, , , "B"
    
    ' marks,count and version
    Multi 6, , , "F"

End Sub

Sub UseName()

    ' marks and count
    Multi 12, count:=5
    
    ' marks and amount
    Multi 12, amount:=89.99
    
    ' marks and version
    Multi 12, version:="B"
    
    ' marks,count and version
    Multi 12, count:=6, version:="F"

End Sub

 
Using the name of the parameter is the best way. It makes the code more readable and it means you won’t have error by mistakenly adding extra commas.

wk.SaveAs "C:Docsdata.xlsx", , , , , , xlShared
    
wk.SaveAs "C:Docsdata.xlsx", AccessMode:=xlShared

IsMissing Function

We can use the IsMissing function to check if an Optional Parameter was supplied.

Normally we check against the default value but in certain cases we may not have a default.

We use IsMissing with Variant parameters because it will not work with basic types like Long and Double.

' https://excelmacromastery.com/
Sub test()
    ' Prints "Parameter not missing"
    CalcValues 6
    
    ' Prints "Parameter missing"   
    CalcValues
    
End Sub

Sub CalcValues(Optional x)

    ' Check for the parameter
    If IsMissing(x) Then
        Debug.Print "Parameter missing"
    Else
        Debug.Print "Parameter Not missing"
    End If

End Sub

Custom Function vs Worksheet Function

When you create a function it appears in the function list for that workbook.

 
Have a look at the function in the next example.

Public Function MyNewFunction()
    MyNewFunction = 99
End Function

 
If you add this to a workbook then the function will appear in the function list. Type “=My” into the function box and the function will appear as shown in the following screenshot.

 
Worksheet Function
If you use this function in a cell you will get the result 99 in the cell as that is what the function returns.

Conclusion

The main points of this post are:

  • Subs and macros are essentially the same thing in VBA.
  • Functions return values but subs do not.
  • Functions appear in the workbook function list for the current workbook.
  • ByRef allows the function or sub to change the original argument.
  • If you call a function sub with parentheses then ByRef will not work.
  • Don’t use parentheses on sub arguments or function arguments when not returning a value.
  • Use parentheses on function arguments when returning a value.

What’s Next?

Free VBA Tutorial If you are new to VBA or you want to sharpen your existing VBA skills then why not try out the The Ultimate VBA Tutorial.

Related Training: Get full access to the Excel VBA training webinars and all the tutorials.

(NOTE: Planning to build or manage a VBA Application? Learn how to build 10 Excel VBA applications from scratch.)

Like this post? Please share to your friends:
  • Excel vba sub workbooks
  • Excel vba sub return
  • Excel vba sub range
  • Excel vba string to number one
  • Excel vba string to long