How to make application level event handlers in VBA? - excel

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

Related

Running Excel Add-In Macro Based on Workbook Events

I want to create a macro that takes the user to the last previously active sheet. I need this macro to keep track of all previously active sheets, which it should be able to do automatically. I want to add this to an Excel add-in, since it needs to be compatible with all the worksheets that my company's using. The sheets themselves are not macro-enabled, so I can't have any code stored in the modules of ThisWorkbook.
I have tried out the examples that I've found on other websites. Unfortunately, all of them require using ThisWorkbook, which I won't be able to use. Is there a way to do this purely within an Excel add-in?
Public MyPrevSheet as String
Sub GoToPreviousSheet()
If Len(MyPrevSheet) > 0 Then
Sheets(MyPrevSheet).Activate
ActiveWorkbook.ActiveSheet.Previous
Else
MsgBox "You have not switched sheets yet since opening the file!"
End If
End Sub
Ideally, I would like for MyPrevSheet to automatically track the last active sheet in the file.
Update: I managed to make it work using Application Events. The idea is to create a class module that can then be assigned the Application.
Here are some useful links that helped me: http://www.cpearson.com/excel/AppEvent.aspx
https://www.jkp-ads.com/Articles/buildexceladdin05.asp

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.

Excel Add-in, when to check for updates?

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.

Connecting password-protected Excel to Access

I want to link a password-protected Excel document to Access - this is not working due to the it being password-protected.
Does anyone have an alternative method to do this?
It has to be password-protected unfortunately and cannot be moved to a secured folder so not sure how to do it.
Any advice?
Try using a hidden form to automatically open the Excel file when the database file is opened.
Add this to a new Module:
Option Compare Database
Public xl As Object
Function OpenExcelFile()
xl.Workbooks.Open "path to file.xlsx", , , , "password"
End Function
Function CloseExcelFile()
xl.Quit
set xl=nothing
End Function
Create a blank form and set the HasModule property to true. then add the following to the form's code module.
Private Sub Form_Load()
OpenExcelFile
End Sub
Private Sub Form_Close()
CloseExcelFile
End Sub
Now create a new macro with an OpenForm task to open your form. Set the window mode to 'Hidden'. Save the macro with the name 'AutoExec'. This makes it run when the db is opened.
When the db is opened the macro will run and open the form hidden. The form load event will fire, creating a public Excel.Application object that opens your excel file (you should be able to remove the password from the code if you want the user to be prompted for it). The Excel application will remain open until the hidden form closes (when you close the database). At that point the form close event will fire, causing the Excel Application to quit. As long as the Excel file is open, you should be able to use linked tables and queries.
**You could add xl.Visible=true to the OpenExcelFile function if you want it to be visible to the user.
This link as a similar idea: https://www.connectionstrings.com/how-to-open-password-protected-excel-workbook/

Installing a VBA macro in Excel 2007

I've got a VBA macro in an Excel 2003 spreadsheet and I'd like to 'install' it on a machine running Excel.
I created a 'Trusted Location' on the local machine, and I know how to copy the module to the existing workbook and assign a key combination to invoke it, but I don't know how to make the macro appear automatically when someone starts Excel. Help?
The simplest solution is ( both for xl2003 and xl2007 ) to copy your xls containing the macro to the path = Application.StartupPath from your client machine ( can build a simple vbscript installer which instantiates excel and retrieves this information ).
This way your macro will be available in any workbook opened since the xls files located in startuppath are loaded at excel startup.
I remember the old way was to save your macro in your Personal.xls
workbook - then it would be accessible
any time you opened Excel - has this changed for 2007?
That was a way. A better way was (and is) to create an Add-in, which you can then enable & disable via Tools->Add-ins. (An Add-in will remain enabled even if you close and re-start Excel). You can save any .XLS file as an Add-in (.XLA).
Within your Add-in you could just use an Auto_Open method:
Private Sub Auto_Open()
DoStuff
End Sub
...or, you could hook up the Workbook_Open event, as Ryan suggests.
Of course, since the user can disable the Add-in, you also want to do the reverse in Auto_Close (or in the Workbook_BeforeClose event).
Actually, if you use events it'd be better to use the Workbook_AddinInstall and Workbook_AddinUninstall events. Using those is slightly more "correct", and also has the benefit that the 'close' event doesn't fire if you close Excel and then hit Cancel when prompted to save.
I'm not sure what you mean by 'appear', but you can execute it automatically by calling it from
Private Sub Workbook_Open()
End Sub
in the ThisWorkbook object module. Is that what you're looking for?
I remember the old way was to save your macro in your Personal.xls workbook - then it would be accessible any time you opened Excel - has this changed for 2007?

Resources