неправильный вызов или аргумент процедуры при вызове функции в excel vba. Vba функции вызов


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

  • 06/08/2017
  • Время чтения: 3 мин
  • Соавторы

В этой статье

Вызов процедуры Sub из другой процедуры, введите имя процедуры и включать значения для все обязательные аргументы.To call a Sub procedure from another procedure, type the name of the procedure and include values for any required arguments. Оператор Call не требуется, но при использовании его необходимо заключить аргументы в скобки.The Call statement is not required, but if you use it, you must enclose any arguments in parentheses.

Процедуры Sub можно использовать для организации других процедур, что значительно упростит для понимания и отладки.You can use a Sub procedure to organize other procedures so they are easier to understand and debug. В следующем примере процедуры Sub Main вызывает процедуру Sub MultiBeep, передав 56 значение для аргумента.In the following example, the Sub procedure Main calls the Sub procedure MultiBeep, passing the value 56 for its argument.

После MultiBeep потоками, управление возвращается Main, и Main вызывает процедуру Sub Message.After MultiBeep runs, control returns to Main, and Main calls the Sub procedure Message. MessageОтображает окно сообщения; При нажатии кнопки ОКуправление возвращается Main, и Main завершения.Message displays a message box; when the user clicks OK, control returns to Main, and Main finishes.

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 с несколькими аргументамиCalling Sub procedures with more than one argument

Следующий пример показывает два способа вызова процедуры Sub с несколькими аргументами.The following example shows two ways to call a Sub procedure with more than one argument. Во второй раз при вызове, скобки необходимы для аргументов так как используется оператор Call .The second time it is called, parentheses are required around the arguments because the Call statement is used.

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

Использование скобок при вызове процедур функцииUsing parentheses when calling function procedures

Чтобы использовать возвращаемое значение функции, назначьте ее переменной, и заключите аргументы в скобки, как показано в следующем примере.To use the return value of a function, assign the function to a variable and enclose the arguments in parentheses, as shown in the following example.

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

Если вы не хотите возвращаемое значение функции, можно вызвать функцию так же, как вызов процедуры Sub .If you are not interested in the return value of a function, you can call a function the same way you call a Sub procedure. Опустить скобки, списка аргументов и не присвоить функцию переменной, как показано в следующем примере.Omit the parentheses, list the arguments, and do not assign the function to a variable, as shown in the following example.

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

Если включить скобки в предыдущий пример, оператор вызывает ошибку синтаксиса.If you include parentheses in the preceding example, the statement causes a syntax error.

Передача именованных аргументовPassing named arguments

Оператор в процедуре Sub или Function можно передать значения вызываемых процедур, используя именованные аргументы.A statement in a Sub or Function procedure can pass values to called procedures using named arguments. Можно получить список именованных аргументов в любом порядке.You can list named arguments in any order. Именованный аргумент состоит из имени аргумента, за которым следует двоеточие и знак равенства (: =) и значение аргумента.A named argument consists of the name of the argument followed by a colon and an equal sign (:=), and the value assigned to the argument.

В следующем примере функция MsgBox вызывается с использованием именованных аргументов без возвращаемого значения.The following example calls the MsgBox function using named arguments with no return value.

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

В следующем примере вызывается функция MsgBox с использованием именованных аргументов.The following example calls the MsgBox function using named arguments. Возвращаемое значение присваивается переменной.The return value is assigned to the variable.

answer3 = MsgBox(Title:="Question 3", _ Prompt:="Are you happy with your salary?", Buttons:=4)

msdn.microsoft.com

function - Как вызвать функцию VBA в процедуру Sub

Вызов вспомогательной процедуры - трехсторонняя технология

Как только у вас есть процедура, независимо от того, создан ли она или она является частью языка Visual Basic, вы можете ее использовать. Использование процедуры также называется вызовом.

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

Sub CreateCustomer() Dim strFullName As String strFullName = "Paul Bertrand Yamaguchi" msgbox strFullName End Sub Sub Exercise() CreateCustomer End Sub

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

Sub CreateCustomer() Dim strFullName As String strFullName = "Paul Bertrand Yamaguchi" End Sub Sub Exercise() Call CreateCustomer End Sub

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

