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.