Как определить, находится ли физическое устройство в сети или офлайн в Windows с помощью pInvoke

Я написал код, который может записывать и читать данные с физического диска. Я открываю физический диск с помощью pInvoke CreateFile и использую FileStream для чтения и записи данных.

Когда физический диск подключен к сети, все работает отлично.

Если физический диск отключен, и я пытаюсь выполнить запись на диск, я получаю сообщение об ошибке System.IO.IOException: «Носитель защищен от записи».

Как я могу определить, находится ли диск в автономном режиме, не пытаясь выполнить запись на диск.

Вот код, который создает FileStream и выполняет запись на диск

    private const uint GENERIC_READ = 0x80000000;
    private const uint GENERIC_WRITE = 0x40000000;
    private const uint OPEN_EXISTING = 3;
    private const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
    private const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;

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



    public void OpenFile()
    {
        m_handleValue = CreateFile(DevicePath, GENERIC_WRITE | GENERIC_READ,
                            0x3, IntPtr.Zero, OPEN_EXISTING,
                            FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
                            , IntPtr.Zero);
        
        m_fileStream = new FileStream(m_handleValue, FileAccess.ReadWrite, 512);
    }



    public void WriteData(int offset, byte[] data)
    {
        m_fileStream.Seek(offset, SeekOrigin.Begin);
        m_fileStream.Write(data, 0, data.Length);
    }

person Yaniv daye    schedule 26.07.2020    source источник
comment
По правде говоря, невозможно узнать со 100% уверенностью, потому что вы зависите от драйверов устройств для этого устройства, чтобы правильно и точно сообщать о своем состоянии в Windows. Windows выдает сообщение об ошибке. Носитель защищен от записи. поскольку он считает, что устройство подключено к сети и подключено, но защищено от записи, если Windows сочтет, что устройство отключено или недоступно, она выдаст вам другое сообщение об ошибке и другой код ошибки.   -  person Dai    schedule 26.07.2020
comment
Почему вы все равно заново реализуете CreateFile? Ваше объявление не добавляет никаких функций, которых еще нет ни в одном из конструкторов FileStream.   -  person Dai    schedule 26.07.2020
comment
В любом случае, для проверки состояния устройства вы захотите использовать WMI, а не CreateFile Win32. Тем не менее, может быть уместным фактически разрешить создание исключения, но только если отключенное / недоступное устройство действительно является исключительным обстоятельством.   -  person Dai    schedule 26.07.2020
comment
Я не переопределял CreateFile, я использую его с флагами, поэтому я могу пропустить операционную систему (используя FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH)   -  person Yaniv daye    schedule 26.07.2020
comment
Эти параметры также доступны через другие перегрузки конструктора FileStream.   -  person Dai    schedule 26.07.2020
comment
Не для физического диска, для физического диска мне нужно использовать extern CreateFile   -  person Yaniv daye    schedule 27.07.2020


Ответы (1)


Используя DeviceIoControl pInvoke, мы можем просмотреть атрибут DISK_ATTRIBUTE_OFFLINE

public static class RawDeviceInfoProvider
    {
        private const int IOCTL_DISK_GET_DISK_ATTRIBUTES = 0x000700F0;
        private const uint DISK_ATTRIBUTE_OFFLINE = 0x1;

        [StructLayout(LayoutKind.Sequential)]
        public struct GetDiskAttributes
        {
            public uint Version;
            public uint Reserved;
            public ulong Attributes;
        }

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


        public static bool GetOnlineStatus(SafeFileHandle hDevice)
        {
            uint dummy;
            GetDiskAttributes attributes = new GetDiskAttributes();
            IntPtr lpOutBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(attributes));
            bool success = DeviceIoControl(hDevice, IOCTL_DISK_GET_DISK_ATTRIBUTES, IntPtr.Zero, 0,
                lpOutBuffer, (uint)Marshal.SizeOf(typeof(GetDiskAttributes)), out dummy, IntPtr.Zero);
            attributes = (GetDiskAttributes)Marshal.PtrToStructure(lpOutBuffer, typeof(GetDiskAttributes));
            Marshal.FreeHGlobal(lpOutBuffer);
            if (!success)
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new IOException("Unable to retrieve disk attributes, Error: " + errorCode);
            }
            bool isOffline = (attributes.Attributes & DISK_ATTRIBUTE_OFFLINE) > 0;
            return !isOffline;
        }
    }
person Yaniv daye    schedule 28.07.2020