Sub CreateCustomer() Dim strFullName As String strFullName = "Paul Bertrand Yamaguchi" End Sub Sub Exercise() CreateCustomer() End Sub

Процедуры и уровни доступа

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

Private Sub CreateCustomer() Dim strFullName As String strFullName = "Paul Bertrand Yamaguchi" End Sub

Правила, применяемые к глобальным переменным, одинаковы:

Закрыто: если процедура сделана частной, ее можно вызвать другими процедурами того же модуля. Процедуры внешних модулей не могут получить доступ к такой процедуре.

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

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

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

qaru.site

Вызов функции VBA: клавиша Excel против VBS-вызова

Я борюсь с VBA Sub, который вызывается кнопкой. Этот Sub открывает таблицу Configuration.xls Excel из жестко закодированного пути к файлу. MsgBox расскажет мне о текущей рабочей области - рабочая область изменяется от текущего файла до только что открытого. Здесь все хорошо.

Теперь я хочу выполнить этот Sub из внешней партии, которая вызывает VBS, который вызывает VBA Sub. Рабочее пространство после открытия файла Configuration.xls остается неизменным и не изменяется в Configuration.xls. Кроме того, при вызове Sub на VBS функция запускается дважды - не подскажите почему.

Так что мой вопрос: почему у меня разные способы взаимодействия между двумя механизмами вызова?

Я упростил приведенный ниже код, поскольку он показывает то же поведение, что и мой более сложный реальный код.

Sub ReadConfiguration() MsgBox ActiveWorkbook.Name FileExcel = "D:\_Trash\VBA_VBS\Configuration.xls" Workbooks.Open Filename:=FileExcel, ReadOnly:=True, IgnoreReadOnlyRecommended:=True strFileName = FunctionGetFileName(FileExcel) MsgBox ActiveWorkbook.Name On Error Resume Next Set wBook = Workbooks(strFileName) If Err Then Exit Sub End If ActiveWorkbook.Close savechanges:=False End Sub '***************************************************** Function FunctionGetFileName(FullPath As Variant) Dim StrFind As String Do Until Left(StrFind, 1) = "\" iCount = iCount + 1 StrFind = Right(FullPath, iCount) If iCount = Len(FullPath) Then Exit Do Loop FunctionGetFileName = Right(StrFind, Len(StrFind) - 1) End Function '*****************************************************

VBS выглядит следующим образом

Dim args, objExcel Set args = WScript.Arguments Set objExcel = CreateObject("Excel.Application") objExcel.Workbooks.Open args(0) objExcel.Visible = False objExcel.Run "Module1.ReadConfiguration()" objExcel.ActiveWorkbook.Close(0) objExcel.Quit

stackoverrun.com

Вызов функции доступа VBA из Excel

Я создаю лист компенсации. Таблицы и ключевая информация находятся в базе данных доступа, Compensation.accdb, которая имеет функцию для определения компенсации, основанной на контракте агента. Если агент является «REP», функция Access VBA выполняет одно вычисление, и если агент является SRP, он выполняет другое. Несколько отдельных пользователей хотят вызвать эту функцию из Excel (кстати, MS Office 2013). Идея заключается в том, что пользователь меняет или вводит количество в своей электронной таблице, а электронная таблица вызывает функцию VBA Compensation.accdb. Compensation.accdb выполняет вычисление и передает значение обратно в исходную таблицу.

Вот код Compensation.accdb VBA:

Option Compare Database Function AutoComp(WritingRepContract As String) As Integer 'Auto insurance 'Debug.Print WritingRepContract If WritingRepContract = "REP" Then AutoComp = 1 'Compensation formula for Rep will go here End If If WritingRepContract = "SRP" Then AutoComp = 2 'Compensation formula for Senior Rep will go here, etc. End If End Function

Вот код Excel VBA:

