C#调用WinApi?

Ice*_*Van 1 c# windows winapi interop

我试图DeviceIoControl用代码在C#中调用WinAPI函数IOCTL_DISK_SET_DISK_ATTRIBUTES并传递struct SET_DISK_ATTRIBUTES。我正在尝试使用以下代码:

const uint GENERIC_READ = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const int FILE_SHARE_READ = 0x1;
const int FILE_SHARE_WRITE = 0x2;

const uint IOCTL_DISK_SET_DISK_ATTRIBUTES = 0x0007c0f4;
const ulong DISK_ATTRIBUTE_READ_ONLY = 0x0000000000000002;

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr SecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile
);

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

struct SET_DISK_ATTRIBUTES
{
    public uint Version;
    public bool Persist;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] Reserved1;
    public ulong Attributes;
    public ulong AttributesMask;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public uint[] Reserved2;
};

private bool SetReadonly(IntPtr handle)
{
    var sda = new SET_DISK_ATTRIBUTES();
    sda.AttributesMask = DISK_ATTRIBUTE_READ_ONLY;
    sda.Attributes = DISK_ATTRIBUTE_READ_ONLY;

    int nPtrQryBytes = Marshal.SizeOf(sda);
    sda.Version = (uint)nPtrQryBytes;

    IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);
    Marshal.StructureToPtr(sda, ptrQuery, false);

    uint byteReturned;
    var res = DeviceIoControl(handle, IOCTL_DISK_SET_DISK_ATTRIBUTES, ptrQuery, (uint)nPtrQryBytes, IntPtr.Zero, 0, out byteReturned, IntPtr.Zero);

    var ex = new Win32Exception(Marshal.GetLastWin32Error());
    MessageBox.Show(ex.Message);

    return res;
}
Run Code Online (Sandbox Code Playgroud)

我收到错误“参数不正确”。调用DeviceIoControl函数传递结构的正确方法是什么SET_DISK_ATTRIBUTES

GSe*_*erg 5

的原始定义SET_DISK_ATTRIBUTES

typedef struct _SET_DISK_ATTRIBUTES {
  DWORD     Version;
  BOOLEAN   Persist;
  BYTE      Reserved1[3];
  DWORDLONG Attributes;
  DWORDLONG AttributesMask;
  DWORD     Reserved2[4];
} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES;
Run Code Online (Sandbox Code Playgroud)

使用BOOLEAN数据类型,数据类型定义unsigned char(1字节)BOOL的同义词,与之相反的是int(4字节)的同义词。

默认情况下,bool将封送C#BOOL
您需要将其强制为一个字节

{
    ...
    [MarshalAs(UnmanagedType.I1)]
    public bool Persist;
    ...
}
Run Code Online (Sandbox Code Playgroud)