Search code examples
vbaexcelexcel-2013

How to handle 'No' or 'Cancel' on Workbook.SaveAs overwrite confirmation?


I'm want users to be prompted to save a workbook before the VBA script starts modifying content. When the SaveAs dialog box comes up, if the user clicks Cancel I raise a custom error and stop the script. If they click Save and the filename already exists I want them to be asked whether to overwrite.

Here's my code:

Function SaveCurrentWorkbook(wkbSource As Workbook, strNewFileName As String) As Variant
    If Not bolDebug Then On Error GoTo errHandler
    Dim varSaveName As Variant

SaveAsDialog:
    varSaveName = Application.GetSaveAsFilename(InitialFileName:=strNewFileName, FileFilter:="Excel Files (*.xls), *.xls")
    If varSaveName <> False Then
        wkbSource.SaveAs Filename:=varSaveName, ConflictResolution:=True, Addtomru:=True
        Set SaveCurrentWorkbook = wkbSource
    Else
        SaveCurrentWorkbook = False
        Err.Raise 11111, , "Save Canceled"
    End If

exitProc:
    Exit Function

errHandler:
    Select Case Err.Number
        Case 1004 'Clicked "No" or "Cancel" - can't differentiate
            Resume SaveAsDialog
        Case esle
            MsgBox "File not saved. Stopping script.", vbOKOnly, Err.Description
            Resume exitProc
    End select

End Function

If they click 'Yes', it overwrites it. If they click 'No', I want the SaveAs dialog box to come up so they can select a new filename, but instead I get an error. If they click 'Cancel', I want an error to occur and for the script to stop. The problem is I can't differentiate the errors triggered between 'No' and 'Cancel'.

Any suggestions how to handle this? (Please excuse any poor use of error handling - it's been a while.)

P.S. This function is called by another procedure so if the user clicks 'Cancel' at either the SaveAs dialog box or the ResolveConflict dialog, I would like the calling procedure to stop as well. I figure I can do this by checking what SaveCurrentWorkbook returns (either a Workbook object or False).


Solution

  • You can simply create your own "overwrite?"-question like this:

    Function SaveCurrentWorkbook(wkbSource As Workbook, strNewFileName As String) As Variant
        If Not bolDebug Then On Error GoTo errHandler
        Dim varSaveName As Variant
    
    SaveAsDialog:
    
        varSaveName = Application.GetSaveAsFilename(InitialFileName:=strNewFileName, FileFilter:="Excel Files (*.xls), *.xls")
        If varSaveName <> False Then
          If Len(Dir(varSaveName)) Then 'checks if the file already exists
            Select Case MsgBox("A file named '" & varSaveName & "' already exists at this location. Do you want to replace it?", vbYesNoCancel + vbInformation)
            Case vbYes
              'want to overwrite
              Application.DisplayAlerts = False
              wkbSource.SaveAs varSaveName, ConflictResolution:=2, Addtomru:=True
              Application.DisplayAlerts = True
              Set SaveCurrentWorkbook = wkbSource
            Case vbNo
              GoTo SaveAsDialog
            Case vbCancel
              SaveCurrentWorkbook = False
              Err.Raise 11111, , "Save Canceled"
            End Select
          Else
            wkbSource.SaveAs varSaveName, ConflictResolution:=True, Addtomru:=True
            Set SaveCurrentWorkbook = wkbSource
          End If
        Else
          SaveCurrentWorkbook = False
          Err.Raise 11111, , "Save Canceled"
        End If
    
    exitProc:
        Exit Function
    
    errHandler:
        Select Case Err.Number
        Case 1004 'Clicked "No" or "Cancel" - can't differentiate
          Resume SaveAsDialog
        Case Else
          MsgBox "File not saved. Stopping script.", vbOKOnly, Err.Description
          Resume exitProc
        End Select
    
    End Function
    

    As you have noticed, there is no difference between "No" and "Cancel" (for the application, because it will not stop the saving itself). Excel simply lies to itself saying: "I can't save here" and pops the same error for both cases... so the only real solution is to create your own msgbox :(