I am just wondering if there is an easy way to make the function "now()", in Excel, just to work when a modification is done on the workbook, and not when the workbook is opened.
take a look at this:
http://www.extendoffice.com/documents/excel/954-excel-created-last-modified-time.html#three
and try using the second macro from:
Sub Workbook_Open()
Range("A2").Value = Format(ThisWorkbook.BuiltinDocumentProperties("Last Save Time"), "short date")
End Sub
Replace A2 with the cell you want to put that last modified time in.
you can also add:
Public Function ModDate()
ModDate = Format(FileDateTime(ThisWorkbook.FullName), "m/d/yy h:n ampm")
End Function
and then call:
=ModDate()
EDIT:
You can also use:
FileDateTime()
http://www.techonthenet.com/excel/formulas/filedatetime.php
You'd have to figure out how to get the file to refer to itself.
Bear in mind though, that a file is changed by being opened, so it might as well be the current time. For more on this, see:
http://support.microsoft.com/kb/826741
So NOW() might be all you have. Also, you can search Excel's components in program files, but if NOW is written in its binary, it might not be changeable.
However...
According to microsoft,
Making your custom functions available anywhere
To use a custom function, the workbook containing the module in which
you create the function must be open. If that workbook is not open,
you get a #NAME? error when you try to use the function. Even if the
workbook is open, if you use the function in a different workbook, you
must precede the function name with the name of the workbook in which
the function resides. For example, if you create a function called
Discount in a workbook called Personal.xls, and you call that function
from another workbook, you must write =personal.xls!Discount(), not
simply =Discount().
You can save yourself some keystrokes (and possible typing errors) by
selecting your custom functions from the Insert Function dialog box.
(Your custom functions appear in the User Defined category.) An easier
way to make your custom functions available at all times is to store
them in a separate workbook and then save that workbook as an add-in
(an XLA file) in your XLStart folder. (The XLStart folder is a
subfolder of the folder containing your Excel files. When you start
Excel, the program opens any documents it finds in XLStart.) To save a
workbook as an add-in, choose File, Save As (or File, Save). Then
choose Microsoft Excel Add-in from the Files Of Type list.
If your user-defined functions are stored in an XLA file that is
present in memory, you don't have to specify the name of that file
when you call a function. If the XLA file is saved in your XLStart
folder, it will be present in memory whenever you run Excel.
http://office.microsoft.com/en-us/excel-help/creating-custom-functions-HA001111701.aspx
So it seems implied that, provided user defined functions are in that workbook, they should work just fine wherever the file is.
Hope that gives you your answer.
Related
I have an Add-In installed in my Excel (which is stored in a separate folder) that I want to run in one of my Excel files through a VBA macro. Whenever I call the:
Application.Run "'Addintorun.xla'"
I get the error that the macro may not be available. I know I might need to enable all macros through Macro Security, but I can't tick this option since it's blocked by the administrator. However the add-in per se works fine, I just can't call it from the macro. I also added a reference to the Add-in in my module but nothing changed.
There are two ways to accomplish what you need:
Add the add-in as reference to the workbook you need calling its Subs, Function(s). In this way you may call them exactly as in the add-in itself. Only in case of the same macro names, the add-in name must be used when make a call.
You can call the Subs which are not private in the next way:
Application.Run "'Addintorun.xla'!MyMacro"
The simple quotes are necessary only if the add-in name contains spaces, but it is a good habit to use them all the time, since they do not bother a name without spaces, neither...
You can also obtain a result of a (not Private) function in the next way:
Dim res As Long
res = Application.Run("'Addintorun.xla'!MyFunction", 3, 9)
Debug.Print res
'MyFunction should receive two `Long` parameters and returning also a `Long`
'It may return any kind of variable, but res must be declared to match it.
Such subs/functions can also be called using the add-inn full name, instead of its name. In this way, the add-in will be loaded/open during the call, if not already loaded...
After a bunch of processing, I save my Excel spreadsheet with a script-defined name and a user-chosen path. In other words, I know exactly where the file is.
I want to close down Excel. If I do
Workbook.Close
...the instance of Excel will hang around. If I do
Excel.Application.quit
...it might affect other instances of Excel I have open.
Given I know exactly which Excel I want to close, can I close the workbook AND the associated instance in a single step, without a lot of testing for other workbooks or instances? TIA
If you already have the Workbook Object, you can access the Application that it is running within using Workbook.Application. The .Parent property also returns the object that the current object is a member of, which for Workbooks, is also the Application.
So either of the following will close the specific Excel App that is running the target workbook:
'Given that TargetWorkbook is a valid Workbook Object
TargetWorkbook.Application.Quit
TargetWorkbook.Parent.Quit
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 want to create an excel template that will includes formulas for dating the columns. However, since those formulas will be based on TODAY(), I need to convert them to static strings (so the dates don't change everytime someone opens it). Is there a way to add a macro that will run automatically when someone creates a new spreadsheet based on the template? (Similarly to Auto_Open(), only on Create, rather than Open). If so, I could just create a macro that will replace the formulas with their results upon document creation. Can this be done?
[Note: I'm not married to this solution; it just seemed like the simplest way to protect my spreadsheet. If someone can suggest an alternative approach, I'd be obliged.]
I have a couple thoughts...
If you run a copy/paste values macro every time it really won't matter, right?
You could check if the file exists yet (has been saved), and if not
then this must be the template opened as a new workbook, maybe?
Code:
Private Sub Workbook_Open()
If Dir(ActiveWorkbook.Name) = "" Then
'run the macro?
MsgBox "I'm gonna run this macro"
End If
End Sub
You could have a cell on one of the sheets, that will never be used,
or is hidden, that will store whether or not to run the macro, and
change that when the file is opened or when the macro is ran. Then
have a macro run on open that checks that cell. (Or custom/document property)
You could populate the cells that have the today() formula only on
open and if they are already populated then don't run the macro?
I realized that there is no need for a Workbook_Create() function, as that behavior can be emulated by simply deleting the macro after it has run once (which happens when it is first created). Deleting macros is done automatically when the file is saved with a .xlsx extension. In addition, you need to prevent the macro from running when you open the template itself (while editing the it). You can hold the SHIFT key when opening it to prevent auto-run macros, but since that method isn't foolproof, I added this code at the top:
Private Sub Workbook_Open()
'If we're opening the template, don't run the macro
If Application.ActiveWorkbook.FileFormat = xlOpenXMLTemplateMacroEnabled Then
Exit Sub
End If
...
'add code here to SaveAs .xlsx, thus removing the macros, so it won't run every time.
End Sub
(Note: I didn't show my SaveAs code as it is rather messy: I wanted to suppress the default warning about losing macros, but wanted to also protect the user from inadvertantly overwriting previous file. If anyone is interested, I could post it)
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!