Envoyer un fichier dans la corbeille


83

J'utilise actuellement la fonction suivante

file.Delete();

Mais comment puis-je utiliser cette fonction pour envoyer un fichier dans la corbeille au lieu de simplement le supprimer purement et simplement?



3
Le lien de @ UweKeim est maintenant mort, vous pouvez trouver une version au format .chm de MSDN Magazine (décembre 2007) ici , l'article est appelé .NET Matters: IFileOperation in Windows Vistaet il se trouve dans le Columnsdossier.
jrh

L'article ne s'ouvre pas dans le fichier .chm pour moi. Ce lien fonctionne: docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/…
RandomEngy

Vous devez également ajouter FOFX_RECYCLEONDELETE = 0x00080000aux indicateurs d'opération, et cet indicateur n'est pris en charge que sur Windows 8 ou supérieur.
RandomEngy

Réponses:


52

REMARQUE: cela ne fonctionne pas non plus avec les applications interactives non-UI comme les services Windows

Ce wrapper peut vous fournir les fonctionnalités nécessaires:

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);
        }
    }

Je ne comprends pas comment utiliser ça ... pouvez-vous expliquer?
muttley91

4
Remove Pack = 1 en cas de compilation pour une plate-forme 64 bits (sinon, cela échouera). Sans Pack = 1 spécifié, cela fonctionnera à la fois pour 32 bits et 64 bits. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Sean

1
Lors de l'utilisation de Pack = 1, une AccessViolationException a été levée. Le retirer a fait l'affaire. Windows 64 bits au fait
P1nGu1n

1
Quelles sont les exigences pour même exécuter ce code? Je supprime Pack = 1 mais il ne compile toujours pas. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute n'existent pas en tant qu'espace de noms. Toute aide s'il vous plaît merci :)
puretppc

1
SHFileOperation ne gère pas les chemins longs et échouera avec des chemins plus longs que MAX_PATH (même avec un préfixe \\? \).
Melvyn

155

Utilisez FileSystem.DeleteFile et spécifiez le bon RecycleOption .

Bien que cela fonctionne avec les applications interactives de l'interface utilisateur, cela ne fonctionnera pas avec les applications interactives non-UI comme une application de service Windows.


17
@noldorin C'est une solution parfaitement bien, ne mérite pas un vote défavorable. Je voudrais une référence sur pourquoi accéder à la bibliothèque VisualBasic est "moche".
jsmith

7
@noldorin: Surtout dans ce cas Microsoft.VisualBasic.FileIO.FileSystemfait fondamentalement la même chose que l'exemple posté ici en utilisant SHFileOperation.
Dirk Vollmar

18
@Noldorin: Moche, hein? Pour moi, la méthode WinAPI est bien plus moche - aussi, vous feriez mieux de gâcher quelque chose. Personnellement, je n'aime pas la syntaxe VB, mais dans les assemblages, cela ne ILme dérange pas. L'assembly VB appelle la même fonction WinAPI btw.
Jaroslav Jandek

7
@Noldorin: Obsolète? Avez-vous pris l'assemblée pour un Microsoft.VisualBasic.Compatibilityhasard? Ce que je voudrais éviter. Cela ne semble pas être obsolète de sitôt (il est utilisé dans le moteur de rapport RDL, etc.).
Jaroslav Jandek

6
@Noldorin: l'utilisation d'un assemblage de framework intégré semble être une meilleure solution que le mappage de style dur vers shell32.dll. En utilisant des assemblys de framework, vous obtenez le changement portable et des évolutions ultérieures. Mappage vers les bibliothèques système, vous prenez toutes les chances d'être obsolètes à tout moment ...
fredlegrain

41

Depuis MSDN :

Ajoutez une référence à l'assembly Microsoft.VisualBasic. La classe nécessaire se trouve dans cette bibliothèque.

Ajoutez cette instruction using en haut du fichier using Microsoft.VisualBasic.FileIO;

