I have a VBA macro which is called from a spreadsheet function (user defined function, UDF). When the spreadsheet is downloaded from the internet and the user has set "Trust Center" settings accordingly, the spreadsheet will open in so the called "Protected View". The function will not be called. A button "Enable Editing" is shown.
If the button is pressed, the spreadsheet is "trusted" and reopened normally, starting calculation, and hence calling the user defined function.
However, in that VBA function the value of Application.ActiveWorkbook is Nothing. This can be verified in the debugger.
Since I just need to read some properties (like path name) of the spreadsheet, I could alternatively inspect the availability of Application.ActiveProtectedViewWindow which should reference to the protected version of the workbook. In the debugger, this object can be inspected. However, running in release (without debug) the value of Application.ActiveProtectedViewWindow is also Nothing.
Both behaviors - especially the first one - appears to be a bug present in Excel 2010 and 2013 (see also a post at the MSDN forum ).
Question: Is there a way to get hold of properties of the active workbook after it has been enabled for editing?
PS: As a follow up to the nice observation of Siddharth Rout, that "ThisWorkbook" might work: In my case, the macro is not part of the Workbook being openend. The UDF is defined in an XLA. Hence, ThisWorkbook would reference the XLA. I do need to get the ActiveWorkbook (= the workbook calling the UDF) instead of ThisWorkbook (= the workbook running the UDF).
IMPORTANT REQUIREMENT:
My function is called as a user defined function, i.e., execution order is determined by Excel updating the cell.
The function is not part of the workbook being opened. It is part of an XLA.
I cannot add any code to the workbook which is opened.
Summary: The problem can be replicated and there are some possible workarounds. The most promising one - resulting from a chat - is to use ActiveWindow.Parent instead of ActiveWorkbook.
I was able to replicate the problem.
I tried
Private Sub Workbook_Open()
MsgBox "Application.ActiveWorkbook Is Nothing = " & _
CStr(Application.ActiveWorkbook Is Nothing)
End Sub
And I got True
However, then I tried this and it gave me False
Private Sub Workbook_Open()
MsgBox "Application.ActiveWorkbook Is Nothing = " & _
CStr(Application.ThisWorkbook Is Nothing)
End Sub
Now answering your question...
Question: Is there a way to get hold of properties of the workbook after it has been enabled for editing?
Yes. Use ThisWorkbook instead of ActiveWorkbook
Followup From Comments
Once the workbook completely loads after you exit the Protected Mode, you would be able to access the ActiveWorkbook object. To test this, put this code in the protected file.
Private Sub Workbook_Activate()
MsgBox "Application.ActiveWorkbook Is Nothing = " & _
CStr(Application.ActiveWorkbook Is Nothing)
End Sub
You will notice that you get a False
So once your workbook loads, your add-in can use ActiveWorkbook to interact with the opened file.
Here is another test
Private Sub Workbook_Activate()
MsgBox ActiveWorkbook.Path
End Sub
This is what I got the moment, I exit the Protected Mode
FOLLOWUP FROM CHAT
Using ActiveWindow.Parent.Path instead of ActiveWorkbook.Path would solve the problem.
I had this same issue today, and neither the accepted answer nor any other answer that I could find on this page or through searching the Google-verse worked for me. I'm using the version of Excel within Office 365, and I figured that was at the root of the problem.
I eventually came to a solution after finding a Microsoft Excel 2010 resource and hitting the old try-fail cycle for a few hours. Here's what I got:
Option Explicit
Public WithEvents oApp As Application
Private bDeferredOpen As Boolean
Private Sub Workbook_Open()
Set oApp = Application
End Sub
Private Sub oApp_WorkbookActivate(ByVal Wb As Workbook)
If bDeferredOpen Then
bDeferredOpen = False
Call WorkbookOpenHandler(Wb)
End If
End Sub
Private Sub oApp_WorkbookOpen(ByVal Wb As Workbook)
Dim oProtectedViewWindow As ProtectedViewWindow
On Error Resume Next
'The below line will throw an error (Subscript out of range) if the workbook is not opened in protected view.
Set oProtectedViewWindow = oApp.ProtectedViewWindows.Item(Wb.Name)
On Error GoTo 0
'Reset error handling
If oProtectedViewWindow Is Nothing Then
bDeferredOpen = False
Call WorkbookOpenHandler(Wb)
Else
'Delay open actions till the workbook gets activated.
bDeferredOpen = True
End If
End Sub
Private Sub WorkbookOpenHandler(ByVal Wb As Workbook)
'The actual workbook open event handler code goes here...
End Sub
The difference between the 2010 solution and mine is that I had to call Workbook_Open and explicitly set the oApp variable there, because without that assignment neither the oApp_WorkbookActivate nor oApp_WorkbookOpen functions would fire when I opened the file.
Figured that someone else might be able to benefit from this, so I posted it, despite the fact that the most recent update to this thread is better than 2 years old.
Best.
Try using Application.Caller.Parent.Parent instead of Application.Activeworkbook
This is not a complete answer to the original question, but a (dirty) workaround for a problem related to this.
I needed ActiveWorkbook to infer the workbooks path, that is ActiveWorkbook.Path.
An alternative to using ActiveWorkbook.Path is to check for Application.RecentFiles(1).Path which is the path of the most recently opened file. In many cases this will be the workbook for which the user just has "Enabled Editing". However, of course, this method may fail: In the case the used opened another sheet, then enabling the previously opened sheet.
(Note: ActiveWorkbook.Path give the path of the folder, while Application.RecentFiles(1).Path gives the complete path of the file, so there has to be some post-processing).
I know it's old thread, but i came across the same issue and i found solution ;)
The only way to go around it, is to use variable type Workbook
Dim wbk as Workbook
Set wbk = Application.ProtectedViewWindows(index).Workbook
Warning:
ActiveSheet returns Nothing when active window is protected too.
Dim wsh As Worksheet
Set wsh = wbk.Worksheets(index)
Try this code it works.
If (UCase(ActiveWorkbook.Name) = ucase("<YOUR XLA NAME WITH EXTENSION>")) Then
End
End If
Set wbObj = ActiveWorkbook
First time when you run the macro, it just ends without doing anything. Second time it picks up the proper file.
Related
Hi so I am building an Excel system to run macro for running several different Macros on other Excel files.
Let's say I have two Excel files: "Parent.xlsx" and "child.xlsx" opened already.
In my Parent.xlsx I am running an VBA script, how can I run a macro called "method1" in my "PERSONAL.XLSB" for my "child.xlsx"
Right now, in my Parent.xlsx, I try to run this macro VBA script:
Workbooks("child.xlsx").Application.Run "PERSONAL.XLSB!method1"
In my PERSONAL.XLSB in Modelue6, I have:
Sub method1()
Dim rTable As Range
Selection.AutoFilter
End sub
Error:
Run-time error'1004':
AutoFilter method of Range class failed
Thank you very much!
You need to qualify and reference the workbook that the code should act on.
Look into the ActiveWorkbook property here: https://learn.microsoft.com/en-us/office/vba/api/excel.application.activeworkbook
Application.Run
In Parent.xlsx (to keep the code, save the file as e.g. Parent.xlsm)
Sub callMethod1()
Dim wb As Workbook
Set wb = Workbooks("child.xlsx")
Application.Run "PERSONAL.XLSB!method1", wb
End Sub
In PERSONAL.XLSB
Sub method1(wb As Workbook)
wb.Activate
If Not Selection Is Nothing Then
If TypeName(Selection) = "Range" Then
If ActiveSheet.AutoFilterMode Then
ActiveSheet.AutoFilterMode = False
End If
Selection.AutoFilter
End If
End If
End Sub
First off, you can't expect macros in a workbook of xlsx format. Make sure that you have eikther xlsm or xlsb as a source. This gets us to the second necessity. The workbook must have been saved to have such a format. You can't call a macro from an open workbook that hasn't been saved (because it doesn't have any format yet).
This is the correct syntax for calling an existing macro in another workbook.
Sub Test_TestCall()
Application.Run "'Personal.xlsb'!Method1"
End Sub
Add arguments to the call in brackets in the sequence required by the called procedure.
You may find it easier, however, to simply set a reference to the other workbook. Here is a step-by-step guide how to set a reference. Once a reference is set you can call all macros in the other project as if they were within the calling workbook. The reference gets saved with the workbook and will still be there when you next open the workbook. The drawback of this (and any other method) is that you can't send a working copy of the calling workbook to third parties unless you send the referenced workbook as well.
The error you get has yet another reason. The Selection is made by the user in the ActiveWorkbook, and since you don't tell Method1 which workbook is active it wouldn't be able to find it, right? However, this problem is best solved by following the most basic of all programming rules: "Avoid the Selection object!" Use the Range object instead. If you absolutely must use the Selection` object then pass it to your procedure as an argument.
Application.Run "'Personal.xlsb'!Method1(Selection)"
' and
Sub method1(MyRange As Range)
Dim rTable As Range
MyRange.AutoFilter
End sub
Excel 2016 (or 365) does not seem to fire the Workbook_Open() sub reliably or more precisely, not at all!
The simple event sub
Private Sub Workbook_Open()
MsgBox "Work book is open"
End Sub
does not seem to work. However, if a workbook is already open and then the workbook containing the above Sub is then opened, it does run as expected.
I notice that unlike Excel 2010, 2016 (365) opens each workbook in its own window, not a workbook window in the Excel application window. Is this a bug in 2016 and is there a workaround?
I have produced a work around for my own applications and that is call the activation of a worksheet and call my initialization routines from there. But a bit "rough" and it would be good to have the Workbook_Open() sub working correctly.
It is a simple single Sub in the ThisWorkbook module. Macros are enabled. In Excel 2010 it works perfectly, as do two other macros in other workbooks for which I have written macros. It is just this one thing with Excel 2016. Given that the Workbook_Open() sub is the gateway to a workbook it seems a little strange that we have to go to a workaround to make it function.
Try encapsulating the call with a new instance of Excel. Example below:
Sub OpenInNewExcel()
Dim Background_Excel As Excel.Application
Dim pathName As String
Dim fileName As String
Let pathName = "Enter your path here" 'include "\" at the end
Let fileName = "Enter your file name here"
Background_Excel.Workbooks.Open fileName:=pathName & fileName
Background_Excel.Parent.Quit ' This is how you close the file completely using VBA otherwise the file will close and the Excel Shell will remain.
End Sub
Also make sure that enable macros is turned on in the Options-Trust Center.
You have to add the file/folder location of your workbook as a "Trusted Location".
You can see more info about that in Designate trusted locations for files in Office 2016.
I have same problem then I found solution after google it:
https://www.myonlinetraininghub.com/excel-forum/vba-macros/excel-2016-workbook_open-event-doesnt-trigger
Then I also use "Private Sub Workbook_Open()" and "Public Sub Auto_Open()" open in excel 2016 that work fine:
Private Sub Workbook_Open()
CustomStartUp
End Sub
Public Sub Auto_Open()
CustomStartUp
End Sub
Private Sub CustomStartUp()
MsgBox "Work book is open"
End Sub
I've had this problem (I'm using Microsoft 365), and I found this thread.
It happens for me sometimes when I have another workbook already open, then, on trying to open my macro-enabled workbook, before any sheet is displayed I get the Microsoft warning message about macros. Then, although I click its 'Enable' button, the Workbook opens, macros do get enabled, but Workbook_Open doesn't run.
I've never known the problem to occur if no other workbook is open. (Of course, the user might still get the yellow-backed messages at the top of the workbook, asking them to click the Enable Editing and/or Enable Macros buttons.)
Note that my Workbook_Open just calls another 'workbook-opening' sub in a module to do all the opening processing.
My solution: When my workbook-opening sub is called, it sets a global variable to True to indicate it has run.
I've made it obvious to the user that the problem has occurred, by means of a 'Welcome' sheet with all its cells locked, so the user can do nothing; at this point all other sheets are very hidden. The workbook-opening sub, when it runs, deactivates this sheet and makes it very hidden, so the user never normally sees it, and makes the other sheets visible. But if this screen remains, it instructs the user to select the other workbook, then select this one again. My Workbook_Activate code then runs, and because the global variable isn't True, it calls the workbook-opening sub. If this global variable is True, it does nothing.
To make this work, the Workbook_Close sub makes the other sheets very hidden and the Welcome sheet visible, ready for the next time the Workbook is opened.
Hey presto, the problem is solved.
The Welcome sheet actually has a dual purpose, in that if either of the yellow-backed warning messages are displayed, it will remain and force the user, with suitable instructions, to click Enable Editing and/or Enable macros. If the users aren't au fait with macro-enabled Excel, they will just ignore these and try to carry on regardless.
All this is much easier to implement than to explain. I hope it's clear.
And I hope this might be of help to someone.
I had this issue with one of my files as well. I managed to fix this issue by running Workbook_Open manually in the VBA editor once open and saving the file in another location. The file in the new location should have no issue with auto-running Workbook_Open. If this doesn't work, copy the original file to a new location before manually running & saving.
If the newly saved file does not run Workbook_Open, repair your version of Office.
I keep running into an issue where the worksheet in question gets updated, and then doesn't reflect the changes until I close and re-open the book. It's not really a big deal, I just want to simplify it a bit into a single button click.
I was told that this is impossible to do because closing a workbook will immediately stop execution of code, so you can't reopen the book. But since, I have learned about the PERSONAL.xlsb, and figured since it's a persistent workbook, it could handle the code execution to save, close, and reopen the workbook.
Basically, here's what I've got in the main worksheet:
Public Sub Refresh()
ActiveWorkbook.Save
Application.Run "PERSONAL.xlsb!Module1.RefreshCurrentSheet",ThisWorkbook.Name,_
ThisWorkbook.FullName
End Sub
Which then calls the personal.xlsb macro "Refreshcurrentsheet":
Private Sub RefreshCurrentSheet(ByVal sheetname, Optional ByVal sheetfullname = 0)
Workbooks(sheetname).Close
MsgBox "So far so good!" 'I never see this box
Workbooks(sheetfullname).Open
MsgBox "No errors here..." 'I never see this box
End Sub
This successfully closes the workbook in question, but code execution stops and it doesn't reopen. Is there a way around this? Some way to run the second macro in the persistent sheet without code execution stopping?
We can reopen the workbook using this code inside it (there is no need to use other workbook):
Sub test()
Application.DisplayAlerts = False
Workbooks.Open ThisWorkbook.FullName
Application.DisplayAlerts = True
End Sub
In a subroutine, I want to open a workbook, do some reading from it, and close it.
For some reason, I get an error:
Run-time error '1004':
Method 'Close' of object _Workbook failed
I have identified a minimal code snippet to reproduce the problem.
Create a fresh excel file. In it, create a Userform. On that, create a Command Button with the following Click event code:
Private Sub CommandButton1_Click()
Dim filename As String
Dim opened_workbook As Workbook
filename = Application.GetOpenFilename() ' User selects valid Excel file
Set opened_workbook = Application.Workbooks.Open(filename)
' File operations would occur here
opened_workbook.Close ' Exception thrown here
MsgBox "If you got here, it worked!"
Unload Me
End Sub
What really perplexes me is that this error doesn't happen with the same code when the Command button is not on a userform (on a plain button straight on the worksheet).
I don't even know what else to report or where to look to explain this behavior (besides StackOverflow!). I'm writing VBA using Excel for Mac 2011 and can move to Windows Excel 2010 if it makes a difference.
Yes, in Excel 2011, it is a bug (Undocumented - I haven't found a documentation for it yet). You have to slightly modify the code. Try this
Private Sub CommandButton1_Click()
Dim filename As String
Dim opened_workbook As Workbook
filename = Application.GetOpenFilename() ' User selects valid Excel file
Set opened_workbook = Application.Workbooks.Open(filename)
Unload Me
opened_workbook.Close
MsgBox "If you got here, it worked!"
End Sub
I had this exact problem on Excel 11 on Mac (Worked fine Excel 2013 on Windows), only the error occurred in a module sub that was called from the UserForm.
If somebody (like me) is trying to use the workbook.close method from a sub/function in a module (or another location) that is not inside the UserForm itself you can't use 'Me'. 'Me' is only usable within the UserForm code itself.
Instead of 'Unload Me' use the unload function and the name of your UserForm.
Unload UserFormName
I open a query from SAP BW... I make all the changes I need and I even check the box that says Refresh query every time you open the workbook. The problem is that when I reopen the workbook it's just like a regular Excel, because the SAPBEX.xla file is not loaded anymore.
Any ideas on how can I solve this?
I want the workbook updated with the latest data every time I open the workbook.
Thanks!
You can use an application event (see Chip Pearson's website).
Put this code in the This Workbook module of your PERSONAL.XLSM (see here).
Private WithEvents App As Application
Private Sub Workbook_Open()
Set App = Application
End Sub
And in a module:
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
MsgBox "New Workbook: " & Wb.Name
'or better check here if this is your workbook and activate the addin
End Sub