Creating a UDF that returns that returns a formula - vba

I'm new to VBA and have been reading all about user defined functions and macros. I'm hoping someone could help me out with a project.
I have a subscription to a service that pulls information into excel using an add-in in the ribbon. The only way to pull in the formula is to either 1) use the ribbon which involves a lot of clicking and waiting or 2)type in the formula into the cell with also takes times.
On excel, for normal functions (i.e. if, find, text), I often use the tab shortcut to fill out the formulas. I would like to to create a formula in excel (using VBA) so that I can write "=" -then hit tab - then reference a cell - and then the formula takes the referenced cell and returns a formula.
FYI - I am using Windows 7 and Office 2013
For example:
IF cell A1 the input number = 12345
In Cell B1 I enter the Comm formula that pulls in the data = "=ABC(A1,"Value_Name")
Cell B1 will display = ZYZYZYZY (which comes from the subscription database)
How do I write a VBA code that basically does:
Function (Value)
Returns =ABC(Value,"Value_Name")
: Which then calls the comm function and returns ZYZYZYZY
End Function
I tried my best to explain what I am trying to do - apologies if it was difficult to follow.
Thanks

You can call the other function using Application.Run:
Public Function MyUDF(Value As Variant) As Variant
MyUDF = Application.Run("ABC", Value, "Value_Name")
End Function

Related

VB.net copy and paste excel cell to elsewhere in the workbook

So i am currently using Visual Studio to create a application that takes info out of an excel sheet and then does some calculations on the data and then pushes back to excel.
This bit i have managed to do but the bit i am struggling on is using a 'Parameters' sheet. I want to be able to enter a formula into a cell in one sheet of the workbook and then paste that formula into another sheet but to have it updating,e.g. as the cells go down the formula changes like it would in excel. I used a manual work around by hard coding the formula and then having variable as the row number, however i want to be able to just change the formula in the excel sheet and then when the code runs it applies to the rest.
Currently i have tried saving the cell value/text into a variable and then making the new cells equal that variable, however this then applies the same identical formula to the whole of the column(All required rows).
What i am currently trying to do is paste the variable into the top row and then copy and paste that cell down to the last one,
I have tried making the variable a formula but it evaluates the formula before it is equal to the variable and therefore just sets all the new cells to the formula answer, so i changed the cell to be text instead which then meant the formula did appear in the new cell however it was the identical formula for all cells.
The copy code works as below
bjExcel.cells(rown, colval) = param1
objExcel.cells(rown, colval).copy
This is working fine
But when i use the below the paste won't work
Do Until rown = 10
objExcel.cells(rown, colval).copy
rown = rown + 1
objExcel.cells(rown, colval).paste
Paste is not a recognized with the error:
System.MissingMemberException: 'Public member 'Paste' on type
'ApplicationClass' not found.'
Could be you need to use PasteSpecial instead?
https://learn.microsoft.com/en-us/office/vba/api/excel.range.pastespecial
Depends on what you're using to interop with excel.
shWorkSheet.Range("C7:C7").Copy()
shWorkSheet.Range("V7:V7").PasteSpecial(Excel.XlPasteType.xlPasteAll)

Excel VBA: Naming a range within a user defined function