Public Sub Worksheet_Change(ByVal Target As Range) 'Is there a better way than this??? Dim WritingLevel As String If Target.Address = "$B$8" Then 'This is the cell where one would enter Auto value. If Target.Value = 1 Then 'just a test to see if working WritingLevel = "REP" Else WritingLevel = "SRP" End If CallAutoComp (WritingLevel) End If End Sub Sub CallAutoComp(WritingLevel) Dim appAccess As Access.Application Dim test As Integer Set appAccess = New Access.Application Debug.Print appAccess.Eval("AutoComp(WritingLevel)") 'A test to see what is happening With appAccess .OpenCurrentDatabase "C:\Mypath\Compensation.ACCDB" .Visible = False ' Useful for debugging when true .Eval ("AutoComp(WritingLevel)") End With test = appAccess.Eval("AutoComp(WritingLevel)") With appAccess .CloseCurrentDatabase .Quit End With End Sub

При изменении значения в B8 я получаю это:

Run -time error 2425: Введенное выражение имеет имя функции , которое Microsoft Access не может найти.

Он не любит следующие утверждения (то же самое 2425 ошибка для всех трех утверждений):

Debug.Print statement .Eval ("AutoComp(WritingLevel))") statement test = appAccess.Eval("AutoComp(WritingLevel)")

Я попробовал несколько версий одинарных и двойных кавычек и "&" окружающих WritingLevel без успеха.

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

Когда я заменяю AutoComp(WritingLevel) на AutoComp(SRP) или AutoComp(REP), он отлично работает.

stackoverrun.com

syntax - Каковы правила, регулирующие использование скобок в вызовах функций VBA?

В VB (A) существует идеальная логика для правила скобок в скобках, и это происходит следующим образом.

Если процедура (функция или под) вызывается с аргументами, а вызов находится в строке с другими операторами или ключевыми словами, аргументы должны быть заключены в круглые скобки. Это позволяет отличать аргументы, принадлежащие вызову процедуры от остальной части строки. Итак:

1: If CheckConditions(A, B, C) = DONT_PROCEED Then Exit Sub

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

2: If CheckConditions A, B, C = DONT_PROCEED Then Exit Sub

Потому что невозможно разобрать.

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

3: SaveNewValues Value1, Value2, Value3

В то время как это приводит к синтаксической ошибке (по причинам, описанным ниже):

4: SaveNewValues(Value1, Value2, Value3)

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

5: Call SaveNewValues(Value1, Value2, Value3)

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

Этот вопрос путают дополнительные круглые скобки в VB (A) (и многие другие языки): они также указывают приоритет оценки для выражений. Если вы используете круглые скобки в любом другом контексте, но для приложения аргументов вызова процедуры, VB (A) попытается оценить выражение в круглых скобках в результате простого значения.

Таким образом, в примере 4, где скобки являются незаконными для включения аргументов, VB (A) вместо этого попытается оценить выражение в круглых скобках. Поскольку (Value1, Value 2, Value3) не является выражением, которое может быть оценено, возникает синтаксическая ошибка.

Это также объясняет, почему вызовы с переменной, переданной ByRef, действуют так, как если бы они назывались ByVal, если аргумент заключен в круглые скобки. В приведенном выше примере, где функция p вызывается с параметром ByRef a, существует большая разница между этими двумя вызовами p:

6: p a

и

7: p(a)

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

В 7 аргумент заключен в круглые скобки в любом случае, в результате чего VB (A) оценивает прилагаемое выражение к простому значению. Это, конечно, само определение прохождения ByVal. Скобки гарантируют, что вместо указателя на a передается значение a, а a остается неизмененным.

Это также объясняет, почему правило круглых скобок не всегда кажется господствующим. Самый яркий пример - вызов MsgBox:

8: MsgBox "Hello World!"

И

9: MsgBox ("Hello World!")

Оба правильны, хотя правило скобок указывает, что 9 должно быть неправильным. Это, конечно, но все, что происходит, это то, что VB (A) оценивает выражение в круглых скобках. И строковый литерал оценивается с помощью одного и того же строкового литерала, так что фактический сделанный вызов равен 8. Другими словами: вызовы процедур с одним аргументом с константными или строковыми литералами имеют одинаковый результат с круглыми скобками или без них. (Вот почему даже моим вызовам MsgBox предшествует ключевое слово Call.)