Utilisé FileSystem.DeleteFilepour supprimer un fichier, il a la possibilité de spécifier ou non la corbeille.

Permet FileSystem.DeleteDirectoryde supprimer un répertoire avec l'option de spécifier de l'envoyer ou non à la corbeille.


Le problème avec l'inclusion de Microsoct.VisualBasic est qu'il entre en conflit avec mon utilisation de SearchOption ailleurs dans mon programme (partie de la fonction GetFiles ()).
muttley91

8
@rar Downvote n'est toujours pas mérité car il n'a pas été spécifié dans la question que «la bibliothèque VisualBasic ne peut pas être référencée en raison d'un conflit». Ce que vous pourriez facilement résoudre dans votre code. stackoverflow.com/questions/1317263/…
jsmith

1
Cette méthode semble utiliser en interne SHFileOperation, qui ne gère pas les chemins longs et échouera avec des chemins plus longs que MAX_PATH (même avec un préfixe \\? \).
Melvyn

17

La solution suivante est plus simple que les autres:

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")
    }
}

Vous pouvez utiliser d'autres fonctionnalités de la corbeille en utilisant cette bibliothèque.

N'oubliez pas tout d'abord d'ajouter la bibliothèque "Microsoft Shell Controls And Automation" (à partir du menu COM), pour pouvoir utiliser l' Shell32espace de noms. Il sera lié dynamiquement à votre projet, au lieu d'être compilé avec votre programme.

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


8
Votre réponse serait meilleure lorsque vous vous concentrez sur votre solution au lieu de commenter d'autres réponses dans le premier paragraphe. Aussi, par souci de clarté, je remplacerais 10par Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Il pourrait être utile de mentionner le deuxième paramètre à MoveHere, concernant des options comme 64 ("Conserver les informations d'annulation, si possible"). Lier certaines sources de documentation de MSDN serait une belle finition.
grek40

2
Il semble que l'appel à MoveHere ne fasse apparaître aucune erreur: l'appel sur un fichier inexistant échoue silencieusement! Il échoue également silencieusement sur les chemins plus longs que MAX_CHARS, avec ou sans un préfixe "\\? \" ...
Melvyn

13

Malheureusement, vous devez recourir à l'API Win32 pour supprimer un fichier dans la corbeille. Essayez le code suivant, basé sur ce post . Il utilise la SHFileOperationfonction générique pour les opérations du système de fichiers via Windows Shell.

Définissez ce qui suit (dans une classe d'utilitaires est probablement le meilleur).

[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

Et pour l'utiliser pour supprimer un fichier, l'envoyer dans la corbeille, vous voulez quelque chose comme:

var shf = new SHFILEOPSTRUCT();
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
shf.pFrom = @"C:\test.txt";
SHFileOperation(ref shf);

1
et le double nul termine la chaîne.
sean e

1
SHFileOperation ne gère pas les chemins longs et échouera avec des chemins plus longs que MAX_PATH (même avec un préfixe \\? \).
Melvyn

Notez que cette ligne shf.pFrom = @"C:\test.txt";est erronée - pFrom doit être terminé par un double nul. Vous devez ajouter \0dans le fichier shf.pFrom = "C:\\text.txt\0";. Voir docs.microsoft.com/en-us/windows/desktop/api/shellapi/…
lindexi

1

Vous pouvez DllImport SHFileOperationpour ce faire.


1
SHFileOperation ne gère pas les chemins longs et échouera avec des chemins plus longs que MAX_PATH (même avec un préfixe \\? \).
Melvyn

1

J'utilise cette méthode d'extension, alors je peux simplement utiliser un DirectoryInfo ou FileInfo et le supprimer.

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);
    }
}

un exemple comment l'appeler pourrait être ceci:

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();

}

-1

Il existe une bibliothèque intégrée pour cela.

Ajoutez d'abord la référence Microsoft.VisualBasic Ensuite, ajoutez ce code:

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

J'ai trouvé ceci ici .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.