I am trying to create a user defined function to create a named range and assign a value to the cell. The below code is giving me a #Value error
My code:
Public Function NameARange(CValue As String, NameR As String) as String
Dim ReferAdd As String
ReferAdd = "='" & ActiveSheet.Name & "'!" & ActiveCell.Address
ActiveWorkbook.Names.Add Name:=NameR, RefersTo:=ReferAdd
NameARange = CValue
End Function
Any help to fix this code will be much appreciated. Thanks
Are you sure it's not a #NAME? error that you're getting?
Either way, there are a couple issues with your formula. The short explanation is it doesn't make logical sense.
Let's say you stick that formula in cell A1 of Sheet1...
You're trying to create a named range with a Worksheet Function. Worksheet functions recalculate (re-execute) every time something changes on the worksheet. Excel would try to recreate a new named range by the existing name, over and over and over.
Imagine if you had to sweep the floor anytime sometimes changed in your house... but sweeping the floor changes your house. You'd be stuck in an infinite loop.
You're also want the function to assign a formula to the cell that the function is sitting in. What if you could clone yourself, but the only place that clone could ever stand is exactly where you are standing. Wouldn't work out.
And, finally, you want to finish by returning a value to the same cell that has the function (and the infinite copies of itself)... but not just any value: the value that you called the function with in the first place.
It's like a Catch-22 of a Quagmire of a Paradox.
There is no solution for what you're trying to do except, "don't". Excel won't let you anyhow, which is good because otherwise the universe just might implode.
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:
Insert, delete, or format cells on the spreadsheet.
Change another cell's value.
Move, rename, delete, or add sheets to a workbook.
Change any of the environment options, such as calculation mode or screen views.
Add names to a workbook.
Set properties or execute most methods.
The purpose of user-defined functions is to allow the user to create a custom function that is not included in the functions that ship with Microsoft Excel. The functions included in Microsoft Excel also cannot change the environment. Functions can perform a calculation that returns either a value or text to the cell that they are entered in. Any environmental changes should be made through the use of a Visual Basic subroutine.
During calculation, Excel examines the precedents of the cell that contains a user-defined function. If not all precedents have been calculated so far during the calculation process, Excel eventually calls the user-defined function and passes a Null or Empty cell to the function. Excel then makes sure that enough calculation passes occur for all precedents to be calculated. During the final calculation pass, the user-defined function is passed the current values of the cells. This can cause the user-defined function to be called more frequently than expected, and with unexpected arguments. Therefore, the user-defined function may return unexpected values.
For correct calculation, all ranges that are used in the calculation should be passed to the function as arguments. If you do not pass the calculation ranges as arguments, instead of referring to the ranges within the VBA code of the function, Excel cannot account for them within the calculation engine. Therefore, Excel may not adequately calculate the workbook to make sure that all precedents are calculated before calculating the user-defined function.
(Source: Microsoft : Description of limitations of custom functions in Excel)

Referencing a sheet by index number

I've got a LibreOffice Calc spreadsheet that I use to keep track of my accounts receivable at work. Each sheet lists invoices and their status (paid, unpaid, etc) as well as info about each invoice. I'm trying to create a Summary sheet that lists certain data from each sheet. Creating the sheet manually is easy, but I'm trying to "automate" the process. I want the summary page to auto-update if I add a new sheet (or remove one) as I add and remove accounts to the file.
I know that LibreOffice assigns each sheet an index number that I could refer to in some sort of formula, but I cannot find a function that I can use to refer to that index number when getting a value from a cell within it. One would expect that a function like Sheet(2) would reference the second sheet, but, alas, that is not so!
I've tried using the indirect and address functions without success, but I'm not sure if I'm not understanding these functions or if they're not appropriate for what I'm trying to accomplish.
This has been a missing piece in Calc for a long time. The preferred solution is to write a user-defined function. Spreadsheet formulas do not access sheets by index number but Basic can.
The following function is from https://ask.libreoffice.org/en/question/16604/how-do-i-access-the-current-sheet-name-in-formula-to-use-in-indirect/.
Function SheetName(Optional nSheet)
If IsMissing(nSheet) Then
SheetName = ThisComponent.getCurrentController().getActiveSheet().getName()
Else
SheetName = ThisComponent.getSheets().getByIndex(nSheet-1).getName()
EndIf
End Function
Then get a relative address of the first sheet cell A1 like this.
=ADDRESS(1,1,4,,SHEETNAME(1))
A slightly different function is given at https://forum.openoffice.org/en/forum/viewtopic.php?f=9&t=49799.

VBA Worksheets.Calculate not working with Evaluate referring to expression on another sheet

