E
E
ebroker2018-12-21 15:14:50
Windows
ebroker, 2018-12-21 15:14:50

C# pass parameter to Win32Api function?

You need to call the Win32Api DeviceIoControl function with the IOCTL_DISK_SET_DISK_ATTRIBUTES parameter and pass the SET_DISK_ATTRIBUTES structure, such a command should set the disk as read-only.

How I am trying to do it:
[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
);

const ulong DISK_ATTRIBUTE_READ_ONLY = 0x0000000000000002;
struct SET_DISK_ATTRIBUTES
{
    public uint Version;
    public bool Persist;
    public byte[] Reserved1;
    public ulong Attributes;
    public ulong AttributesMask;
    public uint[] Reserved2;
};       


private bool SetReadonly(IntPtr handle)
{
    var sda = new SET_DISK_ATTRIBUTES();
    sda.Reserved1 = new byte[3];
    sda.Reserved2 = new uint[4];

    sda.AttributesMask = DISK_ATTRIBUTE_READ_ONLY;
    sda.Attributes = DISK_ATTRIBUTE_READ_ONLY;

    int nPtrQryBytes = Marshal.SizeOf(sda);
    IntPtr ptrQuery = Marshal.AllocHGlobal(nPtrQryBytes);

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


I get the error "Invalid parameter"
Tell me how to correctly pass the structure to the Win32Api parameter of the function.

Answer the question

In order to leave comments, you need to log in

3 answer(s)
E
ebroker, 2018-12-25
@ebroker

The issue was resolved here https://stackoverflow.com/questions/53898839/c-sha...

N
none7, 2018-12-22
@none7

First, these arrays should be placed in the structure itself, not managed references to them. It's strange that the marshaling did not spit out the exception. It should be something like this:

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

Secondly, you forgot to copy the structure into memory and pass uninitialized garbage to the DeviceIoControl function. You can also add an overloaded DeviceIoControl method that takes ref SET_DISK_ATTRIBUTES instead of IntPtr and does not mess around with dynamic memory. As long as the structure is a local variable of a synchronous method, the GC will not drag it anywhere.

P
Peter, 2018-12-21
@petermzg

Open Total Commander or a similar file manager,
go to c:\Program Files\dotnet\
Do a search for all dll files and search by content: DeviceIoControl
Next, use the .Net Reflector application (there is a 15-day trial ;) )
Load the found dlls (File /Open Assembly..)
In the search bar DeviceIoControl and "Search member" search type.
He finds everything.
In the tree, select the found method and in the Analyze context menu
. In the Analyze window that opens, select "Used by" and then "Go to member".
It remains only to convert the found examples to suit your own needs.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question