103

Currently I'm using the following function

file.Delete();

But how can I use this function to send a file to the recycle bin instead of just deleting it outright?

muttley91
  • 12,278
  • 33
  • 106
  • 160
  • 10
    http://msdn.microsoft.com/en-us/library/ms127976.aspx – Jaroslav Jandek Jul 19 '10 at 15:28
  • 3
    @UweKeim's link is now dead, [you can find a .chm format version of MSDN Magazine (December 2007) here](http://download.microsoft.com/download/3/a/7/3a7fa450-1f33-41f7-9e6d-3aa95b5a6aea/MSDNMagazine2007_12en-us.chm) , the article is called `.NET Matters: IFileOperation in Windows Vista` and it's found in the `Columns` folder. – jrh Oct 04 '16 at 18:26
  • The article does not open in the .chm file for me. This link works: https://learn.microsoft.com/en-us/archive/msdn-magazine/2007/december/net-matters-ifileoperation-in-windows-vista – RandomEngy Jul 03 '20 at 14:28
  • Also you need to add `FOFX_RECYCLEONDELETE = 0x00080000` to the operation flags, and that flag is only supported on Windows 8 or above. – RandomEngy Jul 03 '20 at 14:56

8 Answers8

178

Use FileSystem.DeleteFile and specify the right RecycleOption.

While this will work with UI Interactive Apps, it will not work with non UI interactive apps like a Windows Service app.

rboy
  • 2,018
  • 1
  • 23
  • 35
