Excel VBA - GoalSeek cannot be called from User Defined Function - excel

Here is the User Defined Function where I'm calling GoalSeek.
I put this into module, however it does not solve for the given context.
Function FindYield() As Double
Worksheets("Sheet1").Range("N8").GoalSeek _
Goal:=0, _
ChangingCell:=Worksheets("Sheet1").Range("N9")
End Function
The same setup works as a Sub.

You need to use a Sub rather than a Function. Functions can only return a value to the cell in which they reside.

Related

In Excel VBA, is there a way to interrogate the function wizard's parsing of arguments?

Consider an arbitrary Excel function with m required arguments and n optional arguments. For a near trivial example, say it is this summation of two to four items.
Function myUDF_Sum(req1, req2, Optional opt1 = 0, Optional opt2 = 0)
myUDF_Sum = req1 + req2 + opt1 + opt2
End Function
My objective is to parse out these arguments for placement in a custom form.
Excel's Function Wizard already does this:
Where for example I would want something like this:
So the question is, is there a way to leverage the parsing work already performed by the Excel Function Wizard? This would seem to be preferable to the alternative, regular expressions or some parser, and would return a list of strings s_1, ..., s_(m+n) representing the values or expressions that are used as the arguments in the function.
But I do not see a way to get access to the argument list in VBA for the function wizard.
I would suggest you to use a different approach, respectively tore register your function and use the standard Excel way of displaying it.
Please, use the next code to register it UDF:
Sub RegUDFMyFunc()
Dim strDescr As String
strDescr = "It sumarize whatever you input..." & vbLf _
& "It adds(myUDF_Sum:<req1 As Long>, <req2 As Long>, <Optional opt1>, <Optional opt2>)"
Application.MacroOptions Macro:="myUDF_Sum", Description:=strDescr, category:=9
End Sub
After that, you go in an Excel cell and start writing the function name. It will be proposed by the functions wizard. You will select its name and please, press fx sign on the formula bar. Your function will appear exactly as you need...
In order to un-register it, please use the next code:
Sub UnregUDFx()
Application.MacroOptions Macro:="myUDF_Sum", Description:=Empty, category:=Empty
End Sub

How to call a bloomberg function inside a UDF

I want to call a bloomberg function inside a UDF, hence, I can't use
Cells(x,y).Formula = bdp(equity, field)
Which is what I normally see. I've tried Aplication.Run and WorkSheetFunction without success, are there other ways so that I can call this function?
A UDF isn't setting formulas, nor is it even setting a value - it is returning a value - so just return the value of the Bloomberg function as the result of your UDF.
For example:
Public Function MyUDF(....) As Variant
'...
'whatever calcs you are doing to determine "equity" and "field"
'(or maybe they are parameters)
'...
MyUDF = bdp(equity, field)
End Function

Why does Excel return #NAME? from a function call

I simply want the function to return the URL from hyperlinked text in a cell.
Found a solution:
Public Function GetAddress(HyperlinkCell As Range)
'GetAddress = Replace(HyperlinkCell.Hyperlinks(1).Address, "URL:", "")
Debug.Print ("Function was called on " + HyperlinkCell)
End Function
However, not even the Debug is being called.
The workbook is Macro Enabled and has all access under Trust.
Macros work fine, so what does it mean that functions are not working in my Spreadsheet?
Thanks
The problem is that you have not pasted the code in the module and hence excel is not able to recognize that name. You have to paste the code in a module. Same goes for other UDF.

Excel VBA - Use an existing string in called sub

