Вызов Sub или Function, содержащихся в модуле, с использованием "CallByName" в VB/VBA
Легко вызвать функцию внутри classModule, используя CallByName. Как насчет функций внутри стандартного модуля?
''#inside class module
''#classModule name: clsExample
Function classFunc1()
MsgBox "I'm class module 1"
End Function
''#
''#inside standard module
''#Module name: module1
Function Func1()
MsgBox "I'm standard module 1"
End Function
''#
''# The main sub
Sub Main()
''# to call function inside class module
dim clsObj as New clsExample
Call CallByName(clsObj,"ClassFunc1")
''# here's the question... how to call a function inside a standard module
''# how to declare the object "stdObj" in reference to module1?
Call CallByName(stdObj,"Func1") ''# is this correct?
End Sub
6 ответов
Я думаю, что ответ jtolle лучше всего отвечал на этот вопрос - небольшая ссылка на Application.Run может быть ответом. Спрашивающий не хочет использовать просто func1 или Module1.func1 - причина, по которой в первую очередь хотелось бы использовать CallByName, заключается в том, что желаемое имя function.sub не известно во время компиляции. В этом случае Application.Run работает, например:
Dim ModuleName As String
Dim FuncName As String
Module1Name = "Module1"
FuncName = "func1"
Application.Run ModuleName & "." & FuncName
Вы также можете добавить имя проекта перед именем модуля и добавить еще один период "." К сожалению, Application.Run не возвращает никаких значений, поэтому, пока вы можете вызывать функцию, вы не получите ее возвращаемое значение.
Хотя это старый вопрос и OP запрашивает CallByName в стандартном модуле, правильные советы разбросаны по ответам и комментариям, и некоторые могут быть неточными, по крайней мере, в 2020 году. Как заявил SlowLearner, Application.run ДЕЙСТВИТЕЛЬНО возвращает Вариант, и в этом случае обе ветви ниже эквивалентны, за исключением обработки ошибок, как прокомментировано в ответе Горовица:
Dim LoadEnumAndDataFrom as Variant
'FunctionName returns a Variant Array
if fCallByName then
LoadEnumAndDataFrom = CallByName(ClassObj, "FunctionNameAtClass", VbMethod)
else
'After moving back function for a standard module
LoadEnumAndDataFrom = Application.Run("StandardModuleName" & "." & "FunctionNameAtStandard")
endif
На самом деле я только что сделал это выше, и у меня не было никаких ошибок, протестировано в Word, Excel и Access, и оба возвращают один и тот же массив.
К сожалению, есть исключение: объектная модель Outlook слишком защищена и не имеет метода Run.
CallByName работает только с объектами класса.
Если ваша подпрограмма находится в стандартном модуле, вы можете сделать это:
Sub Main()
Module1.Func1
End Sub
Если это функция, то вы, вероятно, захотите получить возвращаемое значение; что-то вроде этого:
Sub Main()
Dim var
var = Module1.Func1
End Sub
Модули в VB6 и VBA - это что-то вроде статических классов, но, к сожалению, VB не принимает Module1 как объект. Вы можете написать Module1.Func1 как C.Func1 (C является экземпляром некоторого Class1), но это, очевидно, выполняется компилятором, а не во время выполнения.
Идея: преобразовать Module1 в класс, создать "Public Module1 as Module1" в вашем Startup-модуле и "Set Module1 = New Module1" в вашем "Sub Main".
К сожалению, невозможно предварять ProjectName
перед ModuleName
и добавьте еще один период "." В MS Word это вызывает ошибку времени выполнения 438. Вызов ограничен использованием просто ModuleName.ProcName
,
Это работает:
Public Sub testAppRun()
Dim myfunc As String, teststring As String
myfunc = "testrunfunc"
teststring = "this is my string"
MsgBox Run(myfunc, teststring)
End Sub
Public Function testrunfunc(val As String) As Variant
testrunfunc = val & " changed"
End Function