2009-03-04 3 views
3

Я хочу сделать это: «Если есть модуль X, содержащий функцию Y, тогда позвоните, иначе нет."Есть ли эквивалент CallByName для глобальных функций?

Я знаю, что могу использовать метод CallByName(Object, MethodName, ...) для вызова метода или свойства экземпляра объекта.

Можно ли вызвать глобальную функцию sub /, не связанную с объектом?

//Module1 
Public Sub DoSomething 
End Sub 

//Module2 
Public Sub TriggerDoSomething 
    On Error Resume Next 
    CallByName2 "Module1", "DoSomething", ... 
End Sub 

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

ответ

3

Это действительно было бы проще CallByName класса - не можете ли вы просто обернуть модуль (ы) классом, который перенаправляет вызовы в модуль?

Можно вызвать процедуры в модулях по имени с помощью FunctionDelegator. Это объясняется замечательной книгой Мэтта Керленда Advanced Visual Basic 6.

В Google может быть обнаружен хакс с использованием CallWindowProc, но Мэтт Керленд говорит, что это опасно. Что в значительной степени окончательное слово по этому вопросу :)


EDIT: ответ RS Конли не использует модуль, используется класс, который имеет свойство Instancing GlobalMultiUse, и вы будете иметь возможность использовать CallByName. Это будет работать, если ваш код находится в DLL, а не в EXE. RS Conley предполагает, что в любом случае более гибко иметь минимальный EXE с почти всеми функциональными возможностями в DLL: это вполне может быть правдой.

1

Может ли условная компиляция быть в порядке для вашей проблемы?

//Module2 
Public Sub TriggerDoSomething 
    #If DoSomething_IsPresent Then 
     DoSomething 
    #End if 
End Sub 

Затем в настройках проекта необходимо добавить следующие conditionnal аргументы компиляции:

  • Если DoSomething присутствует: DoSomething_IsPresent = -1
  • Если DoSomething нет: DoSomething_IsPresent = 0

Кстати, будьте осторожны с «Вкл. Ошибка Resume Next»в:

//Module2 
Public Sub TriggerDoSomething 
    On Error Resume Next 
    CallByName2 "Module1", "DoSomething", ... 
End Sub 

Если DoSomething присутствует в Module1, но имеет необработанную ошибку, вы не заметите его.

1

Не используйте модуль, используется класс, который имеет свойство Instancing GlobalMultiUse, и вы будете иметь возможность использовать CallByName

+0

Хорошая идея. Не будет ли это требовать, чтобы класс был перенесен в проект DLL? Что вы могли бы сделать, и это не нарушит клиентский код модуля. Я не мог заставить его работать в EXE. (Пришлось перейти на ActiveX exe, чтобы даже установить класс в GlobalMultiUse.) – MarkJ

+0

Исправьте, если класс находится в EXE. Я редко делаю это, предпочитая иметь как минимум EXE, связанный с DLL. Это просто более гибко. –

+0

Возможно, вы правы. Может быть, вы должны отредактировать ответ, чтобы объяснить это? Возможно, DR еще не имеет кода в DLL. BTW Если у вас нет возражений, я собираюсь изменить свой ответ, чтобы включить вашу идею. Оставьте комментарий на него, если вы хотите, чтобы я взял его. У меня +1 на ваш ответ. – MarkJ

1

Это должно сделать это люди. Принимаю пожертвования.

Public Sub callbyname2(proc As String) 
    Dim vbComp As VBComponent 
    For Each vbComp In ActiveWorkbook.VBProject.VBComponents 
     On Error Resume Next 
     Application.Run (vbComp.name & "." & proc) 
     If Err.Number <> 1004 Then 
      Exit For 
     End If 
    Next 
End Sub 
+0

«ActiveWorkbook» является частью объектной модели Excel, если я правильно помню, не так ли это код VBA, а не код VB6? –

+0

совершенно. но если вам не нужно использовать excel/office, вы действительно не должны использовать VB, я думаю – nicolas

Смежные вопросы