I am intrigued by the VBA statement Worksheets.Calculate. It appears to me that it does not work correctly with custom function using Evaluate Statement when the function refers to cells on another sheet within the same workbook.
On Sheet1 I have Column A with just plain numbers.
Sheet2 in same workbook Column C has basic expressions on Column A Cells like A1+A2 etc.
I have this custom function in VBA Module
Function MyEval(Val1 As String)
Application.Volatile
MyEval = Evaluate(Val1)
End Function
And I put this formula =MyEval(Sheet2!C1) in say B1 in Sheet1 and drag it down.
This works fine for the first time. It takes in Expression in Sheet2:C1 passes it to MyVal, inside evaluates and returns the result.
The issue is the moment I edit the string expression in Sheet2, this entire formula returns 0. I need to Press F9 on Sheet1 to recalculate.
I have put Application.Volatile in MyVal and Worksheets("Sheet1").Calculate in Worksheet Change event in Sheet2.
Still it does not work. The only way to make it work is Press F9 on Sheet1.
Is this expected behavior? Am I missing something. How to I make a custom formula in VBA using Evaluate statement recalculate when there’s worksheet change event and the formula refers to range on another sheet?
No issue if the reference is in the same sheet. It works fine though. I have Excel 2013. Thanks.
Screenshot
The problem is that your code is calling Application.Evaluate which works in the context of the active sheet. If you want it to evaluate in the context of the sheet the function is on, you should use the worksheet.evaluate method like this:
Function MyEval(Val1 As String)
Application.Volatile
MyEval = Application.Caller.Worksheet.Evaluate(Val1)
End Function

Populating Excel multiple cells with data from Add-in user defined function (UDF)

I am working on an Add-in for Excel that needs to populate one or more cells in the worksheet with the data from server. I did following:
Created an Add-in (xlam) and created the user defined function:
GetMyData()
I am calling this function from a simple Excel Worksheet. In A1 cell, I entered the formula =GetMyData()
My server returns JSON Array. I am able to parse the JSON and now trying to populate the A1 and the below rows with values I got from the server. (in this case, I have 20 values, so I want to populate A1:A20 cells).
The issue is that according to Microsoft KB, a user defined function is able to change the value of the active cell only.
https://support.microsoft.com/en-us/help/170787/description-of-limitations-of-custom-functions-in-excel
I also tried to run the code below that changes only one cell to a hardcoded value:
ActiveWorkbook.Sheets("DataSheet").Cells(1, 1).Value = '12312'
Still - getting exception.
Could any one assist with this issue?
Have the function return a vertical array.
For Example:
Function GetMyData() As Variant()
Dim test() As Variant
test = Array(1, 2, 3, 4)
GetMyData = Application.Transpose(test)
End Function
Then highlight all the cells you would ever need with the top as the active cell.
Then put this formula in the formula bar:
=GetMyData()
And hit Ctrl-Shift-Enter instead of Enter to array enter the formula.
If you choose more than the array returns you will get errors.
Or you can, using the Array return, use this to deal with error and enter normally, but it runs the function for each time it is put in a cell.
Put this in the first cell:
=IFERROR(INDEX(GetMyData(),ROW(1:1)),"")
Then copy/drag down till you get blanks
Here is a simple example:
Public Function cerial(d As Date)
Dim bry(1 To 20, 1 To 1) As String
For i = 1 To 20
bry(i, 1) = CStr(d) & "_" & i
Next i
cerial = bry
End Function
It creates an array of 20 items.
There is a tiny trick to using it in the worksheet.
Select, say, E1 through E20. Then click in the formula bar and enter the array formula:
=cerial(TODAY())
Array formulas must be entered with Ctrl + Shift + Enter rather than just the Enter key. If this is done properly, the formula will appear enclosed in brackets in the Formula Bar.
NOTE:
In this example, the internal array bry() is two dimensional.