Задать вопрос
@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 функции.
  • Вопрос задан
  • 158 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 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".

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

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

Похожие вопросы