I have a set of user defined vba functions that sit in an excel module, which are then called from an excel spreadsheet... everything has worked fine at this point.
I've been asked to move the vba from the module to the worksheet's code page. When I did this, I've found I can't call any of the functions from cells on the worksheet... the names simply don't show as existing. Is there a way to call worksheet functions from an excel cell? Also, is there any problem calling a worksheet function from a user defined function in another module or worksheet code behind?
EDIT:
I've found if I call by the sheetname.functionname, it throws an error message that includes "The name conflicts with an Excel built-in name or the name of another object in the workbook"... where if I use sheetname.anythingelse it just resolves to #NAME?
Does this mean excel worksheet functions cannot be called from a sheet?
No. Functions in the worksheet object can't be called from the sheet as user-defined functions.
The Worksheet object is intended for responding to events that happen on a worksheet. You can't put user-defined functions there. User defined functions have to live in a Module.
If your user-defined function does live in a module, you won't have any problem calling it from code anywhere else... including in the worksheet "code-behind".
You have to put the code in a standard module.
Check this link.
http://www.cpearson.com/excel/writingfunctionsinvba.aspx
Related
I have an Excel VBA addin that adds user defined functions (UDFs). These functions all work fine in terms of calculating their results.
I enter them into the Function Wizard using MacroOptions.
When using them in a worksheet, they autocorrect the function names for case. For example, if the function is named MyFunction, and the user enters it as myfunction, then when the formula is entered it autocorrects the function name's case to MyFunction. Just like with Excel's built-in worksheet functions, where if you enter e.g. median it will autocorrect it to MEDIAN.
However, there is one UDF for which that autocorrect is incorrect. I want it to be e.g. MyFunction, but even if the user enters it like that, it autocorrects to all lowercase, myfunction.
I have looked at every relevent line of code and can find no reason for that. The code is the same for all the other UDFs except of course for function name, function description, and the code and parameters in the function itself.
Any idea why that one UDF autocorrects the function name differently?
Here's an example of the MacroOptions line:
Application.MacroOptions "MyAddin.xla!MyFunction", "Description of MyFunction for the Excel's Function Wizard.", , , , , "Custom category in Function Wizard"
And the UDF itself looks like this:
Public Function MyFunction(param1 As Long, param2 As Long) As Long
'MyFunction's code here...
End Function
Again, the UDF calculates correctly. The issue is with the autocorrect on the function name.
I tried closing the addin, then creating a new UDF with the same function name as the affected function in the new, default Excel workbook. It worked correctly -- it autocorrected to the correct case. But when I closed it and went back to the addin, the problem returned.
UPDATE:
Here are the steps that worked for me to fix the problem (thanks, Charles Williams!):
Set the add-in workbook's IsAddin property to false. That turns it into a workbook, so you'll get a worksheet.
File > Save As, save as new xlsm workbook. Important: make sure there are no formulas in the worksheet with the affected function name; otherwise you'll be coming back to this step.
File > Options > Add-ins > Go, Uncheck the add-in so it doesn't load when Excel is started.
Exit and restart Excel.
Open the new xlsm workbook.
Enter a formula with the function name in correct case. It should NOT autocorrect to incorrect case.
Delete the formula.
Save the xlsm workbook.
Make a backup of the original add-in, as you're about to overwrite it.
Save the xlsm as a new xla add-in, overwriting the old one (I assume this works with xlam too but didn't try that).
File > Options > Add-ins > Go, recheck the add-in so it loads when Excel is started.
Restart Excel. Test for the problem; the problem should be fixed.
Excel insists on remembering the capitalization that was used the very first time the UDF is entered into a formula.
I have not found a sensible way of resetting this, apart from renaming the UDF.
If the XLAM's worksheets contain a formula referring to the UDF then that reference will lock in the capitalization. If the XLAM's worksheets do NOT contain a formula referring to the UDF then it will be set from the first workbook that uses it in an Excel session. If you have 2 saved workbooks with different capitalizations and they both get opened then the capitalization in the second gets overwritten with the capitalization from the first.
Inspired by other contributions (thanks!), here are the steps that worked for me:
Close the Excel session and open a new one.
Create a new workbook and write in it a formula including the correctly-capitalized UDF.
Discard the new workbook but keep the Excel session.
Open other workbooks with formulas including the UDF: the UDF will now be correctly capitalized.
You can close the Excel session without saving the workbooks.
In subsequent Excel sessions, the UDF will be correctly capitalized.
Why is that when I have the following VBA code:
public sub Run
End Sub
Sometimes it appears as Run in the macro list on the view tab but sometimes it appears as sheet1!Run?
You've put the macro into one of the worksheet code sheets. This probably occurred by opening the VBE with a right-click to the worksheet name tab and choosing View Code.
The macro can reside there but it will remain Private to that worksheet unless specifically declared otherwise. Generally, a module sheet is the preferred location.
It's also a bad idea to name your macros with reserved words. Run is a function as in Application.Run and your macro can only cause confusion if it carries the same name.
CONTEXT: I have created an Excel Add-In in which there is a worksheet named "Mother". When the user clicks a button from any workbook in which the Add-In is installed, I would like the worksheet "Mother" to be copied inside its same workbook and being renamed. In code:
ThisWorkbook.Sheets("Mother").Copy After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
WHAT I EXPECT: being the line of code above placed into the .xlam code, I know that ThisWorkbook refers to the Add-In and this is observable through a watcher as well:
So, I expect that a copy of "Mother" will be added to the workbook, at the end.
WHAT HAPPENS: the method simply fails, returning the error Copy Method of Worksheet class failed.
WHAT I HAVE TRIED: By simply looking for the name of the error online I have figured out that, apparently, I cannot copy a hidden worksheet and that's why the method fails. So I have tried:
1) To change the visibility with ThisWorkbook.Sheets("Mother").Visible = True... No success;
2) To activate the workbook before/after to change the visibility, so ThisWorkbook.Activate... No success.
I'm not being able to find much documentation online about this, so I'm almost wondering if it's actually possible to edit/show the workbook.xlam, something that I would really need to do for my project.
A BIT MORE OF CONTEXT: The reason why I need to both add the worksheet and show it to the user is that the Add-In, which basically consists in a custom function =myFunction(), needs to be fed by user-inputs for make its calculus.
In particular, neither I can write the data in the sheet before to distribute the Add-In (because I don't know the user inputs in advance), nor I can prepare a user-form where to insert the data and show it at running-time (because the user-inputs are usually a big amount of data that can be copied-pasted easily into an Excel spreadsheet, but not inserted manually into a form nor in the function parameters themselves). So:
MY QUESTION: Is it possible to copy (duplicate) a worksheet within a .xlma workbook and activate it after to allow the user data insertion? If yes, where am I being wrong on the above?
Looks like this link would help: http://forums.techguy.org/business-applications/1120165-add-extra-sheet-xlam-file.html.
The operation cannot be performed on add-in workbook, hence you just need to set it as "not add in":
ThisWorkbook.IsAddIn = False
'your copy operation
This Workbook.IsAddIn = True
I have three modules (standard module, not class module) in my Excel VBA project. One of those was added by right-clicking the VBAProject and insert a module. Two of them were added by executing "modules.add"; I guess modules means module sheets, right? So, my questions are:
1. What does a module mean in VBA?
2. How can I know which module is created while adding a modulesheet?
3. Why when I add a worksheet,there isn't a module appear?
A module is simply a place to put your code. You can just see it as a sheet of paper where you can write something.
In Excel you can put your code in a module, or "behind" a worksheet (what you call a modulesheet). A module is always added manually BY YOU. The "modulesheet" is part of a sheet and thus added or deleted BY EXCEL automatically whenever you create or remove a sheet
When you put some code and variables in a module, its instantly available from all worksheets within your workbook, dependinv on how you declare your variables, subs and functions (private/public)
Usually when one put code behind a worksheet, its because this code is only meant to be called from that particular worksheet and only perform operations on it. I personnaly never work on worksheet level for several reasons:
if you delete your sheet, you lose all code that was behind it.
if you export a sheet, you export the code as well.
if you duplicate a sheet, you duplicate the code as well.
if you want to run the code behind a particular worksheet from another place, you have to fully qualify your calls and variables, which is a horrid solution and also plain boring
My advice is: IN EXCEL, never work on sheet level, uses modules, and if you reach a decent amount of code, organise it in logical groups using multiple modules
RE 1: A module is like a singleton class which has already been initialized, so to speak. In other words a module's code (public properties/variables, public methods, etc) is always available, one does not have to inherit an instance before tries to use it, however, all the data in a module's properties/variables are common "application-wide"
RE 2: It is "sheet module", not "module sheet". This means nothing but the newly added sheet has a module with it when you add it. There's no difference between having this, or adding a module to the sheet later. You can open the code editor window and see modules, classes, etc by pressing ALT+F11
RE 3: By default no VBA code is added to any new sheet because of security reasons. If a Workbook has macro (VBA code) in it, extra attention is required so by default a workbook is not a VBA(macro) workbook.Last but not least, please note that there's no difference between one module or another. The way you create a module does not affect the way modules behave, and there's only one "type of module" (as well as one "type of class module") in Office applications (Excel, Word, etc)
for number 2:
Sub moduleAdd()
Modules.Add
'Modules.Add
qq = Modules.Count
MsgBox "total added module by code = " & qq
For ii = 1 To qq
Set modu = Modules(ii)
If ii = qq Then MsgBox "Newly added module = " & modu.Name
Next
End Sub
Eventually, I want to move the cell to the location where the last error occured. Edit: Forgot to say that I'm using Excel 2003.
As requested in comments...
Look up the 'Caller' property of the 'Application' object in the Excel VBA help. When you use it from a VBA routine, it will tell you where the call to the routine came from - what Range, Chart, etc.
An important thing to be aware of when using 'Application.Caller' is that it isn't always a Range object. Look at the help, but the property returns a Variant value that can be a Range, String, or Error. (It is a Range object in the case you're interested in, but you'll need to be aware of this.)
Because of the above, and the vagaries of VBA syntax when it comes to objects vs. values, it can be tricky to use 'Application.Caller'. Putting a line like:
Debug.Print Application.Caller.Address
in your code will fail when the caller isn't a Range. Doing something like:
Dim v
v = Application.Caller
will "compile", but will create circular references when the caller is a Range because you're trying to access the value of the calling Range.
This all means that it's probably best to write a little utility function for yourself:
Public Function currentCaller() As String
If TypeOf Application.Caller Is Range Then
Dim rng As Range
Set rng = Application.Caller
currentCaller = rng.Address(External:=True)
Else
currentCaller = CStr(Application.Caller)
End If
End Function
and then call it from your error handlers where you want to know where the call came from.
One more thing - obviously this can only tell you the caller once a VBA routine has actually been called. If you have errors in your calling formulas, Excel will return error values to your cells without ever calling your VBA routines.
Wrap your VBA function in another function that stores the cell location and value as variants. Keep this 'wrapper' function as basic as possible so it won't cause any additional errors.
If you're trying to debug app-crashing errors, the wrapper function could even store those values in a comma-delimited text file. Once stored, Excel can crash all it wants and you'll still know what the cell location and value were since you stored them outside of Excel beforehand.
Could this be done with an error handler?
An example of what I mean below:
sub code1()
on error goto cell A1
end sub