Senden Sie eine Datei in den Papierkorb

83

Derzeit verwende ich die folgende Funktion

file.Delete();

Aber wie kann ich diese Funktion verwenden, um eine Datei in den Papierkorb zu senden, anstatt sie sofort zu löschen?

muttley91
quelle
3
@ UweKeims Link ist jetzt tot. Eine Version des MSDN-Magazins (Dezember 2007) im .chm-Format finden Sie hier . Der Artikel heißt .NET Matters: IFileOperation in Windows Vistaund befindet sich im ColumnsOrdner.
jrh
Der Artikel wird für mich nicht in der .chm-Datei geöffnet. Dieser Link funktioniert: docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/…
RandomEngy
Außerdem müssen Sie FOFX_RECYCLEONDELETE = 0x00080000die Operationsflags hinzufügen , und dieses Flag wird nur unter Windows 8 oder höher unterstützt.
RandomEngy

Antworten:

52

HINWEIS: Dies funktioniert auch nicht mit interaktiven Nicht-UI-Apps wie Windows Services

Dieser Wrapper bietet Ihnen die erforderlichen Funktionen:

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);
        }
    }
Eugene Cheverda
quelle
Ich verstehe nicht, wie man das benutzt ... kannst du es erklären?
muttley91
4
Entfernen Sie Pack = 1, wenn Sie für eine 64-Bit-Plattform kompilieren (andernfalls schlägt dies fehl). Ohne Angabe von Pack = 1 funktioniert dies sowohl für 32-Bit als auch für 64-Bit. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Sean
1
Bei Verwendung von Pack = 1 wurde eine AccessViolationException ausgelöst. Das Entfernen hat den Trick getan. 64-Bit-Windows übrigens
P1nGu1n
1
Was sind die Voraussetzungen, um diesen Code überhaupt auszuführen? Ich entferne Pack = 1, aber es wird immer noch nicht kompiliert. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute existieren nicht als Namespace. Jede Hilfe bitte danke :)
puretppc
1
SHFileOperation verarbeitet keine langen Pfade und schlägt mit Pfaden fehl, die länger als MAX_PATH sind (auch mit einem Präfix \\? \).
Melvyn
153

Verwenden Sie FileSystem.DeleteFile und geben Sie die richtige RecycleOption an .

Dies funktioniert zwar mit interaktiven UI-Apps, jedoch nicht mit interaktiven Apps ohne UI wie einer Windows-Dienst-App.

NG.
quelle
16
@noldorin Dies ist eine vollkommen gute Lösung, die keine Ablehnung verdient. Ich möchte einen Hinweis darauf, warum der Zugriff auf die VisualBasic-Bibliothek "hässlich" ist.
Schmied
7
@noldorin: Vor allem in diesem Fall Microsoft.VisualBasic.FileIO.FileSystemist im Grunde das gleiche wie in dem hier geposteten Beispiel mit SHFileOperation.
Dirk Vollmar
18
@Noldorin: Hässlich, was? Für mich ist der WinAPI-Weg viel hässlicher - außerdem sollten Sie besser versuchen, etwas durcheinander zu bringen. Ich persönlich mag die VB- Syntax nicht, aber in Assemblys macht es ILmir nichts aus. Die VB-Assembly ruft übrigens dieselbe WinAPI-Funktion auf.
Jaroslav Jandek
7
@Noldorin: Veraltet? Haben Sie die Versammlung Microsoft.VisualBasic.Compatibilityzufällig verwechselt ? Das würde ich vermeiden. Es scheint nicht so, als würde es bald veraltet sein (es wird in der RDL-Berichts-Engine usw. verwendet).
Jaroslav Jandek
6
@Noldorin: Die Verwendung einer integrierten Framework-Assembly scheint eine bessere Lösung zu sein, als eine Hard-Style-Zuordnung zu shell32.dll vorzunehmen. Wenn Sie Framework-Assemblys verwenden, erhalten Sie die Änderung portabel und erhalten spätere Entwicklungen.
Wenn Sie Systembibliotheken zuordnen
41

Von MSDN :

Fügen Sie einen Verweis auf die Microsoft.VisualBasic-Assembly hinzu. Die benötigte Klasse befindet sich in dieser Bibliothek.

Fügen Sie diese using-Anweisung oben in die Datei ein using Microsoft.VisualBasic.FileIO.

Verwenden Sie FileSystem.DeleteFileeine Datei zu löschen, hat es die Option Papierkorb zu spezifizieren oder nicht.

