Задать вопрос
@ebroker

C# передать параметр в Win32Api функцию?

Нужно вызвать функцию Win32Api DeviceIoControl с парметром IOCTL_DISK_SET_DISK_ATTRIBUTES и передать структуру SET_DISK_ATTRIBUTES такая команда должна установить диск только для чтения.

Как я это пытаюсь сделать:
[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;
}


Получаю ошибку "Invalid parameter"
Подскажите как правильно передать структуру в параметр Win32Api функции.
  • Вопрос задан
  • 168 просмотров
Подписаться 1 Средний Комментировать
Помогут разобраться в теме Все курсы
  • Merion Academy
    Администрирование MS Windows Server
    1 месяц
    Далее
  • Нетология
    Инженер по автоматизации
    13 месяцев
    Далее
  • Skillbox
    Системный администратор с нуля
    6 месяцев
    Далее
Решения вопроса 1
@ebroker Автор вопроса
Вопрос решился здесь https://stackoverflow.com/questions/53898839/c-sha...
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@none7
Во первых эти массивы должны размещаться в самой структуре, а не управляемые ссылки на них. Странно уже то, что маршалинг исключение не выплюнул. Должно быть как то так:
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;
};

Во вторых Вы забыли скопировать структуру в память и передаете функции DeviceIoControl не инициализированный мусор. Так же можно добавить перегруженный метод DeviceIoControl принимающий ref SET_DISK_ATTRIBUTES вместо IntPtr и не возится с динамической памятью. Пока структура является локальной переменной синхронного метода, GC её никуда не утащит.
Ответ написан
Комментировать
petermzg
@petermzg
Самый лучший программист
Открываете Total Commander или подобный файл менеджер
переходите в каталог c:\Program Files\dotnet\
Делаете поиск по всем dll файлам и в поиске по содержимому: DeviceIoControl

Далее используете приложение .Net Reflector (есть 15 дней триала ;) )
Подгружаете найденные dll (File/Open Assembly..)
В строке поиска DeviceIoControl и "Search member" тип поиска.
Он находит все.
В дереве выбираете найденый метод и в контекстом меню Analyze
В открывшемся окне Analyze выбипаете "Used by" и далее "Go to member".

Остается только найденные примеры преобразовать под собственные нужды.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
Монетка Екатеринбург
от 130 000 до 160 000 ₽
Гринатом Петрозаводск
До 80 000 ₽
Алабуга Екатеринбург
от 127 500 ₽