Create a custom worksheet function in Excel VBA - vba

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

Related

UDF is not recognised in excel 2010

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".

Replacing Indirect with non-volatile VBA method, but cannot nest the returned value with Excel functions like OFFSET?

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

Worksheets.Add in UDF Not Working

I have a UDF that can be called from within a cell in my excel workbook. I need it to add a worksheet at the end of the workbook. I have used sheets.add multiple times in my VBA script, but never in a function called from inside a cell and this is apparently causing some issue.
The function accepts an optional parameter for file path of the workbook in which to add the sheet, and if the user leaves this blank I want to default to the active workbook.
Below is the relevant code... What am I doing wrong?
Public Function onesheet(Optional filepath As String)
Dim wb As Workbook
Dim ws As Worksheet
If filepath = "" Then
Set wb = ActiveWorkbook
Set target_ws = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
End If
The function is being called from the cell with
=onesheet()
A function (UDF) has one role: compute a value and return that value to the cell (or formula/expression) that called it.
This is a function:
Public Function Foo(ByVal bar As String) As String
Foo = "Hello, " & bar
End Function
You can use it in a worksheet cell like this:
=Foo("dsdavidson")
And every time Excel recalculates that cell's value, it calls the UDF, making the cell's value read Hello, dsdavidson.
Functions don't have side-effects. Functions don't modify other cells. Functions take input, process it, and output a result.
What you're doing wrong, is using a UDF as if it were a macro.
Change your Function for a Sub, and don't call it from within a cell. Make a button to call it instead. Or whatever rocks your boat. But you can't have a cell formula that adds a worksheet to the workbook every time it recalculates.
Macros need to be Public and parameterless. So you'll want to take your optional parameter value from a specific cell, or display a form that lets the user pick from a list of available opened workbooks - and then call your procedure and pass the user's selection as a parameter.
Quite possibly the macro code could end up looking something like this (YMMV):
Public Sub AddWorksheet()
With New PromptForm
.Show
If .Cancelled Then Exit Sub
OneSheet .SelectedBook
End With
End Sub
You cannot add sheets through user defined function.
Here are the limitations of User Defined Functions.
A user-defined function called by a formula in a worksheet cell cannot change the environment of Microsoft Excel. This means that such a function cannot do any of the following:
1) Insert, delete, or format cells on the spreadsheet.
2) Change another cell's value.
3) Move, rename, delete, or add sheets to a workbook.
4) Change any of the environment options, such as calculation mode or screen views.
5) Add names to a workbook.
6) Set properties or execute most methods.
For more details visit this site...
https://support.microsoft.com/en-in/help/170787/description-of-limitations-of-custom-functions-in-excel

VBA String Function does not update when I change the text

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

Excel VBA, Get the value of a private worksheet constant

I want to retrieve the value of a worksheet-code-level private constant via VBA. I'm trying to do something similar to having "tags" on my worksheets that are accessible via VBA. I'd like to use the CodeModule in the VBAProject so that I can have a number of "tags", not just one. I just can't figure out how to grab the constant, even after reviewing much code and forums on-line. Does anyone have any insight on this? I am running Excel 2013 on a Windows 8.1 machine.
Maybe the easiest way to do this is to have a function that can the value of a private constant with a public accessor method. For instance, if you have the following code in your worksheet Sheet1:
Private Const myValue = "the answer is 42"
Public Function getSecret()
getSecret = myValue
End Function
Then you can access it from another module with
Sub test()
Dim sheetName = "Sheet1"
MsgBox "The sheet says that " & Sheets(sheetName).getSecret()
End Sub
You can make this fancier - you could create a collection of tags and index them… but I think that goes beyond the question you had. Note that you have to "fully qualify" the name of the accessor macro when it is in a worksheet; the advantage is that you can use the same function to examine the tag of different worksheets just by changing the sheetName.
I would export the code to a .BAS file. You can then read the material back in as a text file and retrieve the constant