Надішліть файл у кошик


83

В даний час я використовую наступну функцію

file.Delete();

Але як я можу використовувати цю функцію, щоб відправити файл у кошик, а не просто видалити його прямо?



3
Посилання @ UweKeim вже мертве, тут ви можете знайти версію журналу MSDN (грудень 2007 р.) У форматі .chm , статтю викликано .NET Matters: IFileOperation in Windows Vistaта знайдено в Columnsпапці.
jrh

Стаття не відкривається у файлі .chm для мене. Це посилання працює: docs.microsoft.com/en-us/archive/msdn-magazine/2007/december/…
RandomEngy

Також вам потрібно додати FOFX_RECYCLEONDELETE = 0x00080000до операційних прапорів, і цей прапор підтримується лише в Windows 8 або вище.
RandomEngy

Відповіді:


52

ПРИМІТКА. Це також не працює з іншими інтерактивними програмами, такими як служби Windows

Ця обгортка може надати вам необхідну функціональність:

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

Я не розумію, як цим користуватися ... Ви могли б пояснити?
muttley91

4
Remove Pack = 1, якщо компілюєте для 64-бітної платформи (інакше це не вдасться). Без зазначеного пакета = 1 це буде працювати як для 32, так і для 64 бітів. pinvoke.net/default.aspx/Structures/SHFILEOPSTRUCT.html
Шон

1
При використанні Pack = 1 було викинуто AccessViolationException. Видалення його зробило свою справу. 64-розрядна Windows до речі
P1nGu1n

1
Які вимоги навіть до запуску цього коду? Я видаляю Pack = 1, але він все ще не компілюється. DllImport, DllImportAttribute, MarshalAs, MarshalAsAttribute, StructLayout, StructLayoutAttribute не існують як простір імен. Будь-яка допомога, будь ласка, дякую :)
puretppc

1
SHFileOperation не обробляє довгі шляхи і не вдасться із шляхами довшими за MAX_PATH (навіть із префіксом \\? \).
Мелвін,

155

Використовуйте FileSystem.DeleteFile і вкажіть правильний RecycleOption .

Незважаючи на те, що це буде працювати з UI Interactive Apps, воно не буде працювати з інтерактивними програмами, не пов'язаними з UI, такими як програма Windows Service.


17
@noldorin Це абсолютно прекрасне рішення, яке не заслуговує на голосування. Я хотів би отримати посилання на те, чому доступ до бібліотеки VisualBasic "потворний".
jsmith

7
@noldorin: Особливо в цьому випадку Microsoft.VisualBasic.FileIO.FileSystemце в основному те саме, що в прикладі, розміщеному тут за допомогою SHFileOperation.
Dirk Vollmar

18
@Noldorin: Некрасиво, так? Для мене спосіб WinAPI набагато потворніший - крім того, вам краще розібратися в чомусь зіпсувати. Мені особисто не подобається синтаксис VB, але в збірках це просто ILтак, щоб я не заперечував. Збірка VB викликає ту саму функцію WinAPI, до речі.
Ярослав Яндекс

7
@Noldorin: Застаріла? Ви Microsoft.VisualBasic.Compatibilityвипадково помилково прийняли збори ? Цього я б уникнув. Не здається, що найближчим часом він буде застарілим (він використовується в механізмі звітності RDL тощо).
Ярослав Яндек

6
@Noldorin: Використання вбудованої фреймворкової збірки виглядає кращим рішенням, ніж перехід на жорстке зіставлення в shell32.dll. Використовуючи фреймворкові збірки, ви отримуєте переносні зміни та отримуєте подальші еволюції. Зіставившись на системні бібліотеки, ви
ризикуєте

41

З MSDN :

Додайте посилання на збірку Microsoft.VisualBasic. У цій бібліотеці знаходиться необхідний клас.

Додайте це за допомогою оператора у верхню частину файлу using Microsoft.VisualBasic.FileIO;

Використовуйте FileSystem.DeleteFileдля видалення файлу, він має можливість вказати кошик для сміття чи ні.

Використовуйте FileSystem.DeleteDirectoryдля видалення каталогу з можливістю вказати, надсилати його до кошика чи ні.


Проблема включення Microsoct.VisualBasic полягає в тому, що це суперечить моєму використанню SearchOption в іншому місці моєї програми (частина функції GetFiles ()).
muttley91

8
@rar Downvote досі не заслуговує, оскільки в питанні не було зазначено, що "на бібліотеку VisualBasic не можна посилатися через конфлікт". Що ви могли б легко вирішити у своєму коді. stackoverflow.com/questions/1317263/…
jsmith

1
Цей метод, як видається, внутрішньо використовує SHFileOperation, який не обробляє довгі шляхи і не вдасться із шляхами довшими за MAX_PATH (навіть із префіксом \\? \).
Мелвін

17

Наступне рішення простіше, ніж інші:

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

За допомогою цієї бібліотеки ви можете використовувати інші функції кошика.

По-перше, не забудьте додати бібліотеку "Управління та автоматизація оболонки Microsoft" (із меню COM), щоб мати можливість використовувати Shell32простір імен. Він буде динамічно пов’язаний з вашим проектом, а не компілюватися разом із вашою програмою.

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


8
Ваша відповідь буде кращою, якщо ви зосередитесь на своєму рішенні, а не коментуєте інші відповіді в першому абзаці. Крім того, для ясності я б замінив 10на Shell32.ShellSpecialFolderConstants.ssfBITBUCKET. Можливо, варто згадати другий параметр MoveHere, щодо таких опцій, як 64 ("Зберегти інформацію про скасування, якщо це можливо"). Пов’язання деяких джерел документації з MSDN було б гарним завершенням.
grek40

2
Схоже, виклик MoveHere не виявляє жодної помилки: його виклик у неіснуючому файлі не вдається мовчки! Він також мовчки не справляється на шляхах довшими за MAX_CHARS, з префіксом "\\? \" Або без нього ...
Мелвін,

13

На жаль, вам потрібно вдатися до Win32 API, щоб видалити файл до кошика. Спробуйте наступний код, виходячи з цього повідомлення . Він використовує загальну SHFileOperationфункцію для операцій з файловою системою через оболонку Windows.

Визначте наступне (у класі службових програм, мабуть, найкраще).

[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

А щоб використовувати його для видалення файлу, надіславши його в кошик, потрібно щось на зразок:

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

1
і double null закінчує рядок.
sean e

1
SHFileOperation не обробляє довгі шляхи і не вдасться із шляхами довшими за MAX_PATH (навіть із префіксом \\? \).
Мелвін,

Зверніть увагу, що цей рядок shf.pFrom = @"C:\test.txt";помилковий - pFrom має бути подвійним нулем. Ви повинні додати \0у файл shf.pFrom = "C:\\text.txt\0";. Див. Docs.microsoft.com/en-us/windows/desktop/api/shellapi/…
lindexi


1

Я використовую цей метод розширення, тоді я можу просто використовувати DirectoryInfo або FileInfo і видалити це.

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

зразок, як це назвати, може бути таким:

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

Є вбудована бібліотека .

Спочатку додайте посилання Microsoft.VisualBasic Потім додайте цей код:

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

Я знайшов це тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.