NG.
  • 22,560
  • 5
  • 55
  • 61
  • 2
    Works, but not ideal. Referencing the Microsoft.VisualBasic is often undesirable from within C#. Any association with VB from within C# code strikes me as ugly. (Not my down-vote though.) – Noldorin Jul 19 '10 at 15:29
  • 23
    @noldorin This is a perfectly fine solution, doesn't deserve a downvote. I'd like a reference on why accessing the VisualBasic library is "ugly". – jsmith Jul 19 '10 at 15:33
  • 7
    @noldorin: Especially in this case `Microsoft.VisualBasic.FileIO.FileSystem` does basically the same as the example posted here using `SHFileOperation`. – Dirk Vollmar Jul 19 '10 at 15:46
  • 23
    @Noldorin: Ugly, huh? For me the WinAPI way is way uglier - also, you have better shot at messing something up. I personally dislike VB **syntax** but in assemblies it's just `IL` so I don't mind. The VB assembly calls the same WinAPI function btw. – Jaroslav Jandek Jul 19 '10 at 15:46
  • 1
    I did not down-vote. It's not ugly per se, it just shouldn't be used from within C#. It is pretty much obsolete as far as I'm concerned. – Noldorin Jul 19 '10 at 15:46
  • 7
    @Noldorin: Obsolete? Have you mistaken the assembly for `Microsoft.VisualBasic.Compatibility` by chance? That one I **would** avoid. Doesn't seem like it's going to be deprecated any time soon (it's used in the RDL reporting engine, etc.). – Jaroslav Jandek Jul 19 '10 at 15:54
  • 7
    @Noldorin: Using a built-in framework assembly looks like a better solution than going hard-style mapping to shell32.dll. Using framework assemblies you get the change being portable and getting later evolutions. Mapping to system libraries, you take all chances to be obsolete any day... – fredlegrain Apr 08 '13 at 15:35
  • @fredlegrain: But we know Microsoft.VisualBasic.FileIO just uses shell32 thunks under the hood anyway. ;) – Noldorin Apr 08 '13 at 17:23
  • 7
    @Noldorin: Right, so why should one rewrite something the is already packaged somewhere in the framework? – fredlegrain Apr 12 '13 at 14:39
  • 3
    Because it's tied to the Visual Basic system, of course. It is not even intended to be used from C#, and indeed could disappear at any point in the future while C# proper remains in its entirety. – Noldorin Apr 13 '13 at 20:30
  • 5
    @Noldorin no matter what .NET programming langauge it is you know it's going to the same compiled langauge right? – EaterOfCode May 22 '13 at 11:21
  • 1
    You don't know what DLLs will be available on the system though, in the future. If anything is likely to be removed, it's a DLL like this. Though MS are obsessed with backwards-compatibility, so perhaps none will ever get removed. Yay for bloat? – Noldorin May 22 '13 at 17:03
  • 1
    For me, it works in localhost, but when hosted on windows server 2012 with IIS, didn't work. File deletes, but doesn't go to recycle bin. No Error. Any permission issue? – d-coder Jun 07 '14 at 20:40
  • 1
    @singh does your server even _have_ a recycle bin. I often see the recycle bin being disabled on servers. – DonkeyMaster Sep 24 '14 at 13:13
  • 3
    @DonkeyMaster: Yes, it's enabled; Or how would I check if it's not going in there. – d-coder Sep 25 '14 at 14:37
  • 1
    While this works in User Space apps with a UI interface this **will NOT work** with a non UI interactive app like a windows service (I learnt the hard way). Quoting from MSDN _The showUI and recycle parameters are not supported in applications that are not user interactive, such as Windows Services._ – rboy May 28 '15 at 19:10
  • 1
    This is a much better solution than the accepted answer. I even built a solution using F# that uses this approach and it works great. As long as you tell it to compile as a Windows app instead of console app, it works. – Jacobs Data Solutions Jul 11 '15 at 13:25
  • 2
    This method appears to internally use SHFileOperation, which does not handle long paths and will fail with paths longer than MAX_PATH (even with a \\?\ prefix). – Melvyn Mar 12 '18 at 11:05
  • It doesn't like being off the UI thread in an `Async` call either – CAD bloke Feb 09 '20 at 04:20
  • Another problem with this solution is under some circumstances it will not simply throw the 'FileNotFoundException' ... but instead do what the function's input parameter implies is possible: pop up an error dialog. There is no way to avoid this. It's an improbable event that can only be triggered by the right circumstances... so super fun to find it in the wild in my released app. So fun. – DAG Apr 11 '23 at 14:17
  • As with my previous comment - same issue with SHFileOperation in shell32... if you specify silent and no error dialogs, it will still throw up a dialog that says "Could not find this item" and "Item Not Found" in the title bar. It's improbable, but possible to cause this (I can reliably repro by spawning a bunch of apps, where each creates the same file and sends to Recycle Bin) – DAG Apr 11 '23 at 15:25
73

NOTE: This also does not work with non UI Interactive apps like Windows Services

This wrapper can provide you needed functionality:

using System.Runtime.InteropServices;

