tags:

views:

341

answers:

3

I want to do this: "If there's a module X containing a function Y then call it, otherwise don't."

I'm aware that I can use CallByName(Object, MethodName, ...) to call a method or property of an object instance.

Is it possible to call a global sub/function which is not bound to an object?

//Module1
Public Sub DoSomething
End Sub

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

I know, it would be better to refactor my code to wrap DoSomething into a class, but currently this is not possible as it would break the code of my coworkers in a way that could not be fixed in a few hours.

+1  A: 

Could conditionnal compilation be ok for your problem ?

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

Then in your project settings you would add the following conditionnal compilation arguments :

  • If DoSomething is present : DoSomething_IsPresent = -1
  • If DoSomething is not present : DoSomething_IsPresent = 0


By the way, be careful with the "On Error Resume Next" in :

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

If DoSomething is present in Module1 but has an unhandled error you won't notice it.

Sébastien Nussbaumer
+3  A: 

It really would be easier to CallByName a class - can't you just wrap the module(s) with a class that redirects the calls to the module?

It's possible to call routines in modules by name using a FunctionDelegator. This is explained in Matt Curland's excellent book Advanced Visual Basic 6.

Googling might find you some hacks using CallWindowProc, but Matt Curland says that's dangerous. Which is pretty much the final word on the matter :)


EDIT: RS Conley's answer is don't use a module, use a class that has a instancing property of GlobalMultiUse and you will be able to use CallbyName. This will work if your code is in a DLL rather than an EXE. RS Conley suggests in any case it is more flexible to have a minimal EXE with nearly all functionality in a DLL: this may well be true.

MarkJ
+1  A: 

Don't use a module, use a class that has a instancing property of GlobalMultiUse and you will be able to use CallbyName

RS Conley
MarkJ
Correct if the class resides in a EXE. I rarely do that anymore preferring to have a minimum of a EXE linked to a DLL. It just more flexible that way.
RS Conley
You might be right. Maybe you should edit the answer to explain that? It's possible DR doesn't already have the code in a DLL. BTW If you have no objection I'm going to edit my answer to include your idea. Leave a comment on it if you'd like me to take it out. I've +1 on your answer.
MarkJ
No problem the points of all this is to get the right answer out.
RS Conley
Great! BTW I browsed some of your other answers. I like the sound of the structure of your VB6 app, I wish our legacy apps were as neat as that. Unfortunately we change them fairly infrequently so they only improve very slowly
MarkJ
Thanks. It was a problem for us as well. What we did is first develop the model the core libraries. Then put anything that modified the model into a Command Object. The forms now created and execute command objects. Then we added the UI interfaces. At each point we had working software.
RS Conley