Наконец, это объясняет нечетные ошибки несоответствия типа и странное поведение при передаче аргументов Object. Скажем, ваше приложение имеет процедуру HighlightContent, которая принимает аргумент TextBox как аргумент (и вы никогда не догадаетесь, выделяет его содержимое). Вы вызываете это, чтобы выбрать весь текст в текстовом поле. Вы можете вызвать эту процедуру тремя синтаксически правильными способами:

10: HighlightContent txtName 11: HighlightContent (txtName) 12: Call HighlightContent(txtName)

Скажем, ваш пользователь ввел "Джон" в текстовое поле, и ваше приложение вызывает HighlightContent. Что произойдет, какой вызов будет работать?

10 и 12 являются правильными; в текстовом поле будет выделено имя John. Но 11 синтаксически корректен, но приведет к ошибке компиляции или времени выполнения. Зачем? Потому что круглые скобки неуместны. Это побудит VB (A) попытаться оценить выражение в круглых скобках. И результат оценки объекта чаще всего будет значением его свойства по умолчанию;.Text, в этом случае. Поэтому вызов процедуры типа 11 не передаст объект TextBox процедуре, а строковое значение "Джон". Результат в несоответствии типов.

qaru.site

vba - неправильный вызов или аргумент процедуры при вызове функции в excel vba

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

Private Sub Lotus2_Click() ThisWorkbook.Send_Unformatted_Rangedata (2) End Sub

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

********* UPDATE ******************* Привет, я просто нашел что-то не так с этой строкой с сообщением об Run time error -2147417851 (80010105) Automation error The server threw an exception:

Set noDocument = noDatabase.CreateDocument

Но я не вижу в этом ничего плохого. Любая помощь будет очень признательна.

Sub Send_Unformatted_Rangedata(i As Integer) Dim noSession As Object, noDatabase As Object, noDocument As Object Dim vaRecipient As Variant Dim rnBody As Range Dim Data As DataObject Dim rngGen As Range Dim rngApp As Range Dim rngspc As Range Dim stSubject As String stSubject = "E-Mail For Approval for " + (Sheets("Summary").Cells(i, "A").Value) + " for the Project " + Replace(ActiveWorkbook.Name, ".xls", "") 'Const stMsg As String = "Data as part of the e-mail body." 'Const stPrompt As String = "Please select the range:" 'This is one technique to send an e-mail to many recipients but for larger 'number of recipients it more convenient to read the recipient-list from 'a range in the workbook. vaRecipient = VBA.Array(Sheets("Summary").Cells(i, "U").Value, Sheets("Summary").Cells(i, "V").Value) On Error Resume Next 'Set rnBody = Application.InputBox(Prompt:=stPrompt, _ Default:=Selection.Address, Type:=8) 'The user canceled the operation. 'If rnBody Is Nothing Then Exit Sub Set rngGen = Nothing Set rngApp = Nothing Set rngspc = Nothing Set rngGen = Sheets("General Overview").Range("A1:C30").SpecialCells(xlCellTypeVisible) Set rngApp = Sheets("Application").Range("A1:E13").SpecialCells(xlCellTypeVisible) Set rngspc = Sheets(Sheets("Summary").Cells(i, "P").Value).Range(Sheets("Summary").Cells(i, "Q").Value).SpecialCells(xlCellTypeVisible) Set rngspc = Union(rngspc, Sheets(Sheets("Summary").Cells(i, "P").Value).Range(Sheets("Summary").Cells(i, "R").Value).SpecialCells(xlCellTypeVisible)) On Error GoTo 0 If rngGen Is Nothing And rngApp Is Nothing And rngspc Is Nothing Then MsgBox "The selection is not a range or the sheet is protected. " & _ vbNewLine & "Please correct and try again.", vbOKOnly Exit Sub End If 'Instantiate Lotus Notes COM objects. Set noSession = CreateObject("Notes.NotesSession") Set noDatabase = noSession.GETDATABASE("", "") 'Make sure Lotus Notes is open and available. If noDatabase.IsOpen = False Then noDatabase.OPENMAIL 'Create the document for the e-mail. Set noDocument = noDatabase.CreateDocument 'Copy the selected range into memory. rngGen.Copy rngApp.Copy rngspc.Copy 'Retrieve the data from then copied range. Set Data = New DataObject Data.GetFromClipboard 'Add data to the mainproperties of the e-mail document. With noDocument .Form = "Memo" .SendTo = vaRecipient .Subject = stSubject 'Retrieve the data from the clipboard. .Body = Data.GetText & " " & stMsg .SaveMessageOnSend = True End With 'Send the e-mail. With noDocument .PostedDate = Now() .send 0, vaRecipient End With 'Release objects from memory. Set noDocument = Nothing Set noDatabase = Nothing Set noSession = Nothing 'Activate Excel for the user. AppActivate "Microsoft Excel" 'Empty the clipboard. Application.CutCopyMode = False MsgBox "The e-mail has successfully been created and distributed.", vbInformation End Sub

