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
Related
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.
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.
I'm using this VBA macro in an Excel 2010 workbook to define the function FileSize, which enables me to pull the size of a document into a document master worksheet using the filepath.
Function FileSize(FileName As String)
FileSize = FileLen(FileName)
End Function
I then use the FileSize function to reference a file path string in column A like so:
=FileSize(A1)
This works in the workbook I wrote it for initially, but when I copypaste the macro for the Function into a new module for a new worksheet, I get an invalid name error.
Both workbooks are macro-enabled (.xlsm), and activating or deactivating option explicit hasn't had any effect. What am I doing wrong?/What am I neglecting to do?
#NAME suggests that your new workbook has no idea what the formula =FileSize() is referring to.
Double check to insure that you are actually putting that function in a module in the same workbook in which you are using the formula.
Make sure that you have defined the code as a Function and not a Sub.
Rip your computer off your desk and throw it out the window.
Thank you, JNevill! Luckily, defenestration won't be necessary.
I figured it out--I gave my module a name that was identical to the function it contained. Just changed the module name, and now the functions populate correctly.
I have a VBA program that asks for the user to enter a desired range, which is in another opened workbook. If there is an error, i.e. the other workbook is manually activated, but no range is selected, or there is an error, I want the program to display the original macro workbook sheet with an error message. The code below works in Debug mode, but when the VBA program is run, it displays the error correctly but does not display the original macro worksheet. It remains on the sheet that was manually activated by the user. What am I missing?
In the code below, "HMArea" is a Range variable returned by the routine getting user input.
"Macro_Fname" is a string variable for the file name of the original VBA program.
HM_file = FileName(HMArea)
If HM_file = "Macro_Fname" Then
Windows("Macro_Fname").Activate
Sheets("[name of the sheet in Macro_Fname]").Select
Range("D4").Select
MsgBox "ERROR: No data selected"
Exit Sub
End If
Try changing
Windows("Macro_Fname").Activate
to
Workbooks("Macro_Fname").Activate
However, the exact nature of your question is vague. Assuming you are in Workbook A, do you want to select a range in Workbook B (which is open at the same time)?
To refer to macro workbook use ThisWorkbook
When another workbook is opened always assign it to variable so that you can have control over it.
Set wbk = Workbooks.Open("D:\test.xlsx")
When working with multiple workbook always prefix the workbook object. If its ignored it will take active workbook.
`Sheets("[name of the sheet in Macro_Fname]").Select`
Avoid using Select/Acitvate. See here
Range("D4").Select
Once the above issues are fixed your code will run as expected.
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!