excelvbasave-as

Excel won't let macro save spreadsheet with macros


I've written a spreadsheet for a small company, that has several useful functions including performing the shift rotation for their full- and part-time employees, generates a list of possibly understaffed shifts and then prompts the user to save the updated file with a suggested new name. However I code it, I run into one of 2 problems:

  1. The macro is able to save the spreadsheet without the macros - but then subsequent adjustments to the scheduling won't be reflected in the list of understaffed shifts because the macro isn't saved with the file.
  2. The macro attempts to save the spreadsheet with the macros - but returns an error message, regardless of the parameters I pass the Workbook.SaveAs method. I would have expected that if I saved it with FileFormat=xlOpenXMLWorkbookMacroEnabled and a .xlsm suffix, then there'd be no problem. Instead I get an error message (sorry I don't have it in front of me) to the effect that Excel can't save the spreadsheet in that format. If I manually save the spreadsheet in that format, I have no problem.

I suspect this has to do with safeguards against VBA viruses, but I'm not sure how else to create the functionality I need. The office staff are not computer professionals by any stretch of the imagination, so I need to keep it simple. We also need a record of past rotations, so staff can look back on previous adjustments. At the same time, they want to be able to make adjustments to the current rotation and then re-generate the list of understaffed shifts, or clear it and start again. I've checked similar forums and posts and the thing that usually does the trick, making sure the filename suffix is in line with the FileType parameter, doesn't seem to have worked here. Any suggestions?

Public Sub SaveSchedule()
    Dim SaveName As String
    Dim SaveDlg As Office.FileDialog
    
    With Excel.ActiveWorkbook.Worksheets("Workers")
        SaveName = "Shift Schedule " & Year(.Range("StartDate"))
        SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
        SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
        SaveName = SaveName & " to " & Year(.Range("EndDate"))
        SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
        SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
        SaveName = SaveName & ".xlsm" '".xlsx"
    End With
    Set SaveDlg = Application.FileDialog(msoFileDialogSaveAs)
    With SaveDlg
        .AllowMultiSelect = False
        .ButtonName = "Save"
        .InitialFileName = SaveName
        .Title = "Save new shift schedule"
        If .Show() Then
            Excel.ActiveWorkbook.SaveAs .SelectedItems(1), xlOpenXMLWorkbookMacroEnabled ' xlOpenXMLWorkbook
        Else
            MsgBox SaveName & " should be saved as a new file.", vbCritical + vbApplicationModal + vbOKOnly, "New Schedule not saved."
        End If
    End With
End Sub

Error message: This Extension can not be used with the selected file type.


Solution

  • The issue with Application.FileDialog(msoFileDialogSaveAs) is that if you do not specify a correct filter index then it will either pick the first one

    enter image description here

    OR the one which was used last. This can be resolved by specifying .FilterIndex. For .xlsm. the filter index is 2.

    enter image description here

    Try this

    With SaveDlg
        .AllowMultiSelect = False
        .ButtonName = "Save"
        .InitialFileName = SaveName
        .FilterIndex = 2 '<~~ FILTER INDEX
        .Title = "Save new shift schedule"
        If .Show() Then
            Excel.ActiveWorkbook.SaveAs .SelectedItems(1), xlOpenXMLWorkbookMacroEnabled ' xlOpenXMLWorkbook
        Else
            MsgBox SaveName & " should be saved as a new file.", vbCritical + vbApplicationModal + vbOKOnly, "New Schedule not saved."
        End If
    End With
    

    OTHER OPTIONS

    OPTION 1 : Directly save the file

    Dim SaveName As String
    
    With Excel.ActiveWorkbook.Worksheets("Workers")
        SaveName = "Shift Schedule " & Year(.Range("StartDate"))
        SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
        SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
        SaveName = SaveName & " to " & Year(.Range("EndDate"))
        SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
        SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
        SaveName = SaveName & ".xlsm" '".xlsx"
    End With
    
    Excel.ActiveWorkbook.SaveAs Filename:=SaveName, FileFormat:=xlOpenXMLWorkbookMacroEnabled
    

    OPTION 2 : Let user only choose a folder

    In this option user will not be able to modify the file name and extension. They can only choose the Save As folder.

    Option Explicit
    
    Sub Sample()
        Dim SaveName As String
        Dim Extn As String
        Dim FlFormat As Integer
        
        With Excel.ActiveWorkbook.Worksheets("Workers")
            SaveName = "Shift Schedule " & Year(.Range("StartDate"))
            SaveName = SaveName & "-" & Right("00" & Month(.Range("StartDate")), 2)
            SaveName = SaveName & "-" & Right("00" & Day(.Range("StartDate")), 2)
            SaveName = SaveName & " to " & Year(.Range("EndDate"))
            SaveName = SaveName & "-" & Right("00" & Month(.Range("EndDate")), 2)
            SaveName = SaveName & "-" & Right("00" & Day(.Range("EndDate")), 2)
            SaveName = SaveName
        End With
        
        '~~> File extenstion. I have shown only for 2
        '~~> Tweak for rest
        Extn = ".xlsm" '".xlsx"
        If Extn = ".xlsm" Then
            FlFormat = xlOpenXMLWorkbookMacroEnabled
        ElseIf Extn = ".xlsx" Then
            FlFormat = xlOpenXMLWorkbook
        End If
        
        '~~> Folder Browser
        Dim Ret As Variant
        Ret = BrowseForFolder
        If Ret = False Then Exit Sub
        
        Dim Filepath As String
        Filepath = Ret
        If Right(Filepath, 1) <> "\" Then Filepath = Filepath & "\"
        
        SaveName = Filepath & SaveName & Extn
        
        Excel.ActiveWorkbook.SaveAs Filename:=SaveName, FileFormat:=FlFormat
    End Sub
    
    Function BrowseForFolder(Optional OpenAt As Variant) As Variant
        Dim ShellApp As Object
         
        Set ShellApp = CreateObject("Shell.Application"). _
        BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
         
        On Error Resume Next
        BrowseForFolder = ShellApp.self.Path
        On Error GoTo 0
         
        Set ShellApp = Nothing
         
        Select Case Mid(BrowseForFolder, 2, 1)
        Case Is = ":"
            If Left(BrowseForFolder, 1) = ":" Then GoTo CleanExit
        Case Is = "\"
            If Not Left(BrowseForFolder, 1) = "\" Then GoTo CleanExit
        Case Else
            GoTo CleanExit
        End Select
         
        Exit Function
    CleanExit:
        BrowseForFolder = False
    End Function