Moving or saving as .xlsm file breaks macros - excel

I have a .xlsm file which use a variable that gives the name of other spreadsheet using their index (it uses GET.WORKBOOK(1)). In order for this to work, I have to save the file as a .xslm file.
This file is saved on a onedrive and working but when saving a copy elsewhere, the macros are completely broken and I get #NAMES errors in my cells using it.
I tested it with a smaller file and I get exactly the same behavior.
This is the macro saved in the name manager.
=REPLACE(GET.WORKBOOK(1),1,FIND("]",GET.WORKBOOK(1)),"")
I tested it in a small example: one excel .xslm file with one sheet, in one cell calling the variable should give me 'Sheet1'. Once I move this file and try to call this macro again I get #NAMES

You can write a short user defined function (in a module)
Option Explicit
Public Function GetWorkbookNameByIndex(Index As Long) As Variant
Application.Volatile
If Index <= ThisWorkbook.Sheets.Count Then
GetWorkbookNameByIndex = ThisWorkbook.Sheets(Index).Name
Else
GetWorkbookNameByIndex = CVErr(xlErrNA)
End If
End Function
So you can use it as a formula eg:
=GetWorkbookNameByIndex(A1)
And it will return the following:
Image 1: Result of the function: If index is out of range it returns #N/A (=#NV in the image above because of German screensot).
Note that the function has to be volatile, otherwise the formula won't update if a sheet name gets changed. Volatile functions are re-calculate on every calculation in the sheet and therefore come with a more heavy load on calculation. Volatile functions should not be used extensively or calculation will slow down significantly.
The fact that it is volatile will trigger an update if a sheet name gets changed or a sheed gets deleted or moved but actually not if a new sheet is added. Therefore you would need to either manuall re-calculate by pressing F9 or use the NewSheet event:
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Application.Calculate
End Sub
Same for the NewChart event if this is relevant for you.

Related

function not recognizing macro input for sheet name

I'm looking to reformat a program's export. So far I've created a function that calls for a single string input, which is simply a number identifier (2210-01, for example).
This input is causing issues once I go to navigate to the sheet by that name.
I've tried assigning the input datatype as something other than a string, but that's causing other issues. I know that my WB has those sheet names that are in the RunFormatRawExport(), I'm not sure why it's causing issues when I pull open the sheet though.
Sub RunFormatRawExport()
FormatRawExport ("2210-01")
End Sub
Public Function FormatRawExport(ComCode As String)
Sheets("ComCode").Activate
End Function
with this short snippet, the macro should just re navigate to sheet 2210-01. I'm not getting errors when I call for ComCode before this error.
It could be that you should first set focus to the workbook the sheet "CombCode" is in, i.e. Workbooks([name]).Activate

Trying to use Application Volatile to get a cell to display name of workbook each time it is changed, but not working

I am trying to use application.volatile to enable a cell to display the name of the workbook each time the workbook is opened.
Function getbookname() As String
Application.Volatile
getbookname = ActiveWorkbook.Name
End Function
I input =getbookname() into cell B7, but the results are mixed. If I close the workbook, change the name of the workbook and open again, sometimes it works, sometimes it doesn't. Can anyone help on this?
There are many sites which explain why to avoid using Volatile unless really necessary.
In your code, you are using ActiveWorkbook, but your description of what you want implies that ThisWorkbook would be more appropriate.
You do not need VBA. From https://support.office.com/en-us/article/Insert-the-current-Excel-file-name-path-or-worksheet-in-a-cell-186833c6-c899-4912-a14c-240c2eb51e0b:
Insert the current file name, its full path, and the name of the
active worksheet: =CELL("filename")
Insert the current file name only:
=MID(CELL("filename"),SEARCH("[",CELL("filename"))+1,
SEARCH("]",CELL("filename"))-SEARCH("[",CELL("filename"))-1)
If you really want to use VBA, then you can set a reference cell somewhere with the Workbook_Open event. This is even easier if you use a 'Named Range'. For argument, let us call this workbook-scoped named range "bookname". Then, in the cells where you need it, you can just type =bookname
Private Sub WorkBook_Open()
ThisWorkbook.Sheets("MyReferenceSheet").Range("bookname").Value = ThisWorkbook.Name
End Sub
For each of these options, "Volatile" and all the issues that this can cause is not necessary.

Custon fucntion applies to entire workbook instead single sheet

