I'm making a template for macro addins in Excel. Addins have this weird thing that when you close them Excel won't prompt you to save. So I want all my addins to inherit from a template with this code:
Private Sub Workbook_BeforeClose(ByRef Cancel As Boolean)
'check for save because Excel doesn't prompt for addins
'but save will fail if this is a new file, so fall back to default prompt then
If Me.Path <> vbNullString And Not Me.Saved Then
Select Case MsgBox("Wanna save before you quit?", vbQuestion + vbYesNoCancel, "Unsaved Changes")
Case VbMsgBoxResult.vbYes
Me.Save
Case VbMsgBoxResult.vbCancel
Cancel = True
End Select
End If
End Sub
Now I would also like all files made with this template to be set to be addins:
'one shot ideally
Private Sub Workbook_Open()
'only run on new files
If Me.Path = vbNullString Then Me.IsAddin = True
End Sub
The problem is though for files created from macro enabled templates .xltm
, Excel defaults to saving as .xlsm - not .xlam addin files which is required for IsAddin to be True
So I can add:
Private Sub Workbook_Open()
If Me.Path = vbNullString Then
Me.IsAddin = True
Application.DefaultSaveFormat = xlOpenXMLAddIn
End If
End Sub
But that sets the default for all files in Excel. I only want to temporarily change the default until this file is either saved or discarded without saving. Workbook_BeforeSave
runs too late, after the ui is shown with xlsm not xlam.
Any ideas? I don't want to save immediately on creation if that can be avoided, since I may want to discard a file without saving.
We don't want to be running code in the
Open
orBeforeClose
events (or any other) while editing the actual.xltm
template. This should help:We would simply add
If IsTemplate() Then Exit Sub
at the start of each event method.Once a new file is created using the template, there are 2 ways to save. Since the file is turned into an AddIn, the user can't really click the Save button in Excel itself but it can save from within VBE or by closing Excel.
Saving from VB Editor
The user might press the Save button in the VBE or simply Ctrl+S from keyboard while editing code. For this we can use a
BeforeSave
-AfterSave
pair of events. Something like this:Closing Excel
The user might click the Excel close button. This is where your question actually points to.
A way of dealing with this is to change the
Application.DefaultSaveFormat
from theBeforeClose
event and that works well with the downside that we now need a way to restore the app format. And that's made even worse by the fact that the user might press Cancel or Don't Save.Unfortunately there is no event that signals that the application is closing or that the close was cancelled. The only thing I can think of is to trap a state loss. To do that you could use your own subclassProc method but that would require too much boilerplate. Instead I suggest we use a fake object and take advantage of
IUnknown::Release
.In a standard 'bas' module add this code:
The final code in the
ThisWorkbook
module can become:I've tested a couple of scenarios and it seems that the
Application.DefaultSaveFormat
is restored correctly. Apologies if I missed any.