Using VBScript, I'm trying to run a subroutine that resides in one of the code modules. Now this particular sub calls several other subs/functions, including few that reside on the sheet modules. And on calling these subs residing in Sheet Modules, I get can error:
"Sub or Function undefined!"
How can I get around this? There are a lot of such functions and I don't want to move all of them from Sheet modules to code modules. Is there a better work around for this?
VBScript that calls a sub (residing in Code modules) that does not call any code on Sheet modules is working fine, so I'm sure it is the above bit that is causing problem.
If you are calling Sub Routines or functions from different modules then you need to make sure of two things
The Sub / Function should not be declared Private
You call the Sub / Function by prefixing the module name from which the code lives in
So if you have a Sub called TestSub and it lives in Sheet1's code module, then you should call it like Sheet1.TestSub. Calling it by using just TestSub will result in the error Sub or Function not defined.
As mentioned in the comments, the name of the sheet isn't always the same as the display name. You can find the name of the sheet from the object explorer in the VBE
In this example, the real sheet name is on the left, whereas the display name is on the right. You should refer to the sheet using the name on the left.
Related
I have a template file that connects to oracle and want to make a simple macro to refresh the oracle connection in every sheet, and I'll make a separate batch update file to open each of these files and call that macro. The X = HypMenuVRefreshAll() didn't work, so I tried X = HypMenuVRefresh(), and it only worked if I put it in the sheets themselves.
Can I have a module that loops through each of the sheets and calls that macro?
So I have something like this:
(The if statement is because the only sheets connected start with "CC ")
Sub Refresh_Workbook()
For Each Worksheet In ThisWorkbook.Worksheets
If Left(ws.Name, 3) = "CC " Then
Call EPBCS_Refresh_This_Sheet
End If
Next Worksheet
End Sub
And the Refresh sheet code looks like this(This works fine if I run it on it's own):
Public Sub EPBCS_Refresh_This_Sheet()
X = HypMenuVRefresh()
End Sub
But the module code is giving an error, because the sub i'm trying to call is undefined.
I think I could provide the sheet names specifically and call it that way, but the problem is that this is a template. So the sheet names need to be variable if that were the case so others can use this.
Any ideas?
I tried X = HypMenuVRefreshAll() and I got errors relating to other things in the file, so I tried X = HypMenuVRefresh() and that works only if I run it within the sheet object, not in the module object. I'm thinking when I try to run it in a module, it runs into other things, but in the sheet there's really no other code to interfere.
So I need to activate each sheet (variable name because this is a template), and run the code within that sheet's object.
I am trying to configure a button to run multiple macros, but I keep getting the sub or function not defined error seen below.
The Subs exist in sheets 2 through 5 and the macro is in Module 1. Here is what I have tried:
Adding "Public" in front of Sub across the sheets
Adding "Button2_click" to the "READ_ME" sheet
Adding "Call" in front of the Sub names
Double checking the sub names match
I don't usually use VBA, any suggestions for what I am doing incorrectly?
If your subs exist in other sheets, You have to call them with specifying the sheet name along with subname.
For ex -
Sub Button2_Click()
Sheet2.GenerateIdentityData
End Sub
Or you can move your subs to general modules as well to overcome this problem.
I have created a UDF Excel via ALT+F11 in own Module.
Have read many tutorials where everything seems so easy (that you can use your UDF in each Cell of opened Workbook). But I can't use my function.
Tried two test functions in Module (Test and Test2).
Checked everything (disabled all Macro security, allow access to VBA project model) but I don't see my custom function when I type "=" in a cell.
I'm using Excel in active Office 365 license so it is the newest version.
What could cause that my UDF is not applicable in the Excel cell?
I just get "#NAME?" / "#VALUE?" as result and no auto suggestion of function name...
maybe anyone has a hint for me what could cause that issue. Thx!
Public Function test()
test = 1
End Function
Public Static Function test2()
test2 = 123
End Function
#RonRosenfeld,
This is to demonstrate what behaviour I'm seeing:
Scenario 1: Function pasted in ThisWorkbook calling it in Sheet1:
Scenario 2: Function pasted in Sheet2 calling it in Sheet1:
Scenario 3: Function pasted in Module1 calling it in Sheet1:
This is why I came to the conclusing the () must be missing to show the #NAME error since otherwise there would be a syntax error.
#OP, You seem to have put your function in a class module, instead of a regular module.
Functions located in a module created using: add a Module(second menu from left)/Module
succesfully shows up in the function menu.
Is there a way I can write my Userform code in a module?
The reason I'm asking this is because I have a multi-page userform with an increasingly massive amount of code behind it. For organizational purposes, I'd like to be able to space out the code in different modules. But I don't know if this can be done for userforms (aside from calling a subroutine from the userform event).
Is there a way to write UserForm code in a module without having to call the subroutine from the userform code?
Actually it's simple. The code in your form module can call subroutines in other modules. So simply cut your code for a particular routine and paste it into another module, name it appropriately, and then in the form module place the name of the routine to call it. The only gotcha is that when the code is in a seperate module you can't use the Me keyword. If you use that in your code then pass the form as an argument and replace Me with your variable. A simplistic example: Assume you orinally have
Sub OK_Click()
If Me.txtName<>"" then
MsgBox "Ok",vbOkOnly,"It Worked"
End If
End Sub
Then you can create the following in a seperate module:
Sub DoOkClick( f as UserForm)
if f.txtname<>"" then
MsgBox "Ok",vbOkOnly,"It Worked"
End If
End Sub
and then replace the button click code with
Sub Ok_Click
DoOkClick Me
end sub
An approach is outlined here that involves defining a Class and adding controls to the form dynamically, which are then associated with Events of the Class.
From you description, though, it sounds like your UserForm is doing too much. I suggest that you consider creating other forms, rather than trying to do everything from a single form. You could, perhaps, create a Class to store properties (and behaviours) that are common to the two or three forms that you might create. Instantiate the Class when the first (main) form is opened.
I want to write a little logging function in an excel add-in that I will be calling from many different workbooks. I'd like to be able to just call it by passing only the log text, and the log function itself could handle the timestamp, workbookname, etc.
However, I cannot use either ThisWorkbook or ActiveWorkbook to determine which workbook was responsible for making the call, as Thisworkbook will return a reference to the add-in itself, whereas VBA code running in a workbook other than the workbook with active focus in Excel could make the call, but the ActiveWorkbook will return the one that has focus in the window.
Application.Caller looked like a possible solution, but this seems to work only when the function is called from a cell, not from VBA.
Is what I'm trying to do impossible?
Update
According to > 1 person, this is in fact impossible. If anyone happens to know some clever workaround please speak up.
Ok, so having read the question properly I'll try again...
So, to state the problem:
you want a routine written in an addin, that when called from vba in another workbook can work out (among other things) which workbook contains the vba that made the call, without having to pass this information explicitly.
As stated this is not possible (this is a similar question to accessing the call stack from code: something that is to my knowledge not possible)
However you can almost get what you want like this
Declare your log function like this:
Sub MyLogger(wb as Workbook, LogText as String)
Dim CallerName as String
CallerName = wb.name
' your code...
End Sub
Then wherever you call the sub use
MyLogger ThisWorkbook, "Log Text"
Not quite as good as passing nothing, but at least its always the same
To get the name of the calling workbook, use
Application.Caller.Worksheet.Parent.Name
Application.Caller returns information about how Visual Basic was called. If called from a custom function entered in a single cell, a Range object specifying that cell is returned
Having got a reference to the cell, .Worksheet.Parent.Name gives you the name of the workbook
Note that Application.Caller will return other things depending on how your function is called (see VBA help for details)
In an Add-In Function called by an Excel Worksheet Array Entered Function Call, I find that "Application.Caller.Parent.name" gives the Sheet Name (Tab Name, not sheet number).
I had the same issue when coding a custom function. Function works well, but anytime another workbook is calculated or activated, all cells using that function revert to #value. It can be very frustrating when working with multiple files using this formula.
To get the Workbook I used:
Dim CallingWb As Workbook
Set CallingWb = Application.Caller.Parent.Parent
This should work if your function is in a cell.
Too late for the original post, but might help others!