How to Delete Folders in VBA Using FSO, RmDir, and Windows API

Deleting folders programmatically is a common task in file management and automation. In this article, we’ll explore several different methods for deleting folders using Visual Basic for Applications (VBA):

  • RmDir
  • FileSystemObject (FSO)
  • Windows APIs

 

RmDir

VBA provides a built-in command called RmDir for removing directories. This method is simple to use and doesn’t require any additional object creation or API declarations.

Basic Usage of RmDir

The basic syntax for RmDir is straightforward:

Sub DeleteFolderWithRmDir()
    RmDir "C:\Path\To\Your\Folder"
End Sub

Such a command will remove the specified directory if it’s empty. If the directory is not empty, a runtime error will occur and the deletion will not be performed.

So to be truly useful, you would need to make a recursive function that would call itself on every file and sub-folder. Below is one possible approach to this:

'---------------------------------------------------------------------------------------
' Procedure : RmDir_DeleteFolder
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Delete a folder and any subfolders using the RmDir statement
'               *** Does not go to the recycle bin ***
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFolder   : Path of the directory to delete
' sErrorMsg : Returned error message, if the function fails
'
' Usage:
' ~~~~~~
' RmDir_DeleteFolder("C:\Temp\Reporting\20190517", sErrorMsg)
'   Returns -> True/False
'              sErrorMsg will contain any messages if the function fails
'
' Revision History:
' Rev       Date(yyyy-mm-dd)        Description
' **************************************************************************************
' 1         2019-03-21
' 2         2025-03-23              Updated header to new format
'                                   Added Early/Late Binding CCD
'---------------------------------------------------------------------------------------
Function RmDir_DeleteFolder(ByVal sFolder As String, _
                            Optional ByRef sErrorMsg As String) As Boolean
    On Error GoTo Error_Handler
    Dim sFile                 As String
    Dim sSubFolder            As String

    If Dir(sFolder, vbDirectory) = vbNullString Then
        sErrorMsg = "Folder not found."
        GoTo Error_Handler_Exit
    End If

    ' Delete the files in the folder 
    '    could also just do Kill sFolder & "\*.*" but this is safer
    sFile = Dir(sFolder & "\*.*")
    Do While sFile <> ""
        Call Kill(sFolder & "\" & sFile)
        sFile = Dir()
    Loop

    ' Delete the subFolders in the folder
    sSubFolder = Dir(sFolder & "\*", vbDirectory)
    Do While sSubFolder <> ""
        If sSubFolder <> "." And sSubFolder <> ".." Then
            Call RmDir_DeleteFolder(sFolder & "\" & sSubFolder)
        End If
        sSubFolder = Dir()
    Loop

    ' Remove the folder itself
    RmDir sFolder
    DoEvents
    ' Validate the deletion occured
    If Dir(sFolder, vbDirectory) <> vbNullString Then
        sErrorMsg = "Could not delete the specified directory."
    Else
        RmDir_DeleteFolder = True
    End If

Error_Handler_Exit:
    On Error Resume Next
    Exit Function

Error_Handler:
    'Debug.Print Err.Number, Err.Description, sFile, sFolder
    If Err.Number = 70 Then
        sErrorMsg = "Permission denied." & _
                    "  Possibly a file is open and locking the folder deletion" & _
                    ", user doesn't have deletion permissions, ..."
    Else
        MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
               "Error Source: RmDir_DeleteFolder" & vbCrLf & _
               "Error Number: " & Err.Number & vbCrLf & _
               "Error Description: " & Err.Description & _
               Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
               , vbOKOnly + vbCritical, "An Error has Occurred!"
    End If
    Resume Error_Handler_Exit
End Function

which in turn can be used by simply doing:

Sub RmDir_DeleteFolder_Test()
    Dim sErrorMsg             As String

    If Not RmDir_DeleteFolder("C:\Temp\Test1", sErrorMsg) Then
        Debug.Print sErrorMsg
    Else
        ' Deletion was successful.
    End If
End Sub

Also, it is important to note that the RmDir Statement bypasses the system Recycle Bin providing no means of recovery should a mistake have taken place.
 

FileSystemObject (FSO)

To delete a specific folder using FSO, you can use the DeleteFolder method, In it’s simplest form, it would look something like:

Sub FSO_DeleteFolder()
    Dim FSO As Object
    Set FSO = CreateObject("Scripting.FileSystemObject")
    FSO.DeleteFolder "C:\Path\To\Your\Folder", True
    Set FSO = Nothing
End Sub

To make it more useful, I’ve transformed it slightly into a reusable function like:

'---------------------------------------------------------------------------------------
' Procedure : FSO_DeleteFolder
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Delete a folder and any subfolders
'               *** Does not go to the recycle bin ***
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Late Binding  -> None required
'             Early Binding -> Microsoft Scripting Runtime
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFolder   : Path of the directory to delete
' sErrorMsg : Returned error message, if the function fails
'
' Usage:
' ~~~~~~
' FSO_DeleteFolder("C:\Temp\Reporting\20190517", sErrorMsg)
'   Returns -> True/False
'              sErrorMsg will contain any messages if the function fails
'
' Revision History:
' Rev       Date(yyyy-mm-dd)        Description
' **************************************************************************************
' 1         2019-03-21
' 2         2025-03-23              Updated header to new format
'                                   Added Early/Late Binding CCD
'---------------------------------------------------------------------------------------
Function FSO_DeleteFolder(ByVal sFolder As String, _
                          Optional ByRef sErrorMsg As String) As Boolean
On Error GoTo Error_Handler
    #Const FSO_EarlyBind = False    'True => Early Binding / False => Late Binding
    #If FSO_EarlyBind = True Then
        Dim oFSO              As Scripting.FileSystemObject

        Set oFSO = New FileSystemObject
    #Else
        Dim oFSO              As Object

        Set oFSO = CreateObject("Scripting.FileSystemObject")
    #End If

    If oFSO.FolderExists(sFolder) Then
        oFSO.DeleteFolder sFolder, True
        DoEvents
        If Not oFSO.FolderExists(sFolder) Then
            FSO_DeleteFolder = True
        Else
            sErrorMsg = "Could not delete the specified directory."
        End If
    Else
        sErrorMsg = "Folder not found."
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set oFSO = Nothing
    Exit Function

Error_Handler:
    If Err.Number = 70 Then
        sErrorMsg = "Permission denied." & _
                    "Possibly a file is open and locking the folder deletion" & _
                    ", user doesn't have deletion permissions, ..."
    Else
        MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
               "Error Source: FSO_DeleteFolder" & vbCrLf & _
               "Error Number: " & Err.Number & vbCrLf & _
               "Error Description: " & Err.Description & _
               Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
               , vbOKOnly + vbCritical, "An Error has Occurred!"
    End If
    Resume Error_Handler_Exit
End Function

which in turn can be used by simply doing:

Sub FSO_DeleteFolder_Test()
    Dim sErrorMsg As String
    
    If Not FSO_DeleteFolder("C:\Path\To\Your\Folder", sErrorMsg) Then
        Debug.Print sErrorMsg
    Else
        ' Deletion was successful.
    End If
End Sub

Similarily to the RmDir Statement, the one thing that can sometime be a drawback using the FSO approach is that the contents of the deletion bypass the system Recycle Bin providing no means of recovery should a mistake have taken place.
 

Windows APIs

Another powerful technique for folder deletion is to employ Windows APIs, in this case the SHFileOperation API.

Yes, it is a little more complex, but it also offer more power and options. Two major points stand out as a justification for it’s usage:

  • It deletes non-empty folders. No need for recursive routines.
  • It offers the capability of sending the deleted contents to the system Recycle Bin.
  • It offers the capability of displaying a progress dialog to to the user (not shown in this demo).

Here is a sample of how it can be implemented:

#If VBA7 Then
    Private Declare PtrSafe Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationW" (lpFileOp As SHFILEOPSTRUCT) As Long

    Private Type SHFILEOPSTRUCT
        hWnd                      As LongPtr
        wFunc                     As Long
        pFrom                     As LongPtr
        pTo                       As LongPtr
        fFlags                    As Integer
        fAnyOperationsAborted     As Boolean
        hNameMappings             As LongPtr
        lpszProgressTitle         As LongPtr
    End Type
#Else
    Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationW" (lpFileOp As SHFILEOPSTRUCT) As Long

    Private Type SHFILEOPSTRUCT
        hWnd                      As Long
        wFunc                     As Long
        pFrom                     As Long
        pTo                       As Long
        fFlags                    As Integer
        fAnyOperationsAborted     As Boolean
        hNameMappings             As Long
        lpszProgressTitle         As Long
    End Type
#End If

' Constants for SHFileOperation
Private Const FO_DELETE       As Long = &H3          ' Delete operation
Private Const FOF_NOCONFIRMATION As Integer = &H10    ' No confirmation dialog
Private Const FOF_SILENT      As Integer = &H4      ' No progress dialog
Private Const FOF_ALLOWUNDO   As Integer = &H40    ' Allow undo (send to Recycle Bin)

' Returned Result Values (there are more!)
' https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-?redirectedfrom=MSDN
Private Const ERROR_FILE_NOT_FOUND As Long = 2        ' File not found
Private Const ERROR_PATH_NOT_FOUND As Long = 3        ' Path not found
Private Const ERROR_ACCESS_DENIED As Long = 5         ' Access denied
Private Const ERROR_SHARING_VIOLATION As Long = 32
Private Const ERROR_CANCELLED_BY_USER As Long = 1223  ' Operation canceled by the user


'---------------------------------------------------------------------------------------
' Procedure : API_DeleteFolder
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Delete a folder and any subfolders
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Late Binding  -> none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFolder   : Path of the directory to delete
' bSendToRecycleBin : Whether or not the deleted folder/contents should be placed in the
'                       system Recycle Bin or simply permanently deleted
' sErrorMsg : Returned error message, if the function fails
'
' Usage:
' ~~~~~~
' Delete a folder and send it to the Recycle Bin
' API_DeleteFolder("C:\Temp\Reporting\20190517", , sErrorMsg)
'   Returns -> True/False
'              sErrorMsg will contain any messages if the function fails
'
' Delete a folder permanently and do NOT send it to the Recycle Bin
' API_DeleteFolder("C:\Temp\Reporting\20190517", False, sErrorMsg)
'   Returns -> True/False
'              sErrorMsg will contain any messages if the function fails
'
' Revision History:
' Rev       Date(yyyy-mm-dd)        Description
' **************************************************************************************
' 1         2019-03-21
' 2         2025-03-23              Updated header to new format
'                                   Added Early/Late Binding CCD
' 3         2025-03-26              Change to support Unicode per John Mallinson's
'                                     comments.
'---------------------------------------------------------------------------------------
Public Function API_DeleteFolder(ByVal sFolder As String, _
                                 Optional bSendToRecycleBin As Boolean = True, _
                                 Optional ByRef sErrorMsg As String) As Boolean
    Dim shFileOp              As SHFILEOPSTRUCT
    Dim lRetVal               As Long

    ' Ensure the folder path ends with a null character (required by SHFileOperation)
    sFolder = sFolder & vbNullChar & vbNullChar

    With shFileOp
        .hWnd = 0                              ' Handle to the window (0 for no UI)
        .wFunc = FO_DELETE                     ' Specify delete operation
        .pFrom = StrPtr(sFolder)               ' Path of the folder to delete
        .pTo = 0                               ' Not used for deletion
        If bSendToRecycleBin Then
            'Send to Recycle Bin
            .fFlags = FOF_NOCONFIRMATION Or FOF_SILENT Or FOF_ALLOWUNDO
        Else
            'Do Not Send to Recycle Bin! ****
            .fFlags = FOF_NOCONFIRMATION Or FOF_SILENT
        End If
        .fAnyOperationsAborted = False         ' Tracks if the operation was aborted
        .hNameMappings = 0
        .lpszProgressTitle = 0
    End With
    lRetVal = SHFileOperation(shFileOp)

    If lRetVal <> 0 Then
        Select Case lRetVal
            Case ERROR_FILE_NOT_FOUND
                sErrorMsg = "The system cannot find the file specified."
            Case ERROR_PATH_NOT_FOUND
                sErrorMsg = "The system cannot find the path specified."
            Case ERROR_ACCESS_DENIED
                sErrorMsg = "Access denied."
            Case ERROR_SHARING_VIOLATION
                sErrorMsg = "The process cannot access the file because it is being used by another process."
            Case ERROR_CANCELLED_BY_USER
                sErrorMsg = "Operation canceled by the user."
            Case Else
                sErrorMsg = "An unknown error occurred. Error code: " & lRetVal
        End Select
    Else
        API_DeleteFolder = True
    End If
End Function

and then you simply call it by doing:

Sub API_DeleteFolder_Test()
    Dim sErrorMsg             As String

    If Not API_DeleteFolder("C:\Path\To\Your\Folder", , sErrorMsg) Then
        Debug.Print sErrorMsg
    Else
        ' Deletion was successful.
    End If
End Sub

Also note that the error message case statement is only a partially built listing of the common errors, but could be built out further while referring to the URL provided in the code (https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes–0-499-).
 

Some Final Words

VBA offers a multitude of methods for deleting folders, each with its own strengths/weaknesses and use cases. The File System Object (FSO) provides a robust and feature-rich approach, Windows APIs offer low-level control and advanced functionality, and the built-in RmDir Statement provides a simple, native VBA solution for basic folder deletion tasks.

When choosing between these methods, consider factors such as the complexity of your task, the need for error handling and user feedback, and the specific environment in which your code will run. For simple tasks, RmDir might be sufficient, while more complex scenarios may benefit from the power of FSO or Windows APIs.

As always, exercise caution when deleting folders programmatically, and ensure you have proper error handling and safeguards in place to prevent unintended data loss.

2 responses on “How to Delete Folders in VBA Using FSO, RmDir, and Windows API

  1. John Mallinson

    Hi Daniel, great post … but it got me thinking about Ansi and Unicode as the Windows API function you are using is the Ansi version ie “SHFileOperationA” not the Unicode version “SHFileOperationW”. I tested your code with some files and folders with Unicode characters in their names and paths and found that:

    * If only the file or folder name has Unicode characters then it will be successfully deleted, but API_DeleteFolder() will continue to return True even when the file or folder has already been deleted (ie when the file or folder is missing)
    * If the path before the file or folder name (eg the parent folder) includes Unicode characters then error code 124 is returned (which per the API docs for SHFileOperationW means “The path in the source or destination or both was invalid”)

    So I thought to update this to handle Unicode characters. To do this requires the following two changes:

    1. The API declarations change to the following (now uses “SHFileOperationW” and String types changes to LongPtr / Long)

    #If VBA7 Then
    Private Declare PtrSafe Function SHFileOperation Lib “shell32.dll” Alias “SHFileOperationW” (lpFileOp As SHFILEOPSTRUCT) As Long

    Private Type SHFILEOPSTRUCT
    hWnd As LongPtr
    wFunc As Long
    pFrom As LongPtr
    pTo As LongPtr
    fFlags As Integer
    fAnyOperationsAborted As Boolean
    hNameMappings As LongPtr
    lpszProgressTitle As LongPtr
    End Type
    #Else
    Private Declare Function SHFileOperation Lib “shell32.dll” Alias “SHFileOperationW” (lpFileOp As SHFILEOPSTRUCT) As Long

    Private Type SHFILEOPSTRUCT
    hWnd As Long
    wFunc As Long
    pFrom As Long
    pTo As Long
    fFlags As Integer
    fAnyOperationsAborted As Boolean
    hNameMappings As Long
    lpszProgressTitle As Long
    End Type
    #End If

    2. Within API_DeleteFolder(), we now need to pass pointers to the Strings, not the Strings themselves (to prevent the Strings from being converted from Unicode to Ansi while being passed to the Windows API function):

    Change each of

    .pFrom = sFolder
    .pTo = vbNullString
    .lpszProgressTitle = vbNullString

    To

    .pFrom = StrPtr(sFolder)
    .pTo = 0
    .lpszProgressTitle = 0

    That’s it. My testing shows that the updated API_DeleteFolder() will now happily delete (and send to the Recycle Bin) folders (and files) with Unicode characters anywhere in the name / path and will return False if the folder (or file) is missing.