在 C# 中的 Windows x64 上删除文件到回收站

发布于 2024-08-23 14:56:56 字数 5076 浏览 13 评论 0原文

我的这个类似乎在非 64 位上运行得很好。

using System;
using System.Runtime.InteropServices;

namespace DeleteToRecycleBin
{
/// <summary>
/// Send files directly to the recycle bin.
/// </summary>
public class RecybleBin
{

    /// <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, Pack = 1)]
    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 readonly bool fAnyOperationsAborted;
        public readonly IntPtr hNameMappings;
        public readonly 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
        {
            SHFILEOPSTRUCT fs = new SHFILEOPSTRUCT
                                    {
                                        wFunc = FileOperationType.FO_DELETE,
                                        pFrom = path + '\0' + '\0',
                                        fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
                                    };

            // important to double-terminate the string.
            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 SendSilent(string path)
    {
        return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);

    }
}

什么方法可以修复它,使其在 x64 上也能正常工作吗?我尝试将 ushort 更改为 ulong 以及其他一些修改,但它不起作用。

我知道还有其他解决方案需要引用 Microsoft.VisualBasic 但我更喜欢 p/invoke 方式。

正确答案是:

在 x64 下,必须在没有 Pack = 1 参数的情况下声明 SHFILEOPSTRUCT,否则将会失败。如果您希望代码独立于平台,这将是一个真正的痛苦,因为您必须声明两个独立的结构,一个带有 Pack = 1,另一个没有。然后,您必须声明两个不同的 SHFileOperation 调用,每个结构调用一个。然后,您必须根据您运行的是 32 位还是 64 位来决定调用哪一个。

I've got this class which seems to work quite well on non-64bit.

using System;
using System.Runtime.InteropServices;

namespace DeleteToRecycleBin
{
/// <summary>
/// Send files directly to the recycle bin.
/// </summary>
public class RecybleBin
{

    /// <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, Pack = 1)]
    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 readonly bool fAnyOperationsAborted;
        public readonly IntPtr hNameMappings;
        public readonly 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
        {
            SHFILEOPSTRUCT fs = new SHFILEOPSTRUCT
                                    {
                                        wFunc = FileOperationType.FO_DELETE,
                                        pFrom = path + '\0' + '\0',
                                        fFlags = FileOperationFlags.FOF_ALLOWUNDO | flags
                                    };

            // important to double-terminate the string.
            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 SendSilent(string path)
    {
        return Send(path, FileOperationFlags.FOF_NOCONFIRMATION | FileOperationFlags.FOF_NOERRORUI | FileOperationFlags.FOF_SILENT);

    }
}

}

Any way to fix it so it works good on x64 too? I've tried chaning ushort to ulong and couple of other modifications but it doesn't work.

I know there are other solutions that require reference to Microsoft.VisualBasic but i would prefer p/invoke way.

CORRECT ANSWER IS:

Under x64, the SHFILEOPSTRUCT must be declared without the Pack = 1 parameter, or it will fail. This is a real pain if you want your code to be platform independent, as you have to declare two separate structures, one with Pack = 1, and one without. You then have to declare two different SHFileOperation calls, one for each of the structures. Then you have to decide which one to call depending on whether you are running on 32 or 64 bit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

み格子的夏天 2024-08-30 14:56:56

看起来很奇怪,.NET 已经具有删除到回收站的函数...但它们位于 Microsoft.VisualBasic 命名空间中。具体来说,是Microsoft.VisualBasic.FileIO

using Microsoft.VisualBasic.FileIO;

// class declaration, method start here

// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);

// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.AllDialogs, RecycleOption.SendToRecycleBin);

// Directories are the same, but with DeleteDirectory instead

As strange as it seems, .NET already has functions to delete to the Recycle Bin... but they're in the Microsoft.VisualBasic namespace. Specifically, Microsoft.VisualBasic.FileIO.

using Microsoft.VisualBasic.FileIO;

// class declaration, method start here

// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);

// Send file to recycle bin without dialog
FileSystem.DeleteFile("pathToFile", UIOption.AllDialogs, RecycleOption.SendToRecycleBin);

// Directories are the same, but with DeleteDirectory instead
不顾 2024-08-30 14:56:56

您是否查看过 PInvoke 站点?它对 FILEOPSTRUCT 类型的定义略有不同,一方面强制使用 Unicode。我想知道 charset = auto 是否令人困惑......就像它在 32 位上默认为 ANSI,但在 64 位上默认为 Unicode 并且中间某个地方出了问题。

编辑;
另外,Visual Basic 参考方法是一种简单的方法...我知道人们出于某种原因讨厌它,但相关的 DLL 仍然是核心框架的一部分,因此您不会添加任何新的依赖项。

Have you looked at the PInvoke site? It has a slight different definition for the FILEOPSTRUCT type, forcing Unicode for one thing. I wonder if the charset = auto is confusing things...like it defaults to ANSI on 32 bit, but Unicode on 64 bit and something is going wrong somewhere in the middle.

EDIT;
Also, the Visual Basic reference approach is a simple one...I know people have an aversion to it for some reason, but the relevant DLLs are still part of the core framework, so you won't be adding any new dependencies.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文