public class FileOperationAPIWrapper
    {
        /// <summary>
        /// Possible flags for the SHFileOperation method.
        /// </summary>
        [Flags]
        public enum FileOperationFlags : ushort
        {
            /// <summary>
            /// Do not show a dialog during the process
            /// </summary>
            FOF_SILENT = 0x0004,
            /// <summary>
            /// Do not ask the user to confirm selection
            /// </summary>
            FOF_NOCONFIRMATION = 0x0010,
            /// <summary>
            /// Delete the file to the recycle bin.  (Required flag to send a file to the bin
            /// </summary>
            FOF_ALLOWUNDO = 0x0040,
            /// <summary>
            /// Do not show the names of the files or folders that are being recycled.
            /// </summary>
            FOF_SIMPLEPROGRESS = 0x0100,
            /// <summary>
            /// Surpress errors, if any occur during the process.
            /// </summary>
            FOF_NOERRORUI = 0x0400,
            /// <summary>
            /// Warn if files are too big to fit in the recycle bin and will need
            /// to be deleted completely.
            /// </summary>
            FOF_WANTNUKEWARNING = 0x4000,
        }

        /// <summary>
        /// File Operation Function Type for SHFileOperation
        /// </summary>
        public enum FileOperationType : uint
        {
            /// <summary>
            /// Move the objects
            /// </summary>
            FO_MOVE = 0x0001,
            /// <summary>
            /// Copy the objects
            /// </summary>
            FO_COPY = 0x0002,
            /// <summary>
            /// Delete (or recycle) the objects
            /// </summary>
            FO_DELETE = 0x0003,
            /// <summary>
            /// Rename the object(s)
            /// </summary>
            FO_RENAME = 0x0004,
        }



        /// <summary>
        /// SHFILEOPSTRUCT for SHFileOperation from COM
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct SHFILEOPSTRUCT
        {

            public IntPtr hwnd;
            [MarshalAs(UnmanagedType.U4)]
            public FileOperationType wFunc;
            public string pFrom;
            public string pTo;
            public FileOperationFlags fFlags;
            [MarshalAs(UnmanagedType.Bool)]
            public bool fAnyOperationsAborted;
            public IntPtr hNameMappings;
            public string lpszProgressTitle;
        }

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        private static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

        /// <summary>
        /// Send file to recycle bin
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        /// <param name="flags">FileOperationFlags to add in addition to FOF_ALLOWUNDO</param>
        public static bool Send(string path, FileOperationFlags flags)
        {
            try
            {
                var fs = new SHFILEOPSTRUCT
                                        {
                                            wFunc = FileOperationType.FO_DELETE,
                                            pFrom = path + '\0' + '\0',
                                            fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
                                        };
                SHFileOperation(ref fs);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Send file to recycle bin.  Display dialog, display warning if files are too big to fit (FOF_WANTNUKEWARNING)
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        public static bool Send(string path)
        {
            return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_WANTNUKEWARNING);
        }

        /// <summary>
        /// Send file silently to recycle bin.  Surpress dialog, surpress errors, delete if too large.
        /// </summary>
        /// <param name="path">Location of directory or file to recycle</param>
        public static bool MoveToRecycleBin(string path)
        {
            return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);

        }

        private static bool deleteFile(string path, FileOperationFlags flags)
        {
            try
            {
                var fs = new SHFILEOPSTRUCT
                                        {
                                            wFunc = FileOperationType.FO_DELETE,
                                            pFrom = path + '\0' + '\0',
                                            fFlags = flags
                                        };
                SHFileOperation(ref fs);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static bool DeleteCompletelySilent(string path)
        {
            return deleteFile(path,
                              FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI |
                              FileOperationFlags.FOF_SILENT);
        }
    }
rboy
  • 2,018
  • 1
  • 23
  • 35
Eugene Cheverda
  • 8,760
  • 2
  • 33
  • 18
  • I don't understand how to use this...could you explain? – muttley91 Jul 19 '10 at 16:17
  • You may use it as a static methods to perform necessary operations, usings are as much simple as `File.Delete(string filePath);` – Eugene Cheverda Apr 06 '11 at 12:07
  • 5
    Remove Pack = 1 if compiling for a 64 bit platform (it'll fail otherwise). Without Pack = 1 specified this will work for both 32 bit and 64 bit. http://pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html – Sean May 13 '13 at 01:26
  • This code triple null terminates. You've added one more null terminator than needed. – David Heffernan Nov 13 '13 at 17:43
  • 1
    When using Pack = 1, an AccessViolationException was thrown. Removing it did the trick. 64-bit Windows by the way – P1nGu1n Dec 26 '13 at 23:41
  • 2
    What are the requirements to even run this code? I remove Pack = 1 but it still does not compile. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute do not exist as a namespace. Any help please thanks :) – puretppc Jan 25 '14 at 04:41
  • @puretppc `using System.Runtime.InteropServices;` – Dan Is Fiddling By Firelight Sep 15 '14 at 19:20
  • 1
    NOTE: This does **not work** with non UI Interactive apps like Windows Services, only with UI interactive apps – rboy May 28 '15 at 19:51
  • I think both approaches (FileSystem.DeleteFile and P/Invoke to SHFileOperation) have their reason to exist and depending on what your priority is, one of them is right for you. For me personally, it's by far mor comforting to use a well known system api, instead of another frameworkwrapper that covers basic usage of an OS, for others, interoperability might be more important. Upvoted, because the code is very clear and actually does answers the question. – Xan-Kun Clark-Davis Feb 16 '17 at 14:54
  • Is there a reason why the class is not static? – Xan-Kun Clark-Davis Feb 16 '17 at 15:04
  • 2
    SHFileOperation does not handle long paths and will fail with paths longer than MAX_PATH (even with a \\?\ prefix). – Melvyn Mar 12 '18 at 10:02
  • This solution also works for Folders as well – DenisL Aug 08 '23 at 12:33
45

From MSDN:

Add a reference to Microsoft.VisualBasic assembly. The needed class is found in this library.

Add this using statement to the top of the file using Microsoft.VisualBasic.FileIO;

Use FileSystem.DeleteFile to delete a file, it has the option to specify recycle bin or not.

Use FileSystem.DeleteDirectory to delete a directory with the option to specify to send it to the recycle bin or not.

John Warlow
  • 2,922
  • 1
  • 34
  • 49
  • The problem with including Microsoct.VisualBasic is that it conflicts with my use of SearchOption elsewhere in my program (part of the GetFiles() function). – muttley91 Jul 19 '10 at 15:31
  • 8
    @rar Downvote is still not deserved since it was not specified in the question that "VisualBasic library cannot be referenced due to conflict." Which you could easily resolve in your code. http://stackoverflow.com/questions/1317263/system-io-versus-visualbasic-fileio – jsmith Jul 19 '10 at 15:35
  • 1
    This method appears to internally use SHFileOperation, which does not handle long paths and will fail with paths longer than MAX_PATH (even with a \\?\ prefix). – Melvyn Mar 12 '18 at 11:05
19

The following solution is simpler than the other ones:

using Shell32;

static class Program
{
    public static Shell shell = new Shell();
    public static Folder RecyclingBin = shell.NameSpace(10);

    static void Main()
    {
        RecyclingBin.MoveHere("PATH TO FILE/FOLDER")
    }
}

You can use other functionalities of the recycle bin using this library.

First, don't forget to add the library "Microsoft Shell Controls And Automation" (from the COM menu), to be able to use the Shell32 namespace. It will be dynamically linked to your project, instead of being compiled along with your program.

[1]: https://i.stack.imgur.com/erV

sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40
  • 10
    Your answer would be better when you focus on your solution instead of commenting other answers in the first paragraph. Also, for sake of clarity I'd replace `10` by `Shell32.ShellSpecialFolderConstants.ssfBITBUCKET`. It might be worth mentioning the second parameter to `MoveHere`, regarding options like 64 ("Preserve undo information, if possible"). Linking some documentation sources from MSDN would be a nice finishing. – grek40 May 15 '17 at 10:58
  • 2
    It looks like the call to MoveHere does not surface any error: calling it on a non-existing file fails silently! It also fails silently on paths longer than MAX_CHARS, with or without a "\\?\" prefix... – Melvyn Mar 12 '18 at 14:33
  • It does not work for me. It simply does nothing and the file is not deleted. – Elmue May 21 '21 at 19:39
13

Unfortunately you need to resort to the Win32 API to remove a file to the Recycle Bin. Try the following code, based on this post. It makes use of the generic SHFileOperation function for file system operations via the Windows Shell.

Define the following (in a utilities class is probably best).

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto, Pack=1)]
public struct SHFILEOPSTRUCT
{
        public IntPtr hwnd;
        [MarshalAs(UnmanagedType.U4)] public int wFunc;
        public string pFrom;
        public string pTo;
        public short fFlags;
        [MarshalAs(UnmanagedType.Bool)] public bool fAnyOperationsAborted;
        public IntPtr hNameMappings;
        public string lpszProgressTitle;
}

