While Xojo doesn’t currently provide a direct way of recursively deleting a folder, there are various options that will allow you to do this:
1. Recursively iterate through all the folders, deleting each one. You can read about that at our Developer Site, this is the best cross-platform way.
2. Use the Shell to recursively delete a folder (i.e. “del /s” on Windows, or “rm -rf” on OS X and Linux)
Windows specific ways:
3. SHFileOperation (an older API)
4. IFileOperation (the more modern API that Windows recommends over option #3)
I’ve decided to look at option #4, since this allows more customized options, like the ability to show a progress dialog. However, it is also the slightly more complicated option since it deals with COM & Delegates. The example illustrates this:
// Select a folder to delete
Dim f As FolderItem = SelectFolder
// Our one declare that creates our ShellItem
Declare Function SHCreateItemFromParsingName Lib "Shell32" _
(path As WString, pbc As Ptr, riid As Ptr, Byref ppv As Ptr) As Integer
// These IIDs identify the COM object that we're looking for.
// Unfortunately finding the IIDs is not as simple since
// they are typically only exposed by C headers or in the type
// library of the COM component.
// Normally you would use Project->Add ActiveX component to
// add COM objects to your project
Dim CLSID_FileOperation As MemoryBlock = _
COM.IIDFromString("{3ad05575-8857-4850-9277-11b85bdb8e09}")
Dim IID_IFileOperation As MemoryBlock = _
COM.IIDFromString("{947aab5f-0a5c-4c13-b4d6-4bf7836fc9f8}")
Dim IID_IShellItem As MemoryBlock = _
COM.IIDFromString("{43826d1e-e718-42ee-bc55-a1e261c37bfe}")
Dim result As Integer
Dim shellItem As Ptr
result = SHCreateItemFromParsingName(f.NativePath, _
Nil, IID_IShellItem, shellItem)
If result <> COM.S_OK Then Return
// fileOp will be how we communicate with the COM component.
// Basically it will hold a list of function pointers to call
Dim fileOp As Ptr
result = COM.CoCreateInstance(CLSID_FileOperation, _
Nil, COM.CLSCTX_SERVER, IID_IFileOperation, fileOp)
If result <> COM.S_OK Then Return
Dim sizeOfPtr As Integer
#if Target64Bit
sizeOfPtr = 8
#else
sizeOfPtr = 4
#endif
// Do not display any UI/dialog
Const FOF_NO_UI = &h614
// Since fileOp is just a list of function pointers, we need
// to call the correct one. Thankfully this information is
// known (mainly because I have the C headers for them).
// It can also be gathered by looking at the COM component's
// type library. I've setup SetOperationFlags, DeleteItem,
// and PerformOperation as delegates with the correct
// function prototype
// Delegate Function SetOperationFlags(this As Ptr,
// flags As UInt32) As Integer
Dim setOpFlagsFunc As New SetOperationFlags( _
fileOp.Ptr(0).Ptr(5 * sizeOfPtr))
result = setOpFlagsFunc.Invoke(fileOp, FOF_NO_UI)
// Delegate Function DeleteItem(this As Ptr,
// shellItem As Ptr, progressSink As Ptr) As Integer
Dim deleteItemFunc As New DeleteItem(fileOp.Ptr(0).Ptr(18 * sizeOfPtr))
result = deleteItemFunc.Invoke(fileOp, shellItem, Nil)
// Delegate Function PerformOperation(this As Ptr) As Integer
Dim performOpFunc As New PerformOperation(
fileOp.Ptr(0).Ptr(21 * sizeOfPtr))
result = performOpFunc.Invoke(fileOp)
// This is how we cast a Ptr to a COM object to be released
Dim unk As New COM.IUnknown(fileOp)
result = unk.Release
In conclusion, while it’s a lot of work to set this up, it has the added benefit over the other options in that it is more extensible/customizable on the Windows platform. Here’s a link to download this example.