I'm pretty new to this so apologies in advance
I'm half way through a userform in Excel and I'm trying to cut some fat off my code by using Call - I have 12 buttons that all do the same thing, the only difference is that each buttons sub is dependant on the buttons caption. My problem is that I can't figure out a way to use a String I've already declared in the Buttons Sub, then use it in the called Sub. I know you can do it, but my googling skills have failed me :(
Please could someone show me how to do this? Hope that all makes sense...
Here is a very small snippet of my code, but you get the jist:
Public Sub CommandButton4_Click()
Dim Name As String
Name = CommandButton4.Caption
Call Sort1
End Sub`
And the other one (Also tried this as function for the sake of trial and error)
Public Sub Sort1(Name As String)
Label11.Caption = Name
Sheets(Name).Select
End Sub
What you're referring to is passing an argument to another subroutine or function. Let's say you want to use a function a lot of times to get the first letter of a string. A sample of this is:
Function LeftOne(StrSample As String) As String
LeftOne = Left(StrSample, 1)
End Function
The above function can be used inside another function or subroutine provided you meet its requirement: StrSample. By declaring StrSample As String in the arguments field of the function, you are basically requiring that any calls to this should require a string to be passed to it. Anything else would throw an error.
The full line LeftOne(StrSample As String) As String can be read as: "I am function LeftOne. Pass me a string and I'll return to you a string after doing something with it." Note that the name StrSample is an arbitrary name.
Anyway, calling the above is as simple as:
Sub MsgInABox()
Dim StrToFeed As String
StrToFeed = "BK201"
MsgBox LeftOne(StrToFeed) 'Returns B.
End Sub
In your example, if you want to pass Name to Sort1, your attempt is absolutely correct.
Let us know if this helps.
You hat to give your sort1 procedure the parameter name.
call sort1(name)
or
call sort1(CommandButton4.Caption)

Stop VBA Evaluate from calling target function twice

I am having trouble getting VBA's Evaluate() function to only execute once; it seems to always run twice. For instance, consider the trivial example below. If we run the RunEval() subroutine, it will call the EvalTest() function twice. This can be seen by the two different random numbers that get printed in the immediate window. The behavior would be the same if we were calling another subroutine with Evaluate instead of a function. Can someone explain how I can get Evaluate to execute the target function once instead of twice? Thank you.
Sub RunEval()
Evaluate "EvalTest()"
End Sub
Public Function EvalTest()
Debug.Print Rnd()
End Function
This bug only seems to happen with UDFs, not with built-in functions.
You can bypass it by adding an expression:
Sub RunEval()
ActiveSheet.Evaluate "0+EvalTest()"
End Sub
But there are also a number of other limitations with Evaluate, documented here
http://www.decisionmodels.com/calcsecretsh.htm
I don't know of a way to stop it, but you can at least recognize when it is happening most of the time. That could be useful if your computation is time consuming or has side effects that you don't want to have happen twice and you want to short circuit it.
(EDIT: Charles Williams actually has an answer to your specific quesion. My answer could still be useful when you don't know what data type you might be getting back, or when you expect to get something like an array or a range.)
If you use the Application.Caller property within a routine called as a result of a call to Application.Evaluate, you'll see that one of the calls appears to come from the upper left cell of of the actual range the Evaluate call is made from, and one from cell $A$1 of the sheet that range is on. If you call Application.Evaluate from the immediate window, like you would call your example Sub, one call appears to come from the upper left cell of the currently selected range and one from cell $A$1 of the current worksheet. I'm pretty sure it's the first call that's the $A$1 in both cases. (I'd test that if it matters.)
However, only one value will ever be returned from Application.Evaluate. I'm pretty sure it's the one from the second eval. (I'd test that too.)
Obviously, this won't work with calls made from the actual cell $A$1.
(As for me, I would love to know why the double evaluation happens. I would also love to know why the evaluator is exposed at all. Anyone?)
EDIT: I asked on StackOverflow here: Why is Excel's 'Evaluate' method a general expression evaluator?
I hope this helps, although it doesn't directly answer your question.
I did a quick search and found that others have reported similar behavior and other odd bugs with Application.Evaluate (see KB823604 and this). This is probably not high on Microsoft's list to fix since it has been seen at least since Excel 2002. That knowledge base article gives a workaround that may work in your case too - put the expression to evaluate in a worksheet and then get the value from that, like this:
Sub RunEval()
Dim d As Double
Range("A1").Formula = "=EvalTest()"
d = Range("A1").Value
Range("A1").Clear
Debug.Print d
End Sub
Public Function EvalTest() As Double
Dim d As Double
d = Rnd()
Debug.Print d
EvalTest = d + 1
End Function
I modified your example to also return the random value from the function. This prints the value a second time but with the one added so the second print comes from the first subroutine. You could write a support routine to do this for any expression.
I face the same problem, after investigation i found the function called twice because i have drop down list and the value used in a user defined function.
working around by the code bellow, put the code in ThisWorkbook
Private Sub Workbook_Open()
'set the calculation to manual to stop calculation when dropdownlist updeated and again calculate for the UDF
Application.Calculation = xlCalculationManual
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, _
ByVal Source As Range)
'calculte only when the sheet changed
Calculate
End Sub
It looks like Application.Evaluate evaluates always twice, while ActiveSheet.Evaluate evaluates once if it is an expression.
When the object is not specified Evaluate is equivalent to Application.Evaluate.
Typing [expression] is equivalent to Application.Evaluate("expression").
So the solution is to add ActiveSheet and to make that an expression by adding zero:
ActiveSheet.Evaluate("EvalTest+0")
After seeing there is no proper way to work around this problem, I solved it by the following:
Dim RunEval as boolean
Sub RunEval()
RunEval = True
Evaluate "EvalTest()"
End Sub
Public Function EvalTest()
if RunEval = true then
Debug.Print Rnd()
RunEval = False
end if
End Function
problem solved everyone.

Resources