Vba excel byval что это
vbStr » 01.07.2005 (Пт) 18:56
Во всех декларациях WinApi-функций встречаются ключевые слова ByVal и ByRef. Знаю, что они означают "по значению" и "по ссылке", но где и как их можно использовать? Подскажите? Если можно с примером.Часто в моих кодах использую кучу дублирующих переменных. Чувствую, что это не совсем правильно - плодить это стадо. Думаю, применением передач значений "по ссылке" можно упростить код. Но не знаю как. Спасибо.
A.A.Z. » 01.07.2005 (Пт) 20:15
GSerg писал(а): ByVal и ByRef - два способа передачи параметров. Дело в том, что VB не поддерживает указатели явно, но всё-таки поддерживает. Передача параметра ByRef (она используется по умолчанию, если не указать способ передачи) - это передача указателя на значение. Принимающая процедура должна будет при каждом обращении к параметру получать его значение по указателю. Передача ByVal - передача не указателя, а самого значения. Принимающая функция не должна зырить в указатель, она сразу имеет значение. В языке C, к примеру, передача указателя на целое - int* a, а передача самого целого - int a. В VB передача указателя на целое - byref a (или просто а), передача самого целого - byval a.Передача ByVal имеет смысл при числовых значениях, поскольку указатель обычно имеет размер 4 байта, передаваемое число (к примеру, Long) - тоже, поэтому можно сразу толкать его, так быстрее. А передача ByRef актуальна при передаче указателей на объекты, структуры и массивы (всё это нельзя передать ByVal), и, кроме того, в тех случаях, когда вызываемая процедура должна иметь возможность изменить переданный параметр так, чтобы это изменение возымело эффект в вызывающей процедуре.
FSO » 01.07.2005 (Пт) 20:24
С ключевым словом byVal функция Dll работает с преобразованной формой сток (С) и все изменения отображаются в исходной строке.
без ByVal ты работаешь непосредственно со строкой VB. т.е. стоковая переменная преобразуется на строку OLE(BSRT).
Без кл. слова ByVal практически всегда нарушается содержимое памяти, и возникают фатальные исключения
Думаю, применением передач значений " по ссылке " можно упростить код.
хм. я так не думаю (((
работать сразу со строкой VB муторное дело. В книги Дана Эпплмана подробно все объясняется на пальцах и на примерах (Примеры есть. если хочешь могу выложить или на мыло кинуть).
т.е. в примере вызова API функции:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef pDst As Any, ByRef pSrc As Any, ByVal ByteLen As Long)
CopyMemory a, b, 4& = БУДЕТ РАВНО = CopyMemory a, ByVal VarPtr(b), 4&
,так как функция принимает значение по ссылке (ByRef), инными словами значение "адреса"
ICQ: 75556561
Разработчик Offline Client
ICQ: 233286456
' mov eax, [esp+4]
' mov ecx, [eax]
' add ecx, 1
Private Sub a(l As Long)
l = l + 1
End Sub
' mov eax, [esp+4]
' add eax, 1
Private Sub b(ByVal l As Long)
l = l + 1
End Sub
Как можно видеть передача параметра ByRef, заносит в регистр ecx (в данном случае) ссылку на реальное значение. Это лишняя операция, и именно по этому существует мнение что передача по значению осуществляется быстрее. хотя одна операция с регистрами много код не замедлит (imho)
ICQ: 216865379
Разработчик Offline Client
ICQ: 233286456
Это не ByRef заносит/передает, а при использовании ByRef используется еще один регистр и совершается еще одна операция.
Это я к тому, что если есть возможность, то желательно использовать ByVal.
Т.е. при ByRef в стек положили адрес, по этому адресу отокопали число и уже только тогда с ним можно работать (тут прибавляется 1).
А при ByVal, в стеке уже все готовенькое, берем и используем ))
А про есх, с тем же успехом тут можно было написать mov eax, [eax].
PS
Это отдизасемблированный код. и я не намерен сомневаться в его истинности ))
PPS
Возможно я и не прав. но по-моему все правда :D
Разработчик Offline Client
ICQ: 233286456
Суть в чем, п++ри использовании ByRef передается адрес, чтобы работать с реальным значением, нужно взять его по этому переданному в функцию адресу. Для этого VB сделал mov eсx, [eax], можно было бы записать mov eax, [eax], но это не суть важно.
Я к тому, что, при передаче по ссылке, делается одна лишняя, по сравнению с передачей по значению, операция. вот и все.
т.е. в примере вызова API функции:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef pDst As Any, ByRef pSrc As Any, ByVal ByteLen As Long)
CopyMemory a, b, 4& = БУДЕТ РАВНО = CopyMemory a, ByVal VarPtr(b), 4&
,так как функция принимает значение по ссылке (ByRef), инными словами значение "адреса"
ICQ: 334781088
>> Это я к тому, что если есть возможность, то желательно использовать ByVal.
Всем спасибо. Особенно digitin.
Разработчик Offline Client
ICQ: 233286456
ICQ: 204447456
ByVal:
------
mov eax, [esp+4] 'Переслать в аккумулятор(EAX) число, находящееся по адресу: вершина стёка(ESP) - 4 байта (или извлечь из него верхние 32 бита).
add eax, 1 'Увеличить аккумулятор на 1
ByRef:
------
mov eax, [esp+4] 'Переслать в аккумулятор(EAX) число, находящееся по адресу: вершина стёка(ESP) - 4 байта (или извлечь из него верхние 32 бита).
mov ecx, [eax] 'Переслать в счётчик(ECX) число, находящееся по адресу, указанному в аккумуляторе.
add ecx, 1 'Увеличить счётчик на 1
Ну ты понимаешь, что это на обратный вывод наталкивает?
"Пользуйте по возможности ByRef, так как для чисел - это не важно, а для String, и Variant это играет огромную роль"
В Visual Basic процедуры и функции выполняют важную роль при работе с этим языком. Например, они способны:
- устранить лишние строки в вашем коде, потому что можно один раз и в одном месте создать процедуру или функцию, а потом вызывать ее при необходимости;
- улучшить восприятие ваших скриптов, так как их легче читать и понимать;
- упростить разработку скриптов, потому что не нужно постоянно повторять один и тот же код, а скрипты будут разделены на отдельные логические блоки.
Visual Basic (VBA) функции и процедуры
- функция по своей особенности может возвращать какое-то значение через собственное имя, то есть ее можно применять в качестве операнда в выражениях, а процедура может возвращать результаты только через параметры, поэтому ее нельзя применять в выражениях;
- функция вызывается путем указания ее имени в каком-либо операторе, а процедура вызывается отдельным оператором.
Процедуры VBA
Процедурам, как и функциям, нужно давать уникальные имена и при необходимости дописывать требуемые параметры.
Процедура в VBA имеет следующий шаблон построения:
Sub НаименованиеПроцедуры ([параметры процедуры через «запятую»])
ОператорыПроцедуры
- «НаименованиеПроцедуры» — это уникальное имя процедуры Sub;
- параметры можно указывать, а можно не указывать;
- «ОператорыПроцедуры» — в этом блоке расположены все операторы, которые определяют функциональность процедуры.
Передача параметров в процедуру VBA
Когда мы описываем процедуру, в круглых скобках мы можем указать какие-то параметры. На самом деле, эти параметры являются «формальными», так как являются всего лишь местом, где будут указываться фактические параметры.
Когда мы вызываем процедуру, в ней располагаются фактические параметры, чьи значения нам уже известны. Такие значения мы можем передавать в процедуру по ссылке или по значению. Потому что каждая переменная в процедуре имеет свое собственное значение и уникальный адрес расположения в оперативной памяти компьютера.
Вот и получается, что VBA дает возможность передавать параметры в процедуру, используя уникальное значение переменной или по ее адресу в оперативной памяти.
- ByVal — это ключевое слово, которое нужно указывать, если происходит передача параметров в процедуру VBA по значению переменной.
- ByRef — это ключевое слово, которое нужно указывать, если происходит передача параметров в процедуру VBA по ссылке переменной.
Функции в Visual Basic
- Математические. Например: Abs, Cos, Exp, Int, Fix, Log, Rnd, Round, Sin и др.
- Для преобразования типов и представления данных. Например: Cbool, Cbyte, Ccur, Cdate, Csng. Cvar, Hex и др.
- Для работы с массивами. Например: Array, Erase, Lbound, Ubound и др.
- Для обработки строк. Например: Asc, Choose, Chr, Error, Filter, Format и др.
- Стандартные, для ввода-вывода и работы с цветом. Например: InputBox, MsgBox, QBColor, RGB и др.
- Для работы с датой и временем. Например: Date, DateAdd, DateDiff, Day, Hour, Minute и др.
- Для работы с папками и файлами. Например: ChDir, ChDrive, Close, FileAttr и др.
- Для работы с объектами и приложениями. Например: CallByName, CreateObject, Environ и др.
- Функции статуса. Например: IsArray, IsDate, IsError, IsNull и др.
- Финансовые. Например: DDB, FV, Ipmt, IRR, MIRR, NPV и др.
Заключение
В Visual Basic (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) в каждую ячейку в выделенном диапазоне. Передать процедуре это число можно при помощи аргумента, вот так:
Имейте в виду, что наличие аргументов для процедур Function и Sub в VBA не является обязательным. Для некоторых процедур аргументы не нужны.
Необязательные аргументы
Процедуры VBA могут иметь необязательные аргументы. Это такие аргументы, которые пользователь может указать, если захочет, а если они пропущены, то процедура использует для них заданные по умолчанию значения.
Возвращаясь к предыдущему примеру, чтобы сделать целочисленный аргумент функции необязательным, его нужно объявить вот так:
В таком случае целочисленный аргумент i по умолчанию будет равен 0.
Необязательных аргументов в процедуре может быть несколько, все они перечисляются в конце списка аргументов.
Передача аргументов по значению и по ссылке
Аргументы в VBA могут быть переданы процедуре двумя способами:
- ByVal – передача аргумента по значению. Это значит, что процедуре передаётся только значение (то есть, копия аргумента), и, следовательно, любые изменения, сделанные с аргументом внутри процедуры, будут потеряны при выходе из неё.
- ByRef – передача аргумента по ссылке. То есть процедуре передаётся фактический адрес размещения аргумента в памяти. Любые изменения, сделанные с аргументом внутри процедуры, будут сохранены при выходе из процедуры.
При помощи ключевых слов ByVal или ByRef в объявлении процедуры можно задать, каким именно способом аргумент передаётся процедуре. Ниже это показано на примерах:
Помните, что аргументы в VBA по умолчанию передаются по ссылке. Иначе говоря, если не использованы ключевые слова ByVal или ByRef, то аргумент будет передан по ссылке.
Перед тем как продолжить изучение процедур Function и Sub более подробно, будет полезным ещё раз взглянуть на особенности и отличия этих двух типов процедур. Далее приведены краткие обсуждения процедур VBA Function и Sub и показаны простые примеры.
VBA процедура «Function»
Редактор VBA распознаёт процедуру Function, когда встречает группу команд, заключённую между вот такими открывающим и закрывающим операторами:
Как упоминалось ранее, процедура Function в VBA (в отличие от Sub), возвращает значение. Для возвращаемых значений действуют следующие правила:
- Тип данных возвращаемого значения должен быть объявлен в заголовке процедуры Function.
- Переменная, которая содержит возвращаемое значение, должна быть названа так же, как и процедура Function. Эту переменную не нужно объявлять отдельно, так как она всегда существует как неотъемлемая часть процедуры Function.
Это отлично проиллюстрировано в следующем примере.
Пример VBA процедуры «Function»: Выполняем математическую операцию с 3 числами
Ниже приведён пример кода VBA процедуры Function, которая получает три аргумента типа Double (числа с плавающей точкой двойной точности). В результате процедура возвращает ещё одно число типа Double, равное сумме первых двух аргументов минус третий аргумент:
Эта очень простая VBA процедура Function иллюстрирует, как данные передаются процедуре через аргументы. Можно увидеть, что тип данных, возвращаемых процедурой, определён как Double (об этом говорят слова As Double после списка аргументов). Также данный пример показывает, как результат процедуры Function сохраняется в переменной с именем, совпадающим с именем процедуры.
Вызов VBA процедуры «Function»
Если рассмотренная выше простая процедура Function вставлена в модуль в редакторе Visual Basic, то она может быть вызвана из других процедур VBA или использована на рабочем листе в книге Excel.
Вызов VBA процедуры «Function» из другой процедуры
Процедуру Function можно вызвать из другой VBA процедуры при помощи простого присваивания этой процедуры переменной. В следующем примере показано обращение к процедуре SumMinus, которая была определена выше.
Вызов VBA процедуры «Function» из рабочего листа
VBA процедуру Function можно вызвать из рабочего листа Excel таким же образом, как любую другую встроенную функцию Excel. Следовательно, созданную в предыдущем примере процедуру Function – SumMinus можно вызвать, введя в ячейку рабочего листа вот такое выражение:
VBA процедура «Sub»
Редактор VBA понимает, что перед ним процедура Sub, когда встречает группу команд, заключённую между вот такими открывающим и закрывающим операторами:
VBA процедура «Sub»: Пример 1. Выравнивание по центру и изменение размера шрифта в выделенном диапазоне ячеек
Рассмотрим пример простой VBA процедуры Sub, задача которой – изменить форматирование выделенного диапазона ячеек. В ячейках устанавливается выравнивание по центру (и по вертикали, и по горизонтали) и размер шрифта изменяется на заданный пользователем:
Данная процедура Sub выполняет действия, но не возвращает результат.
В этом примере также использован необязательный (Optional) аргумент iFontSize. Если аргумент iFontSize не передан процедуре Sub, то его значение по умолчанию принимается равным 10. Однако же, если аргумент iFontSize передается процедуре Sub, то в выделенном диапазоне ячеек будет установлен размер шрифта, заданный пользователем.
VBA процедура «Sub»: Пример 2. Выравнивание по центру и применение полужирного начертания к шрифту в выделенном диапазоне ячеек
Следующая процедура похожа на только что рассмотренную, но на этот раз, вместо изменения размера, применяется полужирное начертание шрифта в выделенном диапазоне ячеек. Это пример процедуры Sub, которой не передаются никакие аргументы:
Вызов процедуры «Sub» в Excel VBA
Вызов VBA процедуры «Sub» из другой процедуры
Чтобы вызвать VBA процедуру Sub из другой VBA процедуры, нужно записать ключевое слово Call, имя процедуры Sub и далее в скобках аргументы процедуры. Это показано в примере ниже:
Если процедура Format_Centered_And_Sized имеет более одного аргумента, то они должны быть разделены запятыми. Вот так:
Вызов 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 процедурам:
Помните о том, что если перед объявлением VBA процедуры Function или Sub ключевое слово не вставлено, то по умолчанию для процедуры устанавливается свойство Public (то есть она будет доступна везде в данном проекте VBA). В этом состоит отличие от объявления переменных, которые по умолчанию бывают Private.
Ранний выход из VBA процедур «Function» и «Sub»
Обратите внимание, что перед тем, как завершить выполнение процедуры Function – VAT_Amount, в код вставлена встроенная VBA функция MsgBox, которая показывает пользователю всплывающее окно с предупреждением.
Читайте также: