How can I run several macros where the Macro name begins with a specific string of characters? - vba

I've created several custom functions which I would like to Register. Currently, I have a different procedure for which I specify the registration for each function (there's no issue with that piece). However, the only way I know of to registering all these functions is by calling each Macro by name in another procedure like this:
Sub spRegisterFunctions()
Call spRegisterCUSTOMAfunction
Call spRegisterCUSTOMBfunction
Call spRegisterCUSTOMCfunction
Call spRegisterCUSTOMDfunction
End Sub
I'm actually looking for something more dynamic so that every time I create a new function, and it's corresponding "spRegister..." procedure, I don't have to remember to add the "Call" code to the "Sub spRegisterFunction()" procedure for that specific function.
Here's an example of what attempting to do:
Sub spRegisterFunctions()
Dim mc as Macro
For Each mc in VBProject("NameOfProject").Module("NameOfModule")
If Left(mc.Name,10)="spRegister" then
Call mc
End If
Next mc
End Sub
As you can see, I'm attempting to run any macro in a specific module who's name begins with "spRegister". Obviously the code above will not work, partly because some of those objects don't even exist.
Is there any way to do this?

Related

Passing arguments from Visio ShapeSheet to procedure in VBA

I have been working with Visio VBA for a couple of years. I pass arguments from the ShapeSheet of a shape to several procedures in VBA using either RUNMACRO() or CALLTHIS() Functions.
I either pass pass plain strings or the value of different formulas in the ShapeSheet. The most common argument that I pass to my procedures is the ID() of the shape.
After a patch update of Windows: https://support.microsoft.com/en-us/topic/march-15-2021-kb5001566-os-build-18363-1441-out-of-band-23c4c824-8638-43e9-a381-ff58213ae6fe, I am no longer able to pass arguments from the ShapeSheet of a Shape to my procedures in VBA. Whenever I use RUNMACRO or CALLTHIS, all the arguments that I pass, even if they are plain strings, in my procedure side everything that I get is "", blank information.
Is there a way to know if this is a bug or if this is on purpose, maybe as a security measure?
Here is a simple example procedure:
Public Function HelloWorld(Number As Integer)
If Number = 1 Then
MsgBox ("Hello World 1")
End If
If Number = 2 Then
MsgBox ("Hello World 2")
End If
End Function
And this procedure is called in the EventDblClick of a Shape:
RUNMACRO("HelloWorld(1)","Test")
When the EventDblClick is triggered the value of Number stays as null, ignoring the argument sent in the RUNMACRO function, which is a 1. Since the argument of Number in the HelloWorld() function is not optional, it triggers a Compile error message
"Argument not optional"
My programs were also recently affected by this update. Previously, I was able to structure the ‘macroname’ string in RUNMACRO (macroname [,projname_opt]) to include arguments to my functions and subroutines (as in Alexis’ HelloWorld example). However, that suddenly seems to be no longer possible. It is almost as if RUNMACRO is now modifying the ‘macroname’ string to exclude any arguments prior to making the call to the Function or Subroutine.
One workaround that I have found is to use CALLTHIS and restructure the VBA Function or Subroutine slightly as shown below. That said, it is going to be a huge hassle for me to execute this change in every cell, in every shape, in every file using the RUNMACRO formula. I’m going to have to write a separate macro just to execute this change.
Workaround:
CALLTHIS(HelloWorld,,1)
[NOTE: The two commas are intentional.]
Public Function HelloWorld(callingShape as Visio.Shape, number as Integer)
‘Insert Code Here
End Function

Name error when trying to call a function

I'm still learning VBA so I might be doing a lot of very basic mistakes. At the moment I'm trying to make a macro which could count the rows of a table. This sub works perfectly (with a table named "Tab").
Sub AddRowTable()
ActiveSheet.ListObjects("Tab").ListRows.Add (2)
End Sub
However, when I try to convert this sub to a function so I can call it with the name of the table as variable, I get a name error when writing "=AddRowTableFunction(Tab)" in a cell.
Function AddRowTableFunction(TableName)
ActiveSheet.ListObjects(TableName).ListRows.Add (3)
End Function
I understand that it is just a problem of type, but I just cant find how to do it properly.
Thanks.
At the moment I'm trying to make a macro which could count the rows of a table.
First off, that is not what your code is doing. Your code is adding a row to the table. The number of rows would be accessed using ListRows.Count.
when I try to convert this sub to a function so I can call it with the name of the table as variable...
You don't need a Function in order to include a variable. The differance between a Sub and a Function is that a Function returns a variable, while a Sub does not (i.e. a Function gives back a variable to the code that used it). Both Subs and Functions can take variables.
A Function that returns the number of rows in a given table would be something like this:
Function AddRowTableFunction(TableName As String)
AddRowTableFunction = ActiveSheet.ListObjects(TableName).ListRows.Count
End Function
For adding a row, you would probably use a Sub, because the action of adding a row doesn't return any information:
Sub AddRowTable(TableName As String)
ActiveSheet.ListObjects(TableName).ListRows.Add
End Sub
Finally, when using the Function in a formula, as Apafey pointed out, you need to write "Tab" (in quotes), not just Tab. "Tab" tells Excel to pass the text of the word Tab, while Tab tells Excel to look for a range named Tab, which probably doesn't exist.
You should try:
=AddRowTableFunction("Tab")
You wrote:
=AddRowTableFunction(Tab)
that is not fine.
As FaneDuru said, an UDF function can't change other cells, which explains the error). Thnaks !

How to call a sub routine of one form from other form?

i'm a new in vb.net, i would like to ask if how can I call a sub routine of the main form from another form.
I tried putting the prefix of the main form( main.subroutinename() ), it doesn't show an error when compiled but it doesn't work either.
As Microsoft says:
Calling syntax
You invoke a Sub procedure explicitly with a stand-alone calling statement. You cannot call it by using its name in an expression. You must provide values for all arguments that are not optional, and you must enclose the argument list in parentheses. If no arguments are supplied, you can optionally omit the parentheses. The use of the Call keyword is optional but not recommended.
The syntax for a call to a Sub procedure is as follows:
[Call] SubName[(argumentlist)]
You can call a Sub method from outside the class that defines it. First, you have to use the New keyword to create an instance of the class, or call a method that returns an instance of the class. For more information, see New Operator. Then, you can use the following syntax to call the Sub method on the instance object:
Or you can create a Sub Routine in a Module making it visible (Friend or Public, etc) then calling it inside entire the Namespace that contain your Module
object.MethodName[(argumentList)]
Illustration of declaration and call
The following Sub procedure tells the computer operator which task the application is about to perform, and also displays a time stamp. Instead of duplicating this code at the start of every task, the application just calls tellOperator from various locations. Each call passes a string in the task argument that identifies the task being started.
Sub tellOperator(ByVal task As String)
Dim stamp As Date
stamp = TimeOfDay()
MsgBox("Starting " & task & " at " & CStr(stamp))
End Sub
The following example shows a typical call to tellOperator.
tellOperator("file update")

What happens when i call a sub vba

I'm using the Call Function to activate other Macro's, but I'm not entirly sure how VB reads this function.
(I'm using this with MS Excel 2010)
For Example:
Sub main macro ()
blabla
blabla
Call Edit
Call Save
Call HistoryLog
End Sub
This code has some If funcions, and at some point will get to "Call Edit"
Here the Macro "Sub Edit()"will be activated. But I need this code to edit data, save the data into a new file and make a history log in an other Excel sheet.
If VBA is finished with the "Sub Edit()" part how will the code continu?
Does it Calls the "Sub Save()" part?
Or do I realy require to type "Call Sub Save" at the end of the "Sub Edit()" part?
VBA will process all lines of your code in the order they are given, unless an error occurs in one of them. As it is, your code will just stop at the point of error.
Where to call Save() really depends on how you want your code to work. If you want to make sure that after every call to Edit() changes are saved, I'd call Save() within Edit(). If sometimes you want to call Edit() without calling Save() you should not put the call to Save() into Edit().
When you call a procedure from within another procedure, program control returns to the line just below the Call line. In your example, when the Edit procedure reaches an End Sub or Exit Sub line, program control will continue on the Call Save line (the line just below Call Edit).
The Call keyword is included in the language for backward compatitbility. You can call the Edit procedure like
Edit
without the Call keyword. If you like using Call, it doesn't harm anything though.

How to instantiate a vba class and call a method from vb.net?

As I guess many are, I'm sitting with an ms access application with a mixture of tables, VBA Modules and VBA Classes. I intend to migrate that application to VB.NET.
However it will take some time and I would like to make use of automation to slowly move the code to VB.NET
Now I can call regular SUB and Functions from my VB.NET application but wonder if there is a way to invoke the methods of user defined objects.
Rough example what I want to do
VBA
'Class1
Public Sub Test()
Print "Hello world"
End Sub
'Module1
Public oClass1 as Class1
Public Sub Init()
Set oClass1 = New Class1
End Sub
VB.Net
' Left out the opening of the access db
oAccess.Run("Init")
oAccess.Run("oClass1.Test())
Is it even possible?
The Application.Run method requires a string containing "The name of the Function or Sub procedure to be run" as its first argument. But "oClass1.Test" is neither.
You could work around that issue by creating another VBA procedure which wraps your oClass1.Test method, and run the wrapper procedure ...
oAccess.Run("Wrap_oClass1_Test") ' no parentheses after procedure name
Public Sub Wrap_oClass1_Test()
oClass1.Test
End Sub
I confirmed that approach worked with the rest of your sample code when called from VBScript so I believe it should also work from VB.Net.
Tim's CallByName suggestion also looks promising, but I didn't test that one.