Excel Add-in, when to check for updates? - excel

I've made a useful Excel VBA add-in that I'm almost ready to publish. I only have one problem. I want the add-in to check for updates whenever it is ran, and to notify the user if they're using an old version.
I have written a public sub that will check my website for the update using internet explorer automation. It is working fine when I run it manually.
My issue is, when should I call the CheckForUpdate() sub? I've tried putting it in Workbook_Open(), but the issue I've found is that if it takes too long, it blocks Excel from loading properly.
Is there a standard way that add-in writers check for updates? Why does Excel not load up a workbook when I have code in Workbook_Open()?
Thanks!
Edit: Here is my entire code. If this is added to an add-in workbook, and then the add-in is activated, I can't open any Excel files.
Private Sub Workbook_Open()
Call CheckForUpdate
End Sub
Public Sub CheckForUpdate()
Dim ie As Object
Set ie = CreateObject("internetexplorer.application")
ie.Visible = False
ie.navigate "https://example.com/checkforupdate"
Do While ie.readystate <> 4: DoEvents: Loop
Set HTML = ie.document
If HTML.DocumentElement.innerHTML = "update is available" Then
MsgBox "An update is ready. Go get it!"
Else
MsgBox "no update"
End If
Set ie = Nothing
End Sub
Update: I've tested on three computers now. 2 of them have Excel 2013 and the problem happens. One has Excel 2016 and it doesn't have the problem. I want to support all Excel versions, so I still need a work around.

Ok, I ran your code and reproduced the issue, with Excel 2013. I didn't test on any other version.
It looks like what happens is if your code runs before a workbook is visible, it causes problems. I think it has more to do with the IE part, than anything else.
I tried using Application.OnTime Now + TimeValue("00:00:15"), "CheckForUpdate". The problem with that is that if the user starts excel and out waits the timer before opening a workbook, you have exactly the same problem. I suspect the persons suggesting asynchronous VBScript will have exactly the same issue, but in a much more complicated way.
So let's go simple. You asked for a better place to put your code than Workbook_Open(). There is one.
Here's what worked for me:
Start a new add-in project. Add your CheckForUpdates function to a new module. Add the following code to ThisWorkbook.
Private WithEvents App As Application
Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
CheckForUpdate
End Sub
Private Sub Workbook_Open()
Set App = Application
End Sub
With this code, your update procedure will run when a workbook is activated. It appears to not cause problems there.
Please let me know if that works. Good luck.

Related

How to make application level event handlers in VBA?

I have a VBA add-in that sits in a shared file drive that three users in my organization have added to their Excel. I thought the add-in would be handy because I could push changes to the code without updating the code in any individual Excel sheets. When I tried updating the code in the add-in, the add-in was read-only because other users had Excel open. I've been trying to figure out how to make the add-in read only whenever anyone else (meaning anyone other than me) opens an instance of Excel. I've added the below code to a class module in my add-in. I've tried debugging, but no part of the below code is executed when a user opens a new workbook. I'm totally stuck.
Private WithEvents App As Excel.Application
Private Sub Workbook_Open()
Set App = Application
End Sub
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
If App.UserName <> "Andrew Lubrino" Then
SetAttr "C:\FilePath\Add-in.xlam", vbReadOnly
End If
End Sub
I've found a number of posts on this topic all with accepted code for seemingly the same problem, but the code simply doesn't work in my environment. Can anyone tell me what's going wrong?
edit:
I'm trying to make the add-in read only for all other users so that when I try to edit and make changes to the distributed code, I can save those changes. With the current set up, I can't save the code whenever any other user has Excel open. For the above code to work, you'd need the event to trigger for any workbook that another user opens

Workbook_Open() in Excel 2016 not firing

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.

Workbook_Open() won't execute Excel 2011

Using Excel 2011 (should be same as Excel 2010)
Code is under the "ThisWorkbook" module in Excel
Events are enabled
Macros are enabled
I can't seem to get either Workbook_Open() or Workbook_BeforeClose() to execute. I've read numerous posts on the subject but no solution. Here is some simple test code that should execute but doesn't. Any help would be greatly appreciated.
Private Sub Workbook_Open()
ActiveSheet.Range("BL4").Value = "Open is working"
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next 'in case the menu item has already been deleted
ActiveSheet.Range("BL5").Value = "Close is working"
End Sub
First make sure you have put this in this in the right place and have macros enabled.
Then, try adding this line to the workbook_open method:
MsgBox "HELLO"
Do you see the msg box? You're choice of cell looks a bit strange
Also, I think you need to use a .xlsm file not .xlsx (Although not sure on that one)
FInally, if a plugin calls something like this line, it could cause your events not to fire..
Application.EnableEvents = False
So make sure you have tested it with no other sheets or addins open.