I use popular custom function which I found on the internet on one of vba blogs. It reads text cell as if it be formula (i.e. "=A2+B2" or "=ABS(A2+B2)", I created them by using CONCATENATE function, in workbook they are without quotation marks). The code goes:
Function Eval(Ref As String)
Application.Volatile
Eval = Evaluate(Ref)
End Function
In my workbook I have multiple sheets which are exact same copies except 2 columns of data, which calculate some descriptive statistics (i.e. sum, average, standard deviation etc.), the formulas are in my source sheet, copied sheet have formula like: Eval(sourceSheet!A1) and A1 contains text of formula like above. The problem is that to apply macro after loading it, I need to pres F9 to refresh (sometimes several times). It makes refreshing ALL my copied worksheets with the data I have in worksheet I am refreshing. So for example: if i refresh in worksheet 3 and sum of data was 5 it changes sum to 5 in all other sheets. I guess somehow my code makes the function applied to entire workbook instead of single worksheets like every other excel function.
So I have 2 questions:
Is there any way to change the code so my custom function will only apply to worksheet I put it in?
Can you post me a macro code for refreshing entire workbook with every single click of left mouse button?
Thank you in advance
Thats a rather buggy UDF: Evaluate always takes unqualified references as referring to the active sheet.
You really need to use Worksheet.Evaluate. Try something like this that assumes that any unqualified references in Ref are to the sheet that Ref is on
Function Eval(Ref As range)
Application.Volatile
Eval = ref.parent.Evaluate(Ref.value)
End Function
Or if you want it to refer to the sheet that the UDF is being called from try this
Function Eval(Ref As variant)
Application.Volatile
Eval = Application.Caller.Parent.Evaluate(Ref)
End Function
There are also a number of strange things/Quirks/bugs with evaluate you should be aware of: see my blog post
https://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/

Having Excel Fields Auto Update when New Data Added

I have an Excel doc that starts with some fields that come from calculations done on the rows below it. To do the calculations I currently have a module with about 4 functions that loop through rows 20 through N(first blank cell). These functions are called straight from the cells at the top of the sheet. The problem is that the calculations at the top are not updating whenever someone adds/removes data from the rows below. How can this be accomplished?
If your functions are Excel VBA user-defined functions called from worksheet cells, then you will get this not-recalculating behaviour if the UDF refers to cells that are not in the input parameters of the UDF.
If this is the case a good solution would be to define some Dynamic Named Ranges that expand/contract as data is added/deleted and use them as input to the function.
Another solution would be to add Application.Volatile to your UDF, but this has the undesirable side-effect that your UDFs will be recalculated at every calculation which can be painfully slow.
If I understand your question correctly, you can use Worksheet_Change event to accomplish such tasks.
In your sheet module, add a Worksheet_Change event:
Private Sub Worksheet_Change(ByVal rngChanged As Range)
' Call your subs and functions here
MsgBox "You just changed something!"
End Sub
Note that the Worksheet_Change sub must have one and only one argument of type Range. Excel will make it a reference to the range that was changed by the sheet user. If you want to observe its behaviour, try placing this line in the sub:
rngChanged.Interior.ColorIndex = 4
Read more e.g. here.

Possible to tell which workbook called a function in an Excel Add-In (xla)

I want to write a little logging function in an excel add-in that I will be calling from many different workbooks. I'd like to be able to just call it by passing only the log text, and the log function itself could handle the timestamp, workbookname, etc.
However, I cannot use either ThisWorkbook or ActiveWorkbook to determine which workbook was responsible for making the call, as Thisworkbook will return a reference to the add-in itself, whereas VBA code running in a workbook other than the workbook with active focus in Excel could make the call, but the ActiveWorkbook will return the one that has focus in the window.
Application.Caller looked like a possible solution, but this seems to work only when the function is called from a cell, not from VBA.
Is what I'm trying to do impossible?
Update
According to > 1 person, this is in fact impossible. If anyone happens to know some clever workaround please speak up.
Ok, so having read the question properly I'll try again...
So, to state the problem:
you want a routine written in an addin, that when called from vba in another workbook can work out (among other things) which workbook contains the vba that made the call, without having to pass this information explicitly.
As stated this is not possible (this is a similar question to accessing the call stack from code: something that is to my knowledge not possible)
However you can almost get what you want like this
Declare your log function like this:
Sub MyLogger(wb as Workbook, LogText as String)
Dim CallerName as String
CallerName = wb.name
' your code...
End Sub
Then wherever you call the sub use
MyLogger ThisWorkbook, "Log Text"
Not quite as good as passing nothing, but at least its always the same
To get the name of the calling workbook, use
Application.Caller.Worksheet.Parent.Name
Application.Caller returns information about how Visual Basic was called. If called from a custom function entered in a single cell, a Range object specifying that cell is returned
Having got a reference to the cell, .Worksheet.Parent.Name gives you the name of the workbook
Note that Application.Caller will return other things depending on how your function is called (see VBA help for details)
In an Add-In Function called by an Excel Worksheet Array Entered Function Call, I find that "Application.Caller.Parent.name" gives the Sheet Name (Tab Name, not sheet number).
I had the same issue when coding a custom function. Function works well, but anytime another workbook is calculated or activated, all cells using that function revert to #value. It can be very frustrating when working with multiple files using this formula.
To get the Workbook I used:
Dim CallingWb As Workbook
Set CallingWb = Application.Caller.Parent.Parent
This should work if your function is in a cell.
Too late for the original post, but might help others!

Resources