Yaniv daye
Yaniv daye

Reputation: 93

How to detect whether physical device is online or offline in Windows using pInvoke

I wrote code that can write and read data from physical disk. I open the physical disk using pInvoke CreateFile and use FileStream to perform read and write data.

When physical disk is online, every thing works great.

In case the physical disk is offline and I try to write to disk, I get an error System.IO.IOException: 'The media is write protected.'

How can I detect if disk is offline without trying to write to disk.

Here is the code that create the FileStream and perform writes to disk

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

Upvotes: 1

Views: 429

Answers (1)

Yaniv daye
Yaniv daye

Reputation: 93

Using DeviceIoControl pInvoke we can review attribute 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;
        }
    }

Upvotes: 0

Related Questions