Verwenden Sie FileSystem.DeleteDirectorydiese Option, um ein Verzeichnis mit der Option zu löschen, dass es an den Papierkorb gesendet werden soll oder nicht.

JLWarlow
quelle
Das Problem beim Einschließen von Microsoct.VisualBasic besteht darin, dass es im Widerspruch zu meiner Verwendung von SearchOption an anderer Stelle in meinem Programm steht (Teil der Funktion GetFiles ()).
muttley91
8
@rar Downvote ist immer noch nicht verdient, da in der Frage "VisualBasic-Bibliothek kann aufgrund von Konflikten nicht referenziert werden kann" nicht angegeben wurde. Was Sie leicht in Ihrem Code auflösen könnten. stackoverflow.com/questions/1317263/…
jsmith
1
Diese Methode scheint intern SHFileOperation zu verwenden, das keine langen Pfade verarbeitet und bei Pfaden fehlschlägt, die länger als MAX_PATH sind (auch mit einem Präfix \\? \).
Melvyn
18

Die folgende Lösung ist einfacher als die anderen:

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

Mit dieser Bibliothek können Sie andere Funktionen des Papierkorbs verwenden.

Vergessen Sie zunächst nicht, die Bibliothek "Microsoft Shell Controls And Automation" (aus dem COM-Menü) hinzuzufügen, um den Shell32Namespace verwenden zu können. Es wird dynamisch mit Ihrem Projekt verknüpft, anstatt zusammen mit Ihrem Programm kompiliert zu werden.

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

sɐunıɔ ןɐ qɐp
quelle
8
Ihre Antwort wäre besser, wenn Sie sich auf Ihre Lösung konzentrieren, anstatt andere Antworten im ersten Absatz zu kommentieren. Auch aus Gründen der Klarheit würde ich ersetzen 10durch Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Es kann erwähnenswert sein, den zweiten Parameter in MoveHereBezug auf Optionen wie 64 zu erwähnen ("Informationen rückgängig machen, wenn möglich"). Das Verknüpfen einiger Dokumentationsquellen von MSDN wäre ein guter Abschluss.
grek40
2
Es sieht so aus, als würde beim Aufruf von MoveHere kein Fehler auftreten: Das Aufrufen einer nicht vorhandenen Datei schlägt unbemerkt fehl! Es schlägt auch stillschweigend auf Pfaden fehl, die länger als MAX_CHARS sind, mit oder ohne Präfix "\\? \" ...
Melvyn
13

Leider müssen Sie auf die Win32-API zurückgreifen, um eine Datei aus dem Papierkorb zu entfernen. Versuchen Sie den folgenden Code, der auf diesem Beitrag basiert . Es nutzt die generische SHFileOperationFunktion für Dateisystemoperationen über die Windows-Shell.

Definieren Sie Folgendes (in einer Utilities-Klasse ist dies wahrscheinlich am besten).

[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

Und um damit eine Datei zu löschen und sie in den Papierkorb zu senden, möchten Sie Folgendes:

var shf = new SHFILEOPSTRUCT();
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
shf.pFrom = @"C:\test.txt";
SHFileOperation(ref shf);
Noldorin
quelle
1
und double null beenden die Zeichenfolge.
Sean E
1
SHFileOperation verarbeitet keine langen Pfade und schlägt mit Pfaden fehl, die länger als MAX_PATH sind (auch mit einem Präfix \\? \).
Melvyn
Beachten Sie, dass diese Zeile shf.pFrom = @"C:\test.txt";falsch ist - pFrom muss doppelt nullterminiert sein. Sie sollten \0in der Datei hinzufügen shf.pFrom = "C:\\text.txt\0";. Siehe docs.microsoft.com/en-us/windows/desktop/api/shellapi/…
lindexi
1

Sie können DllImport SHFileOperation, um dies zu tun.

Brian R. Bondy
quelle
1
SHFileOperation verarbeitet keine langen Pfade und schlägt mit Pfaden fehl, die länger als MAX_PATH sind (auch mit einem Präfix \\? \).
Melvyn
0

Hierfür gibt es eine eingebaute Bibliothek .

Fügen Sie zuerst die Referenz Microsoft.VisualBasic hinzu. Fügen Sie dann diesen Code hinzu:

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

Ich habe das hier gefunden .

Maifee Ul Asad
quelle
0

Ich verwende diese Erweiterungsmethode, dann kann ich einfach eine DirectoryInfo oder FileInfo verwenden und diese löschen.

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

Ein Beispiel, wie man es nennt, könnte sein:

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 Vehoeven
quelle