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.
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.
Thank you for bringing that to my attention and even supplying the solution.