I am having a problem with incorporating User Defined Functions in excel. For some reason the function is not recognised. The (simplified) code is as follows:
Option Explicit
Option Base 1
Function Dummy(A As Range, _
B As Range, _
C As Double, _
D As Double) As Double
' This function doesn't do anything
End Function
When I use the function in a cell it returns the #NAME? error.
Strangely enough when I started typing "=du" in the cell excel did find the function.
When I use the error checking function of excel this clearly shows that the function is not recognised.
I know this error can occur in case the VBA module is stored in a user form, a sheet or "ThisWorkbook". However that is not the case here.
Can anyone tell me what I am doing wrong here?
Rename your module or your function. The module name and the function name cannot both be "Dummy".
Related
I have a follow-up question to this question.
So I want to replace INDIRECT function calls with a VBA method because INDIRECT is volatile and my excel doc is taking several seconds to load and sometimes is not responding.
But when I use the INDIRECTVBA method and nest it with an OFFSET function I get an error and it shows "#VALUE!"
(yes I know OFFSET is another volatile function, I will replace with INDEX..)
Specifically:
Cell BJ10 contains the text "$R$71" which is a reference to my cell holding the data.
=INDIRECT($BJ$10) works but is volatile.
=INDIRECTVBA($BJ$10) works.
=(OFFSET(INDIRECT($BJ$10),0,0)) works but is doubly volatile.
=(OFFSET(INDIRECTVBA($BJ$10),0,0)) does not calculate, it shows "#VALUE!"
Any thoughts?
Here is the INDIRECTVBA method:
Public Function INDIRECTVBA(ref_text As String)
INDIRECTVBA = Range(ref_text)
End Function
Public Sub FullCalc()
Application.CalculateFull
End Sub
Your function doesn't return a range, so it fails as the first argument to OFFSET() (which requires a range in that position).
Also, your function will fail when any other sheet is active (assuming it's in a standard module), because the scope of Range() defaults to the ActiveSheet.
Try something like:
Public Function INDIRECTVBA(ref_text As String)
Set INDIRECTVBA = Application.ThisCell.Parent.Range(ref_text)
End Function
If everything's not on the same sheet then you will need some way to specify which sheet should be used in your UDF
I'm learning VBA from a book, and the sample function in it is:
Function CubeRoot(number)
CubeRoot = number ^ (1 / 3)
End Function
If I call that function from a sub procedure, I get the correct result, but when I try to use it directly in Excel, I get a "FALSE" result in the cell. I followed the book step-by-step and it does not say to do anything that I haven't done. What am I missing/doing wrong or maybe I need to change some option? I am using Excel 2016.
Edit:
This is what I write in an excel cell: =CubeRoot(8) The result I get is FALSE. However, if I click the fX button and the function arguments box pops up, the formula result shown there is calculated correctly.
I write in an excel cell: =CubeRoot(8) The result I get is FALSE
At first try declaring the variable types properly:
Function CubeRoot(number As Variant) As Double
CubeRoot = number ^ (1 / 3)
End Function
But I do not believe that this will help because the error result then would be #VALUE! but not a boolean FALSE.
But the ^ operator can be overloaded. Maybe by some AddIn you are using. So it seems that it was overloaded to be some boolean operator.
Try the following:
Function CubeRoot(number As Variant) As Double
CubeRoot = Application.Power(number, (1 / 3))
End Function
If that helps, then my suspicion is true and you should go through your installed AddIns to determine which one is doing the weird overload.
If even the using Application.Power(number, (1 / 3)) does not help, then the cell containing the formula seems to be formatted using a weird number format. Try formatting it using the General number format.
According to your mention: "if I click the fX button and the function arguments box pops up, the formula result shown there is calculated correctly.", I suspect it is the weird number format rather than the first two suspicions. So do selecting the cell containing the formula =CubeRoot(8) and set number format General to it using Home tab and Number group.
Finally the problem was that the worksheet functions had been inputted into Excel4 macro sheets instead of worksheets. Probably the Excel4 macro sheets were added using Sheets.Add Method using the type xlExcel4MacroSheet. But in Excel4 macro sheets only Excel4 macro code is possible not default formulas as in worksheets. Excel4 macro is ancient type of macro language from Excel 4.0 (1992). Since Excel 5.0 (1993) VBA is used for Excel macros.
Declare all variables as double, and also the function return type as double.
By default 8 is treated as integer, so 8*X will result integer even if x is single or double.
I'm starting with VBA and I'm very upset to discover I have fallen at the first hurdle in this book I am following.
I should type the following
Function Hello() As String
Hello = "Greetings"
End Function
This all works fine but next I am supposed to change the text and see the function change on the Excel spreadsheet. Unfortunately I can't get this to work. Does anyone know why?
I've saved the document as an Excel Macro-enabled workbook and tried opening and closing.
You seem to have this function in the code-file for thisWorkbook, but it should be in a module. Add a module to your project, place your code there and make the function Public. See also: How to Call VBA Function from Excel Cells?
Normally a Function should be in a Module, not in ThisWorkbook. You store Event handlers in the ThisWorkbook or a Sheet module.
It doesn't recalculate because it doesn't have a Range input, since the function doesn’t have any arguments, it is treated constant output and hence updating the function doesn’t update the cell value.
But if you modify it to accept a Range input, and if there are any changes to the input range, it will recalculate.
declare your function right
Function Hello(str As String) As String
then use something like
cells(1,1).value=str
function does the job for you but first you must call the function by parameter like this
cells(1,1).value=Hello("How are you")
the result will be that in cell 1,1 will "How are you" be written.
but from this on I am not sure what are you trying to accomplish. If you need funct. to write in specific cell all the time you should use something like
Funtion Hello(row as integer, column as integer) as string
cells(row,column).value=inputbox("give me the input")
end function
then to use this you write into code
result=Hello(1,2)
this example works
Function Area(row As Integer, column As Integer) As String
Cells(row, column).Value = InputBox("give something here")
End Function
Sub my()
result = Area(2, 2)
End Sub
run my()
Ok I worked it out, I had written the function into the file "This Workbook" instead of into the Module I created...
I knew it would be something simple! All working now.
Function Hello() As String
Application.Volatile
Hello = "Greetings"
End Function
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
I have a faint memory of being able to use VBA functions to calculate values in Excel, like this (as the cell formula):
=MyCustomFunction(A3)
Can this be done?
EDIT:
This is my VBA function signature:
Public Function MyCustomFunction(str As String) As String
The function sits in the ThisWorkbook module. If I try to use it in the worksheet as shown above, I get the #NAME? error.
Solution (Thanks, codeape): The function is not accessible when it is defined ThisWorkbook module. It must be in a "proper" module, one that has been added manually to the workbook.
Yes it can. You simply define a VBA function in a module. See http://www.vertex42.com/ExcelArticles/user-defined-functions.html for a nice introduction with examples.
Here's a simple example:
Create a new workbook
Switch to VBA view (Alt-F11)
Insert a module: Insert | Module
Module contents:
Option Explicit
Function MyCustomFunction(input)
MyCustomFunction = 42 + input
End Function
Switch back to worksheet (Alt-F11), and enter some values:
A1: 2
A2: =MyCustomFunction(A1)
The word input needs to be replaced as it is a basic keyword. Try num instead. You can also go further by specifying a type, eg variant.
Function MyCustomFunction(num As Variant)
MyCustomFunction = 42 + num
End Function