Excel's VBA ActiveWorkbook is "Nothing" when "Enable Editing" from ProtectedView

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.

Is it possible to deploy a VB application made in Excel as a stand alone app?

Basically wondering if there's a way for me to create a VB application in Excel and have it run without a full version of MS Office. The VB application would load an Excel sheet that would import a CSV onload, then print a PDF of the sheet and close.
If you have any questions, let me know.
No. Not without converting to a standalone application.
If you had were familiar with VB6 (and had access to it; it's no longer for sale), you could create a VB6 app. that references the excel COM components (still need to be installed on each target PC).
Otherwise, build an app. using VB.NET and use Office VSTO 2010 (need to reference the Office PIAs)
How to: Target Office Applications Through Primary Interop Assemblies
Just a little conflict. In office, you code with VBA, which is different than VB. What you would need to do is create a VB app that uses excel libraries or something to do some meaningful work.
The short answer is no.
You could write an external visual basic script that calls in to office and opens excel using some excel libraries, if memory serves me correctly however - you'd still require office installed on this machine. (Unfortunately I can't find a link at the moment to back this up)
Your best bet is to parse the CSV data yourself and generate a PDF from that.
There is some information here: http://www.rlmueller.net/ReadCSV.htm on how to Read CSV data using VBS (to get the examples to run, you should simply have to rename the .txt to .vbs and double click it.)
I'll leave you to find out how you'd then generate the PDF.
I don't think however this is the best solution to your problem - a full .NET application or perhaps some Python would likely serve you better.
Code will go in several different places, "ThisWorkbook" object and the "UserForm" code.
"ThisWorkbook" contains code that will determine if the UserForm is the only Excel thing (workbook) open, and if it is it will hide the Excel application and hide the workbook itself. and if other workbooks are open it simply hides the workbook. I have it set to hide the application and the workbook in both cases so that a new instance of Excel can be opened after the UserForm is running without pulling up the workbook associated with the UserForm. The code for this is below (goes into the "ThisWorkbook" object):
Private Sub WorkBook_Open()
Dim wb As Workbook
Set wb = Workbooks("MyBook.xlsm")
If Workbooks.Count > 1 Then
wb.Windows(1).Visible = False
Else
wb.Windows(1).Visible = False
Application.Visible = False
End If
UserForm1.Show vbModeless
'Put defaults and populations here
End Sub
The UserForm1.Show vbModelessallows for Excel to be used while the UserForm is active.
A couple of notes on this section:
"UserForm1" is the name of my UserForm, change this to the name of yours
Where I Set wb = Workbooks("") change inside the quotes to the name of the
workbook the UserForm is in
The IfElse statement could be eliminated and moved to the If, if you don't need any other action on the opening with no other workbooks open
The next section of code goes in the UserForm Code. I have a button set up to show the Excel workbook in order to edit it and whatnot, you could have a region you click if you don't want a button to show up. When you want to activate the Excel sheet and the application will need to be activated. I unload (deactivate) the active thing (the UserForm). This bit of code isn't necessary if the user doesn't need access to the spreadsheet:
Private Sub See_Excel_Click()
Dim wb As Workbook
Set wb = Workbooks("MyBook.xlsm")
wb.Windows(1).Visible = True
Application.Visible = True
wb.Sheets("Sheet1").Activate
Unload Me
End Sub
Within the userform there should be a way to handle what happens when the userform is closed, as the excel application and workbook will stay open hidden in the background. I have the action close the workbook and the application. A quick note, if you set the Cancel = True then the red x button won't close the userform. The code I use for this is:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then
Cancel = False
Dim wb As Workbook
Set wb = Workbooks("MyBook.xlsm")
wb.Windows(1).Visible = True
Application.Visible = True
ThisWorkbook.Saved = True
ThisWorkbook.Activate
If Workbooks.Count > 1 Then
ActiveWorkbook.Close
Else
Application.Quit
End If
End If
End Sub
That is it for the code that goes inside the UserForm. And the code that is necessary to have the UserForm in VBA act as it's own application while allowing for Excel to operate normally at the same time as the UserForm.
To summarize what happens:
When the Workbook is launched the workbook is hidden, and if no other workbook is open the the Excel application is hidden.
The UserForm is initiated to allow for Excel to be used at the same time
When the spreadsheet is activated again excel is re-enabled and the application and un-hide the worksheet
When the user form is closed, the workbook is closed, and if there are no other workbooks the excel application is closed
If you set defaults or populate ComboBoxes put them in the "WorkBook" object code.

Resources