Вызов 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
Другие вопросы по тегам