DeviceIoControl FSCTL_SET_ZERO_DATA returns ERROR_INVALID_PARAMETER

DeviceIoControl with FSCTL_SET_ZERO_DATA returns ERROR_INVALID_PARAMETER

我正在尝试在 C# 中使用 DeviceIoControl with FSCTL_SET_ZERO_DATA 控制代码。

我创建了文件 C:\tmp\test.txt 并在其中放入了文本 "aaaa"。

我运行代码和我收到的错误号:87
根据 MSDN: "The parameter is incorrect."

我认为问题是因为我发送的输入缓冲区(DeviceIoControl 中的参数编号 3)没有任何数据。

DeviceIoControl returns false.
如何使用 FSCTL_SET_ZERO_DATADeviceIoControl 插入有效参数,这将使它成为 return true

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program2
    {
        [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
 IntPtr lpInBuffer, uint nInBufferSize,
 IntPtr lpOutBuffer, uint nOutBufferSize,
 out uint lpBytesReturned, IntPtr lpOverlapped);

        [Flags]
        public enum EMethod : uint
        {
            Buffered = 0,
            InDirect = 1,
            OutDirect = 2,
            Neither = 3
        }

        [Flags]
        public enum EFileDevice : uint
        {
            FileSystem = 0x00000009
        }

        [Flags]
        public enum EIOControlCode : uint
        {
            FsctlSetZeroData = (EFileDevice.FileSystem << 16) | (50 << 2) | EMethod.Buffered | (FileAccess.Write << 14),
        }

        [StructLayout(LayoutKind.Sequential)]
        struct FILE_ZERO_DATA_INFORMATION
        {
            public FILE_ZERO_DATA_INFORMATION(long offset, long count)
            {
                FileOffset = offset;
                BeyondFinalZero = offset + count;
            }

            public long FileOffset;
            public long BeyondFinalZero;
        }

        [DllImport("kernel32.dll")]
        public static extern uint GetLastError();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CreateFile(
        [MarshalAs(UnmanagedType.LPTStr)] string filename,
        [MarshalAs(UnmanagedType.U4)] FileAccess access,
        [MarshalAs(UnmanagedType.U4)] FileShare share,
        IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        uint flagsAndAttributes,
        IntPtr templateFile);

        static void Main(string[] args)
        {
            IntPtr handle = CreateFile(@"C:\tmp\test.txt", FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, (int)FileAttributes.Normal, IntPtr.Zero);

            long length = 2;
            FILE_ZERO_DATA_INFORMATION data = new FILE_ZERO_DATA_INFORMATION(0, length);
            uint structSize = (uint)Marshal.SizeOf(data);
            IntPtr pBuffer = Marshal.AllocHGlobal((int)structSize);


            uint bytesReturned = 0;
            bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, pBuffer, 5, IntPtr.Zero, 5, out bytesReturned, IntPtr.Zero);

            // bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
            if (succeed)
            {
                Console.WriteLine("Works fine");
            }
            else
            {
                uint err = GetLastError();
                Console.WriteLine("Error number: {0}", err);
            }
        }

    }
}

归功于@Aybe。

修复方法是:

uint pBufferSize = 16; 
Marshal.StructureToPtr(data, pBuffer, false);
bool succeed = DeviceIoControl(handle, (uint)EIOControlCode.FsctlSetZeroData, pBuffer, pBufferSize, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);  
  • 非常重要的补充Marshal.StructureToPtr(data, pBuffer, false);

如果您不添加它,函数有时会 return 为真,有时为假。

Here 是对同样使用 FSCTL 和 C# 的代码的引用。