[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

public const int FO_DELETE = 3;
public const int FOF_ALLOWUNDO = 0x40;
public const int FOF_NOCONFIRMATION = 0x10; // Don't prompt the user

And to use it to delete a file, sending it to the Recycle Bin, you want something like:

var shf = new SHFILEOPSTRUCT();
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
shf.pFrom = @"C:\test.txt";
SHFileOperation(ref shf);
Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 1
    and double null terminate the string. – sean e Apr 14 '13 at 23:41
  • 1
    SHFileOperation does not handle long paths and will fail with paths longer than MAX_PATH (even with a \\?\ prefix). – Melvyn Mar 12 '18 at 10:04
  • Note that this line `shf.pFrom = @"C:\test.txt";` Is wrong - pFrom must be double null terminated. You should add `\0` in the file `shf.pFrom = "C:\\text.txt\0";`. See https://learn.microsoft.com/en-us/windows/desktop/api/shellapi/ns-shellapi-_shfileopstructa – lindexi Mar 22 '19 at 01:33
2

There is built-in library for this .

First add reference Microsoft.VisualBasic Then add this code :

FileSystem.DeleteFile(path_of_the_file,
                        Microsoft.VisualBasic.FileIO.UIOption.AllDialogs,
                        Microsoft.VisualBasic.FileIO.RecycleOption.SendToRecycleBin,
                        Microsoft.VisualBasic.FileIO.UICancelOption.ThrowException);

I have found this here .

Maifee Ul Asad
  • 3,992
  • 6
  • 38
  • 86
1

You can DllImport SHFileOperation to do this.

Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 1
    SHFileOperation does not handle long paths and will fail with paths longer than MAX_PATH (even with a \\?\ prefix). – Melvyn Mar 12 '18 at 10:02
1

I use this extension method, then I can just use a DirectoryInfo or FileInfo and delete that.

public static class NativeMethods
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        struct SHFILEOPSTRUCT
    {
        public IntPtr hwnd;
        [MarshalAs(UnmanagedType.U4)]
        public int wFunc;
        public string pFrom;
        public string pTo;
        public short fFlags;
        [MarshalAs(UnmanagedType.Bool)]
        public bool fAnyOperationsAborted;
        public IntPtr hNameMappings;
        public string lpszProgressTitle;
    }
    private const int FO_DELETE = 0x0003;
    private const int FOF_ALLOWUNDO = 0x0040;           // Preserve undo information, if possible. 
    private const int FOF_NOCONFIRMATION = 0x0010;      // Show no confirmation dialog box to the user      


    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

    static bool DeleteFileOrFolder(string path)
    {


        SHFILEOPSTRUCT fileop = new SHFILEOPSTRUCT();
        fileop.wFunc = FO_DELETE;
        fileop.pFrom = path + '\0' + '\0';            
        fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;


        var rc= SHFileOperation(ref fileop);
        return rc==0;
    }

    public static bool ToRecycleBin(this DirectoryInfo dir)
    {
        dir?.Refresh();
        if(dir is null || !dir.Exists)
        {
            return false;
        }
        else
            return DeleteFileOrFolder(dir.FullName);
    }
    public static bool ToRecycleBin(this FileInfo file)
    {
        file?.Refresh();

        if(file is null ||!file.Exists)
        {
            return false;
        }
        return DeleteFileOrFolder(file.FullName);
    }
}

a sample how to call it could be this:

private void BtnDelete_Click(object sender, EventArgs e)
{
    if(MessageBox.Show("Are you sure you would like to delete this directory?", "Delete & Close", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
        return;

    var dir= new DirectoryInfo(directoryName);
    dir.ToRecycleBin();

}
Walter Verhoeven
  • 3,867
  • 27
  • 36