qaru.site

vba - Вызов функции VBA

Это вариант ответа, уже заданного haarrrgh, поэтому, если вы сочтете это полезным, не забудьте также его перенести.

Существует еще один способ справиться с заполнителями в ваших функциональных вызовах, хранящихся в базе данных. Во-первых, измените данные таким образом:

**Record 1 task Function call** 124567 Email customer Call function emailcus([TokenA],[TokenB]) 434535 AddCost Call function addcost([TokenA],[TokenB])

Обратите внимание, что [SquareBrackets] - это не фактически необходимый синтаксис в этом примере, просто то, что я обычно использую в этой ситуации. Важная часть состоит в том, чтобы сделать параметр tokens тем, что не отображается в другом месте строкового значения (включая другие токены). Вы можете использовать столько параметров, сколько вам нужно, просто убедитесь, что вызывающий код знает, сколько из них ожидается в каждой строке функционального вызова (я сократил его, чтобы сократить мой следующий код).

Затем, когда нужно вызвать функцию, сделайте следующее:

Dim ReturnValue As String 'or as appropriate for individual the function return Dim EvalString As String EvalString = 'code to fetch from table EvalString = Replace(EvalString, "[TokenA]", strValueA) 'strValueA passed in? EvalString = Replace(EvalString, "[TokenB]", strValueB) 'strValueB passed in? ReturnValue = Eval(EvalString)

В VB6, по крайней мере (так что я предполагаю, что это правда в VBA), Replace быстрее, чем конкатенация. Я также считаю, что это более читаемо, но это может быть связано с тем, что я привык к тому, что использовал подобный метод для создания SQL-команд в коде (используя объявления Const, а не хранилище БД, но это тоже сработает).

ИЗМЕНИТЬ

Как я перечитывал свой "законченный" пост сразу после его представления, я понял, что там есть пропасть. Поскольку вы выполняете подстановку перед отправкой строки в Eval, это фактические значения, которые помещаются в строку, не. Код, представленный выше, отлично работает , если, ваши параметры являются числовыми, но если они являются строковыми типами, вы должны включать кавычки либо в свои данные, либо в ваш вызов Replace. Я предпочитаю первое, поэтому измените свои данные на это:

**Record 1 task Function call** 124567 Email customer Call function emailcus('[TokenA]','[TokenB]') 434535 AddCost Call function addcost('[TokenA]','[TokenB]')

Это работает как проверено с помощью Const. Сохраненный в записи DB, вам может понадобиться это:

**Record 1 task Function call** 124567 Email customer Call function emailcus(""[TokenA]"",""[TokenB]"") 434535 AddCost Call function addcost(""[TokenA]"",""[TokenB]"")

(который также работает с Const...).

Альтернативой является оставить данные так, как они есть в моей первой части, и изменить вызовы Replace:

EvalString = Replace(EvalString, "[TokenA]", """" & strValueA & """") 'strValueA passed in? 'or maybe EvalString = Replace(EvalString, "[TokenB]", "'" & strValueB & "'") 'strValueA passed in?

Пара других потенциальных ошибок: эти должны быть функциями, а не Subs, и они должны быть объявлены Public в модуле, а не в коде формы.

qaru.site