• C# 检查硬盘分区是ssd还是hdd


    C# detect driver ssd/hdd

    来自github的代码,略做了一丢丢修改。

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Principal;
    using System.Text;
    using System.Threading.Tasks;
    
    /// <summary>
        /// Class DiskDetectionUtils.
        /// reference : https://github.com/bitbeans/diskdetector-net
        /// </summary>
        public static class DiskDetectionUtils
        {
            #region DeviceIoControl (nominal media rotation rate)
    
            /// <summary>
            /// The ata flags data in
            /// </summary>
            private const uint AtaFlagsDataIn = 0x02;
    
            #endregion
    
            /// <summary>
            /// Check if the application is running as administrator.
            /// </summary>
            /// <returns><c>true</c> if the application is running as administrator otherwise, <c>false</c></returns>
            /// <exception cref="SecurityException"></exception>
            /// <exception cref="ArgumentException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            public static bool IsAdministrator()
            {
                var identity = WindowsIdentity.GetCurrent();
                if (identity == null) return false;
                var principal = new WindowsPrincipal(identity);
                return principal.IsInRole(WindowsBuiltInRole.Administrator);
            }
    
            /// <summary>
            /// Detect a fixed drive by letter.
            /// </summary>
            /// <param name="driveName">A valid drive letter.</param>
            /// <param name="queryType">The QueryType.</param>
            /// <param name="useFallbackQuery">Use QueryType.SeekPenalty as fallback.</param>
            /// <returns>A list of DriveInfoExtended.</returns>
            /// <exception cref="SecurityException">DetectHardwareTypeBySeekPenalty needs administrative access.</exception>
            /// <exception cref="IOException"></exception>
            /// <exception cref="UnauthorizedAccessException"></exception>
            /// <exception cref="DriveNotFoundException"></exception>
            /// <exception cref="ArgumentException"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            /// <exception cref="ArgumentOutOfRangeException"></exception>
            public static DriveInfoExtended DetectFixedDrive(string driveName, QueryType queryType = QueryType.SeekPenalty,
                bool useFallbackQuery = true)
            {
                var driveInfoExtended = new DriveInfoExtended();
                var logicalDrive = new DriveInfo(driveName);
                if (logicalDrive.DriveType == DriveType.Fixed)
                {
                    if (logicalDrive.IsReady)
                    {
                        var tmp = new DriveInfoExtended
                        {
                            DriveFormat = logicalDrive.DriveFormat,
                            VolumeLabel = logicalDrive.VolumeLabel,
                            Name = logicalDrive.Name,
                            UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                            DriveType = logicalDrive.DriveType,
                            AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                            TotalSize = logicalDrive.TotalSize,
                            TotalFreeSpace = logicalDrive.TotalFreeSpace,
                            RootDirectory = logicalDrive.RootDirectory,
                            DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0]
                        };
    
                        var driveId = GetDiskId(tmp.DriveLetter);
                        if (driveId != -1)
                        {
                            tmp.Id = driveId;
                            if (queryType == QueryType.SeekPenalty)
                            {
                                tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                            }
                            else
                            {
                                if (IsAdministrator())
                                {
                                    tmp.HardwareType = DetectHardwareTypeByRotationRate(driveId);
                                }
                                else
                                {
                                    if (useFallbackQuery)
                                    {
                                        tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                    }
                                    else
                                    {
                                        throw new SecurityException(
                                            "DetectHardwareTypeBySeekPenalty needs administrative access.");
                                    }
                                }
                            }
                            if (tmp.HardwareType != HardwareType.Unknown)
                            {
                                driveInfoExtended = tmp;
                            }
                        }
                    }
                }
                return driveInfoExtended;
            }
    
            /// <summary>
            /// Detect all fixed drives.
            /// </summary>
            /// <param name="queryType">The QueryType.</param>
            /// <param name="useFallbackQuery">Use QueryType.SeekPenalty as fallback.</param>
            /// <returns>A list of DriveInfoExtended.</returns>
            /// <exception cref="SecurityException">DetectHardwareTypeBySeekPenalty needs administrative access.</exception>
            /// <exception cref="IOException"></exception>
            /// <exception cref="UnauthorizedAccessException"></exception>
            /// <exception cref="DriveNotFoundException"></exception>
            /// <exception cref="ArgumentException"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            /// <exception cref="ArgumentOutOfRangeException"></exception>
            public static List<DriveInfoExtended> DetectFixedDrives(QueryType queryType = QueryType.SeekPenalty,
                bool useFallbackQuery = true)
            {
                var driveInfoExtended = new List<DriveInfoExtended>();
                var logicalDrives = DriveInfo.GetDrives();
    
                foreach (var logicalDrive in logicalDrives)
                {
                    if (logicalDrive.DriveType == DriveType.Fixed)
                    {
                        if (logicalDrive.IsReady)
                        {
                            var tmp = new DriveInfoExtended
                            {
                                DriveFormat = logicalDrive.DriveFormat,
                                VolumeLabel = logicalDrive.VolumeLabel,
                                Name = logicalDrive.Name,
                                UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                                DriveType = logicalDrive.DriveType,
                                AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                                TotalSize = logicalDrive.TotalSize,
                                TotalFreeSpace = logicalDrive.TotalFreeSpace,
                                RootDirectory = logicalDrive.RootDirectory,
                                DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0]
                            };
    
                            var driveId = GetDiskId(tmp.DriveLetter);
                            if (driveId != -1)
                            {
                                tmp.Id = driveId;
                                if (queryType == QueryType.SeekPenalty)
                                {
                                    tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                }
                                else
                                {
                                    if (IsAdministrator())
                                    {
                                        tmp.HardwareType = DetectHardwareTypeByRotationRate(driveId);
                                    }
                                    else
                                    {
                                        if (useFallbackQuery)
                                        {
                                            tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                        }
                                        else
                                        {
                                            throw new SecurityException(
                                                "DetectHardwareTypeBySeekPenalty needs administrative access.");
                                        }
                                    }
                                }
                                if (tmp.HardwareType != HardwareType.Unknown)
                                {
                                    driveInfoExtended.Add(tmp);
                                }
                            }
                        }
                    }
                }
                return driveInfoExtended;
            }
    
            /// <summary>
            /// Detect a fixed or removable drive.
            /// </summary>
            /// <param name="driveName">A valid drive letter.</param>
            /// <param name="queryType">The QueryType.</param>
            /// <param name="useFallbackQuery">Use QueryType.SeekPenalty as fallback.</param>
            /// <returns>A list of DriveInfoExtended.</returns>
            /// <exception cref="SecurityException">DetectHardwareTypeBySeekPenalty needs administrative access.</exception>
            /// <exception cref="IOException"></exception>
            /// <exception cref="UnauthorizedAccessException"></exception>
            /// <exception cref="DriveNotFoundException"></exception>
            /// <exception cref="ArgumentException"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            /// <exception cref="ArgumentOutOfRangeException"></exception>
            public static DriveInfoExtended DetectDrive(string driveName, QueryType queryType = QueryType.SeekPenalty,
                bool useFallbackQuery = true)
            {
                var driveInfoExtended = new DriveInfoExtended();
                var logicalDrive = new DriveInfo(driveName);
                if (logicalDrive.DriveType == DriveType.Fixed)
                {
                    if (logicalDrive.IsReady)
                    {
                        var tmp = new DriveInfoExtended
                        {
                            DriveFormat = logicalDrive.DriveFormat,
                            VolumeLabel = logicalDrive.VolumeLabel,
                            Name = logicalDrive.Name,
                            UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                            DriveType = logicalDrive.DriveType,
                            AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                            TotalSize = logicalDrive.TotalSize,
                            TotalFreeSpace = logicalDrive.TotalFreeSpace,
                            RootDirectory = logicalDrive.RootDirectory,
                            DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0]
                        };
    
                        var driveId = GetDiskId(tmp.DriveLetter);
                        if (driveId != -1)
                        {
                            tmp.Id = driveId;
                            if (queryType == QueryType.SeekPenalty)
                            {
                                tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                            }
                            else
                            {
                                if (IsAdministrator())
                                {
                                    tmp.HardwareType = DetectHardwareTypeByRotationRate(driveId);
                                }
                                else
                                {
                                    if (useFallbackQuery)
                                    {
                                        tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                    }
                                    else
                                    {
                                        throw new SecurityException(
                                            "DetectHardwareTypeBySeekPenalty needs administrative access.");
                                    }
                                }
                            }
                            driveInfoExtended = tmp;
                        }
                    }
                }
                else
                {
                    if (logicalDrive.IsReady)
                    {
    
                        var tmp = new DriveInfoExtended
                        {
                            DriveFormat = logicalDrive.DriveFormat,
                            VolumeLabel = logicalDrive.VolumeLabel,
                            Name = logicalDrive.Name,
                            UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                            DriveType = logicalDrive.DriveType,
                            AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                            TotalSize = logicalDrive.TotalSize,
                            TotalFreeSpace = logicalDrive.TotalFreeSpace,
                            RootDirectory = logicalDrive.RootDirectory,
                            DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0],
                            HardwareType = HardwareType.Unknown,
                            Id = -1
                        };
                        driveInfoExtended = tmp;
                    }
                }
                return driveInfoExtended;
            }
    
            /// <summary>
            /// Detect fixed and removable drives.
            /// </summary>
            /// <param name="queryType">The QueryType.</param>
            /// <param name="useFallbackQuery">Use QueryType.SeekPenalty as fallback.</param>
            /// <returns>A list of DriveInfoExtended.</returns>
            /// <exception cref="SecurityException">DetectHardwareTypeBySeekPenalty needs administrative access.</exception>
            /// <exception cref="IOException"></exception>
            /// <exception cref="UnauthorizedAccessException"></exception>
            /// <exception cref="DriveNotFoundException"></exception>
            /// <exception cref="ArgumentException"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            /// <exception cref="ArgumentOutOfRangeException"></exception>
            public static List<DriveInfoExtended> DetectDrives(QueryType queryType = QueryType.SeekPenalty,
                bool useFallbackQuery = true)
            {
                var driveInfoExtended = new List<DriveInfoExtended>();
                var logicalDrives = DriveInfo.GetDrives();
    
                foreach (var logicalDrive in logicalDrives)
                {
                    if (logicalDrive.DriveType == DriveType.Fixed)
                    {
                        if (logicalDrive.IsReady)
                        {
                            var tmp = new DriveInfoExtended
                            {
                                DriveFormat = logicalDrive.DriveFormat,
                                VolumeLabel = logicalDrive.VolumeLabel,
                                Name = logicalDrive.Name,
                                UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                                DriveType = logicalDrive.DriveType,
                                AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                                TotalSize = logicalDrive.TotalSize,
                                TotalFreeSpace = logicalDrive.TotalFreeSpace,
                                RootDirectory = logicalDrive.RootDirectory,
                                DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0]
                            };
    
                            var driveId = GetDiskId(tmp.DriveLetter);
                            if (driveId != -1)
                            {
                                tmp.Id = driveId;
                                if (queryType == QueryType.SeekPenalty)
                                {
                                    tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                }
                                else
                                {
                                    if (IsAdministrator())
                                    {
                                        tmp.HardwareType = DetectHardwareTypeByRotationRate(driveId);
                                    }
                                    else
                                    {
                                        if (useFallbackQuery)
                                        {
                                            tmp.HardwareType = DetectHardwareTypeBySeekPenalty(driveId);
                                        }
                                        else
                                        {
                                            throw new SecurityException(
                                                "DetectHardwareTypeBySeekPenalty needs administrative access.");
                                        }
                                    }
                                }
                                driveInfoExtended.Add(tmp);
                            }
                        }
                    }
                    else
                    {
                        if (logicalDrive.IsReady)
                        {
                            var tmp = new DriveInfoExtended
                            {
                                DriveFormat = logicalDrive.DriveFormat,
                                VolumeLabel = logicalDrive.VolumeLabel,
                                Name = logicalDrive.Name,
                                UncPath = Pathing.GetUNCPath(logicalDrive.Name),
                                DriveType = logicalDrive.DriveType,
                                AvailableFreeSpace = logicalDrive.AvailableFreeSpace,
                                TotalSize = logicalDrive.TotalSize,
                                TotalFreeSpace = logicalDrive.TotalFreeSpace,
                                RootDirectory = logicalDrive.RootDirectory,
                                DriveLetter = logicalDrive.Name.Substring(0, 1).ToCharArray()[0],
                                HardwareType = HardwareType.Unknown,
                                Id = -1
                            };
                            driveInfoExtended.Add(tmp);
                        }
                    }
                }
                return driveInfoExtended;
            }
    
            /// <summary>
            /// DeviceIoControl to get disk extents
            /// </summary>
            /// <param name="hDevice">The h device.</param>
            /// <param name="dwIoControlCode">The dw io control code.</param>
            /// <param name="lpInBuffer">The lp in buffer.</param>
            /// <param name="nInBufferSize">Size of the n in buffer.</param>
            /// <param name="lpOutBuffer">The lp out buffer.</param>
            /// <param name="nOutBufferSize">Size of the n out buffer.</param>
            /// <param name="lpBytesReturned">The lp bytes returned.</param>
            /// <param name="lpOverlapped">The lp overlapped.</param>
            /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
            [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl",
                SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint dwIoControlCode,
                IntPtr lpInBuffer,
                uint nInBufferSize,
                ref VolumeDiskExtents lpOutBuffer,
                uint nOutBufferSize,
                out uint lpBytesReturned,
                IntPtr lpOverlapped);
    
    
            /// <summary>
            /// Gets the device ID by drive letter.
            /// </summary>
            /// <param name="driveLetter">A valid drive letter.</param>
            /// <returns>The device ID.</returns>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <exception cref="ArgumentNullException"></exception>
            /// <exception cref="ArgumentException"></exception>
            private static int GetDiskId(char driveLetter)
            {
                var di = new DriveInfo(driveLetter.ToString());
                if (di.DriveType != DriveType.Fixed)
                {
                    throw new DetectionFailedException(string.Format("This drive is not fixed drive: {0}", driveLetter));
                }
    
                var sDrive = "\\.\" + driveLetter + ":";
    
                var hDrive = CreateFileW(
                    sDrive,
                    0, // No access to drive
                    FileShareRead | FileShareWrite,
                    IntPtr.Zero,
                    OpenExisting,
                    FileAttributeNormal,
                    IntPtr.Zero);
    
                if (hDrive == null || hDrive.IsInvalid)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new DetectionFailedException(string.Format("Could not detect Disk Id of {0}",
                        driveLetter),
                        new Win32Exception(lastError)
                        );
                }
    
                var ioctlVolumeGetVolumeDiskExtents = CTL_CODE(
                    IoctlVolumeBase, 0,
                    MethodBuffered, FileAnyAccess); // From winioctl.h
    
                var queryDiskExtents =
                    new VolumeDiskExtents();
    
                uint returnedQueryDiskExtentsSize;
    
                var queryDiskExtentsResult = DeviceIoControl(
                    hDrive,
                    ioctlVolumeGetVolumeDiskExtents,
                    IntPtr.Zero,
                    0,
                    ref queryDiskExtents,
                    (uint)Marshal.SizeOf(queryDiskExtents),
                    out returnedQueryDiskExtentsSize,
                    IntPtr.Zero);
    
                hDrive.Close();
    
                if (!queryDiskExtentsResult)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    const int ERROR_MORE_DATA = 234; //(0xEA) More data is available.
                    if (lastError != ERROR_MORE_DATA
                        || (queryDiskExtents.Extents.Length < 1)    // We need at least 1
                    )
                    {
                        throw new DetectionFailedException(string.Format("Could not detect Disk Id of {0}",
                                driveLetter),
                            new Win32Exception(lastError)
                        );
                    }
                }
    
                return (int)queryDiskExtents.Extents[0].DiskNumber;
            }
    
            /// <summary>
            /// Detect the HardwareType by SeekPenalty.
            /// </summary>
            /// <param name="driveLetter">A valid drive letter.</param>
            /// <returns>The detected HardwareType.</returns>
            public static HardwareType DetectHardwareTypeBySeekPenalty(char driveLetter)
            {
                try
                {
                    return DetectHardwareTypeBySeekPenalty(GetDiskId(driveLetter));
                }
                catch (DetectionFailedException)
                {
                    return HardwareType.Unknown;
                }
            }
    
            /// <summary>
            /// Detect the HardwareType by SeekPenalty.
            /// </summary>
            /// <param name="driveId">A valid drive Id.</param>
            /// <returns>The detected HardwareType.</returns>
            public static HardwareType DetectHardwareTypeBySeekPenalty(int driveId)
            {
                var physicalDriveName = "\\.\PhysicalDrive" + driveId;
    
                try
                {
                    return HasDriveSeekPenalty(physicalDriveName) ? HardwareType.Hdd : HardwareType.Ssd;
                }
                catch (DetectionFailedException)
                {
                    return HardwareType.Unknown;
                }
            }
    
            /// <summary>
            /// Detect the HardwareType by RotationRate.
            /// </summary>
            /// <param name="driveLetter">A valid drive letter.</param>
            /// <returns>The detected HardwareType.</returns>
            public static HardwareType DetectHardwareTypeByRotationRate(char driveLetter)
            {
                try
                {
                    return DetectHardwareTypeByRotationRate(GetDiskId(driveLetter));
                }
                catch (DetectionFailedException)
                {
                    return HardwareType.Unknown;
                }
            }
    
            /// <summary>
            /// Detect the HardwareType by RotationRate.
            /// </summary>
            /// <param name="driveId">A valid drive Id.</param>
            /// <returns>The detected HardwareType.</returns>
            /// <remarks>Administrative privilege is required!</remarks>
            public static HardwareType DetectHardwareTypeByRotationRate(int driveId)
            {
                var physicalDriveName = "\\.\PhysicalDrive" + driveId;
    
                try
                {
                    return HasDriveNominalMediaRotationRate(physicalDriveName) ? HardwareType.Hdd : HardwareType.Ssd;
                }
                catch (DetectionFailedException)
                {
                    return HardwareType.Unknown;
                }
            }
    
            /// <summary>
            /// ws the net get connection.
            /// </summary>
            /// <param name="localName">Name of the local.</param>
            /// <param name="remoteName">Name of the remote.</param>
            /// <param name="length">The length.</param>
            /// <returns>System.Int32.</returns>
            [DllImport("mpr.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern int WNetGetConnection([MarshalAs(UnmanagedType.LPTStr)] string localName, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, ref int length);
    
            /// <summary>
            /// Strings to unc.
            /// </summary>
            /// <param name="path">The path.</param>
            /// <returns>System.Object.</returns>
            private static object strToUnc(string path)
            {
                // This sample code assumes you currently have a drive mapped to p:
    
                // Find out what remote device a local mapping is to
    
                int rc = 0;
    
                // Size for the buffer we will use
    
                int bsize = 200;
    
                // Create a new stringbuilder, pre-sized as above
    
                StringBuilder rname = new StringBuilder(bsize);
    
                // Call the function
    
                rc = WNetGetConnection("Z:", rname, ref bsize);
    
                //https://stackoverflow.com/questions/1088752/how-to-programmatically-discover-mapped-network-drives-on-system-and-their-serve
                //http://www.pinvoke.net/default.aspx/mpr/WNetGetConnection.html
                int length = 255;
                /*2250 (0x8CA)
    This network connection does not exist.
    1200 (0x4B0)
    The specified device name is invalid.*/
                System.Text.StringBuilder UNC = new System.Text.StringBuilder(length);
                int q = WNetGetConnection("Z:", UNC, ref length);
                return UNC.ToString();
            }
    
            //to get the UNC-Path of a network-drive use something like:
    
    
    
            /// <summary>
            /// CreateFile to get handle to drive.
            /// </summary>
            /// <param name="lpFileName">Name of the lp file.</param>
            /// <param name="dwDesiredAccess">The dw desired access.</param>
            /// <param name="dwShareMode">The dw share mode.</param>
            /// <param name="lpSecurityAttributes">The lp security attributes.</param>
            /// <param name="dwCreationDisposition">The dw creation disposition.</param>
            /// <param name="dwFlagsAndAttributes">The dw flags and attributes.</param>
            /// <param name="hTemplateFile">The h template file.</param>
            /// <returns>SafeFileHandle.</returns>
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern SafeFileHandle CreateFileW(
                [MarshalAs(UnmanagedType.LPWStr)] string lpFileName,
                uint dwDesiredAccess,
                uint dwShareMode,
                IntPtr lpSecurityAttributes,
                uint dwCreationDisposition,
                uint dwFlagsAndAttributes,
                IntPtr hTemplateFile);
    
            /// <summary>
            /// Controls the code.
            /// </summary>
            /// <param name="DeviceType">Type of the device.</param>
            /// <param name="Function">The function.</param>
            /// <param name="Method">The method.</param>
            /// <param name="Access">The access.</param>
            /// <returns>System.UInt32.</returns>
            private static uint CTL_CODE(uint DeviceType, uint Function,
                uint Method, uint Access)
            {
                return ((DeviceType << 16) | (Access << 14) |
                        (Function << 2) | Method);
            }
    
            /// <summary>
            /// DeviceIoControl to check no seek penalty.
            /// </summary>
            /// <param name="hDevice">The h device.</param>
            /// <param name="dwIoControlCode">The dw io control code.</param>
            /// <param name="lpInBuffer">The lp in buffer.</param>
            /// <param name="nInBufferSize">Size of the n in buffer.</param>
            /// <param name="lpOutBuffer">The lp out buffer.</param>
            /// <param name="nOutBufferSize">Size of the n out buffer.</param>
            /// <param name="lpBytesReturned">The lp bytes returned.</param>
            /// <param name="lpOverlapped">The lp overlapped.</param>
            /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
            [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl",
                SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint dwIoControlCode,
                ref StoragePropertyQuery lpInBuffer,
                uint nInBufferSize,
                ref DeviceSeekPenaltyDescriptor lpOutBuffer,
                uint nOutBufferSize,
                out uint lpBytesReturned,
                IntPtr lpOverlapped);
    
            /// <summary>
            /// DeviceIoControl to check nominal media rotation rate.
            /// </summary>
            /// <param name="hDevice">The h device.</param>
            /// <param name="dwIoControlCode">The dw io control code.</param>
            /// <param name="lpInBuffer">The lp in buffer.</param>
            /// <param name="nInBufferSize">Size of the n in buffer.</param>
            /// <param name="lpOutBuffer">The lp out buffer.</param>
            /// <param name="nOutBufferSize">Size of the n out buffer.</param>
            /// <param name="lpBytesReturned">The lp bytes returned.</param>
            /// <param name="lpOverlapped">The lp overlapped.</param>
            /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
            [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl",
                SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint dwIoControlCode,
                ref AtaIdentifyDeviceQuery lpInBuffer,
                uint nInBufferSize,
                ref AtaIdentifyDeviceQuery lpOutBuffer,
                uint nOutBufferSize,
                out uint lpBytesReturned,
                IntPtr lpOverlapped);
    
            /// <summary>
            /// Check if the drive has a seek penalty.
            /// </summary>
            /// <param name="physicalDriveName">A valid physicalDriveName.</param>
            /// <returns><c> true </c> if the drive has a seek penalty otherwise, <c> false </c></returns>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <remarks>Administrative privilege is required!</remarks>
            private static bool HasDriveSeekPenalty(string physicalDriveName)
            {
                var hDrive = CreateFileW(
                    physicalDriveName,
                    0, // No access to drive
                    FileShareRead | FileShareWrite,
                    IntPtr.Zero,
                    OpenExisting,
                    FileAttributeNormal,
                    IntPtr.Zero);
    
                if (hDrive == null || hDrive.IsInvalid)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new DetectionFailedException(string.Format("Could not detect SeekPenalty of {0}",
                        physicalDriveName),
                        new Win32Exception(lastError)
                        );
                }
    
                var ioctlStorageQueryProperty = CTL_CODE(
                    IoctlStorageBase, 0x500,
                    MethodBuffered, FileAnyAccess); // From winioctl.h
    
                var querySeekPenalty =
                    new StoragePropertyQuery
                    {
                        PropertyId = StorageDeviceSeekPenaltyProperty,
                        QueryType = PropertyStandardQuery
                    };
    
                var querySeekPenaltyDesc =
                    new DeviceSeekPenaltyDescriptor();
    
                uint returnedQuerySeekPenaltySize;
    
                var querySeekPenaltyResult = DeviceIoControl(
                    hDrive,
                    ioctlStorageQueryProperty,
                    ref querySeekPenalty,
                    (uint)Marshal.SizeOf(querySeekPenalty),
                    ref querySeekPenaltyDesc,
                    (uint)Marshal.SizeOf(querySeekPenaltyDesc),
                    out returnedQuerySeekPenaltySize,
                    IntPtr.Zero);
    
                hDrive.Close();
    
                if (querySeekPenaltyResult == false)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new DetectionFailedException(string.Format("Could not detect SeekPenalty of {0}",
                        physicalDriveName),
                        new Win32Exception(lastError)
                        );
                }
                if (querySeekPenaltyDesc.IncursSeekPenalty == false)
                {
                    //This drive has NO SEEK penalty
                    return false;
                }
                //This drive has SEEK penalty
                return true;
            }
    
            /// <summary>
            /// Check if the drive has a nominal media rotation rate.
            /// </summary>
            /// <param name="physicalDriveName">A valid physicalDriveName.</param>
            /// <returns><c> true </c> if the drive has a media rotation rate otherwise, <c> false </c></returns>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="BluePrint.Common.Utility.DetectionFailedException"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="Win32Exception"></exception>
            /// <exception cref="DetectionFailedException"></exception>
            /// <remarks>Administrative privilege is required!</remarks>
            private static bool HasDriveNominalMediaRotationRate(string physicalDriveName)
            {
                var hDrive = CreateFileW(
                    physicalDriveName,
                    GenericRead | GenericWrite, // Administrative privilege is required
                    FileShareRead | FileShareWrite,
                    IntPtr.Zero,
                    OpenExisting,
                    FileAttributeNormal,
                    IntPtr.Zero);
    
                if (hDrive == null || hDrive.IsInvalid)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new DetectionFailedException(string.Format("Could not detect NominalMediaRotationRate of {0}",
                        physicalDriveName),
                        new Win32Exception(lastError)
                        );
                }
    
                var ioctlAtaPassThrough = CTL_CODE(
                    IoctlScsiBase, 0x040b, MethodBuffered,
                    FileReadAccess | FileWriteAccess); // From ntddscsi.h
    
                var idQuery = new AtaIdentifyDeviceQuery { data = new ushort[256] };
    
                idQuery.header.Length = (ushort)Marshal.SizeOf(idQuery.header);
                idQuery.header.AtaFlags = (ushort)AtaFlagsDataIn;
                idQuery.header.DataTransferLength =
                    (uint)(idQuery.data.Length * 2); // Size of "data" in bytes
                idQuery.header.TimeOutValue = 3; // Sec
                idQuery.header.DataBufferOffset = Marshal.OffsetOf(
                    typeof(AtaIdentifyDeviceQuery), "data");
                idQuery.header.PreviousTaskFile = new byte[8];
                idQuery.header.CurrentTaskFile = new byte[8];
                idQuery.header.CurrentTaskFile[6] = 0xec; // ATA IDENTIFY DEVICE
    
                uint retvalSize;
    
                var result = DeviceIoControl(
                    hDrive,
                    ioctlAtaPassThrough,
                    ref idQuery,
                    (uint)Marshal.SizeOf(idQuery),
                    ref idQuery,
                    (uint)Marshal.SizeOf(idQuery),
                    out retvalSize,
                    IntPtr.Zero);
    
                hDrive.Close();
    
                if (result == false)
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new DetectionFailedException(string.Format("Could not detect NominalMediaRotationRate of {0}",
                        physicalDriveName),
                        new Win32Exception(lastError)
                        );
                }
                // Word index of nominal media rotation rate
                // (1 means non-rotate device)
                const int kNominalMediaRotRateWordIndex = 217;
    
                if (idQuery.data[kNominalMediaRotRateWordIndex] == 1)
                {
                    return false;
                }
                return true;
            }
    
            /// <summary>
            /// For DeviceIoControl to get disk extents
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct DiskExtent
            {
                /// <summary>
                /// The disk number
                /// </summary>
                public readonly uint DiskNumber;
                /// <summary>
                /// The starting offset
                /// </summary>
                public readonly long StartingOffset;
                /// <summary>
                /// The extent length
                /// </summary>
                public readonly long ExtentLength;
            }
    
            /// <summary>
            /// Struct VolumeDiskExtents
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct VolumeDiskExtents
            {
                /// <summary>
                /// The number of disk extents
                /// </summary>
                public readonly uint NumberOfDiskExtents;
                /// <summary>
                /// The extents
                /// </summary>
                [MarshalAs(UnmanagedType.ByValArray)] public readonly DiskExtent[] Extents;
            }
    
            /// <summary>
            /// Struct StoragePropertyQuery
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct StoragePropertyQuery
            {
                /// <summary>
                /// The property identifier
                /// </summary>
                public uint PropertyId;
                /// <summary>
                /// The query type
                /// </summary>
                public uint QueryType;
                /// <summary>
                /// The additional parameters
                /// </summary>
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public readonly byte[] AdditionalParameters;
            }
    
            /// <summary>
            /// Struct DeviceSeekPenaltyDescriptor
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct DeviceSeekPenaltyDescriptor
            {
                /// <summary>
                /// The version
                /// </summary>
                public readonly uint Version;
                /// <summary>
                /// The size
                /// </summary>
                public readonly uint Size;
                /// <summary>
                /// The incurs seek penalty
                /// </summary>
                [MarshalAs(UnmanagedType.U1)] public readonly bool IncursSeekPenalty;
            }
    
            /// <summary>
            /// Struct AtaPassThroughEx
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct AtaPassThroughEx
            {
                /// <summary>
                /// The length
                /// </summary>
                public ushort Length;
                /// <summary>
                /// The ata flags
                /// </summary>
                public ushort AtaFlags;
                /// <summary>
                /// The path identifier
                /// </summary>
                public readonly byte PathId;
                /// <summary>
                /// The target identifier
                /// </summary>
                public readonly byte TargetId;
                /// <summary>
                /// The lun
                /// </summary>
                public readonly byte Lun;
                /// <summary>
                /// The reserved as uchar
                /// </summary>
                public readonly byte ReservedAsUchar;
                /// <summary>
                /// The data transfer length
                /// </summary>
                public uint DataTransferLength;
                /// <summary>
                /// The time out value
                /// </summary>
                public uint TimeOutValue;
                /// <summary>
                /// The reserved as ulong
                /// </summary>
                public readonly uint ReservedAsUlong;
                /// <summary>
                /// The data buffer offset
                /// </summary>
                public IntPtr DataBufferOffset;
                /// <summary>
                /// The previous task file
                /// </summary>
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] PreviousTaskFile;
                /// <summary>
                /// The current task file
                /// </summary>
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] CurrentTaskFile;
            }
    
            /// <summary>
            /// Struct AtaIdentifyDeviceQuery
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            private struct AtaIdentifyDeviceQuery
            {
                /// <summary>
                /// The header
                /// </summary>
                public AtaPassThroughEx header;
                /// <summary>
                /// The data
                /// </summary>
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public ushort[] data;
            }
    
            #region CreateFile (get handle to drive)
    
            /// <summary>
            /// The generic read
            /// </summary>
            private const uint GenericRead = 0x80000000;
            /// <summary>
            /// The generic write
            /// </summary>
            private const uint GenericWrite = 0x40000000;
            /// <summary>
            /// The file share read
            /// </summary>
            private const uint FileShareRead = 0x00000001;
            /// <summary>
            /// The file share write
            /// </summary>
            private const uint FileShareWrite = 0x00000002;
            /// <summary>
            /// The open existing
            /// </summary>
            private const uint OpenExisting = 3;
            /// <summary>
            /// The file attribute normal
            /// </summary>
            private const uint FileAttributeNormal = 0x00000080;
    
            #endregion
    
            #region Control Codes
    
            /// <summary>
            /// The file device mass storage
            /// </summary>
            private const uint FileDeviceMassStorage = 0x0000002d;
            /// <summary>
            /// The ioctl storage base
            /// </summary>
            private const uint IoctlStorageBase = FileDeviceMassStorage;
            /// <summary>
            /// The file device controller
            /// </summary>
            private const uint FileDeviceController = 0x00000004;
            /// <summary>
            /// The ioctl scsi base
            /// </summary>
            private const uint IoctlScsiBase = FileDeviceController;
            /// <summary>
            /// The method buffered
            /// </summary>
            private const uint MethodBuffered = 0;
            /// <summary>
            /// The file any access
            /// </summary>
            private const uint FileAnyAccess = 0;
            /// <summary>
            /// The file read access
            /// </summary>
            private const uint FileReadAccess = 0x00000001;
            /// <summary>
            /// The file write access
            /// </summary>
            private const uint FileWriteAccess = 0x00000002;
            /// <summary>
            /// The ioctl volume base
            /// </summary>
            private const uint IoctlVolumeBase = 0x00000056;
    
            #endregion
    
            #region DeviceIoControl (seek penalty)
    
            /// <summary>
            /// The storage device seek penalty property
            /// </summary>
            private const uint StorageDeviceSeekPenaltyProperty = 7;
            /// <summary>
            /// The property standard query
            /// </summary>
            private const uint PropertyStandardQuery = 0;
    
            #endregion
        }
    
        /// <summary>
        /// Class NativeMethods.
        /// </summary>
        public partial class NativeMethods
        {
            /// <summary>
            /// The type of structure that the function stores in the buffer.
            /// </summary>
            public enum InfoLevel
            {
                /// <summary>
                /// The function stores a <see cref="UNIVERSAL_NAME_INFO" /> structure in the
                /// buffer.
                /// </summary>
                UniversalName = 1,
    
                /// <summary>
                /// The function stores a <c>REMOTE_NAME_INFO</c> structure in the buffer.
                /// </summary>
                RemoteName = 2
            }
    
    
            /// <summary>
            /// ws the name of the net get universal.
            /// </summary>
            /// <param name="lpLocalPath">The lp local path.</param>
            /// <param name="dwInfoLevel">The dw information level.</param>
            /// <param name="lpBuffer">The lp buffer.</param>
            /// <param name="lpBufferSize">Size of the lp buffer.</param>
            /// <returns>System.Int32.</returns>
            [DllImport("mpr.dll", CharSet = CharSet.Auto)]
            public static extern int WNetGetUniversalName(
                string lpLocalPath,
                InfoLevel dwInfoLevel,
                ref UNIVERSAL_NAME_INFO lpBuffer,
                ref int lpBufferSize);
    
            /// <summary>
            /// ws the name of the net get universal.
            /// </summary>
            /// <param name="lpLocalPath">The lp local path.</param>
            /// <param name="dwInfoLevel">The dw information level.</param>
            /// <param name="lpBuffer">The lp buffer.</param>
            /// <param name="lpBufferSize">Size of the lp buffer.</param>
            /// <returns>System.Int32.</returns>
            [DllImport("mpr.dll", CharSet = CharSet.Auto)]
            public static extern int WNetGetUniversalName(
                string lpLocalPath,
                InfoLevel dwInfoLevel,
                IntPtr lpBuffer,
                ref int lpBufferSize);
    
            /// <summary>
            /// The <see cref="UNIVERSAL_NAME_INFO" /> structure contains a pointer to a
            /// Universal Naming Convention (UNC) name string for a network resource.
            /// </summary>
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            public struct UNIVERSAL_NAME_INFO
            {
                /// <summary>
                /// Pointer to the null-terminated UNC name string that identifies a
                /// network resource.
                /// </summary>
                [MarshalAs(UnmanagedType.LPTStr)]
                public string lpUniversalName;
            }
        }
    
        /// <summary>
        /// Class DetectionFailedException.
        /// Implements the <see cref="System.Exception" />
        /// </summary>
        /// <seealso cref="System.Exception" />
        public class DetectionFailedException : Exception
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="DetectionFailedException"/> class.
            /// </summary>
            public DetectionFailedException()
            {
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="DetectionFailedException"/> class.
            /// </summary>
            /// <param name="message">描述错误的消息。</param>
            public DetectionFailedException(string message)
                : base(message)
            {
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="DetectionFailedException"/> class.
            /// </summary>
            /// <param name="message">The message.</param>
            /// <param name="inner">The inner.</param>
            public DetectionFailedException(string message, Exception inner)
                : base(message, inner)
            {
            }
        }
    
        /// <summary>
        /// Class DriveInfoExtended.
        /// </summary>
        public class DriveInfoExtended
        {
            /// <summary>
            /// Gets or sets the name.
            /// </summary>
            /// <value>The name.</value>
            public string Name { get; set; }
            /// <summary>
            /// Gets or sets the drive letter.
            /// </summary>
            /// <value>The drive letter.</value>
            public char DriveLetter { get; set; }
            /// <summary>
            /// Gets or sets the type of the drive.
            /// </summary>
            /// <value>The type of the drive.</value>
            public DriveType DriveType { get; set; }
            /// <summary>
            /// Gets or sets the identifier.
            /// </summary>
            /// <value>The identifier.</value>
            public int Id { get; set; }
            /// <summary>
            /// Gets or sets the volume label.
            /// </summary>
            /// <value>The volume label.</value>
            public string VolumeLabel { get; set; }
            /// <summary>
            /// Gets or sets the drive format.
            /// </summary>
            /// <value>The drive format.</value>
            public string DriveFormat { get; set; }
            /// <summary>
            /// Gets or sets the total free space.
            /// </summary>
            /// <value>The total free space.</value>
            public long TotalFreeSpace { get; set; }
            /// <summary>
            /// Gets or sets the total size.
            /// </summary>
            /// <value>The total size.</value>
            public long TotalSize { get; set; }
            /// <summary>
            /// Gets or sets the available free space.
            /// </summary>
            /// <value>The available free space.</value>
            public long AvailableFreeSpace { get; set; }
            /// <summary>
            /// Gets or sets the type of the hardware.
            /// </summary>
            /// <value>The type of the hardware.</value>
            public HardwareType HardwareType { get; set; }
            /// <summary>
            /// Gets or sets the root directory.
            /// </summary>
            /// <value>The root directory.</value>
            public DirectoryInfo RootDirectory { get; set; }
            /// <summary>
            /// Gets or sets the unc path.
            /// </summary>
            /// <value>The unc path.</value>
            public string UncPath { get; set; }
        }
    
        /// <summary>
        /// Possible HardwareTypes.
        /// </summary>
        public enum HardwareType
        {
            /// <summary>
            /// Unknown hardware type.
            /// </summary>
            Unknown,
    
            /// <summary>
            /// Hard Disk Drive.
            /// </summary>
            Hdd,
    
            /// <summary>
            /// Solid State Drive.
            /// </summary>
            Ssd
        }
    
        /// <summary>
        /// Possible QueryTypes.
        /// </summary>
        public enum QueryType
        {
            /// <summary>
            /// Detect the HardwareType by SeekPenalty.
            /// </summary>
            SeekPenalty,
    
            /// <summary>
            /// Detect the HardwareType by RotationRate.
            /// </summary>
            RotationRate
        }
    
        /// <summary>
        /// Class Pathing.
        /// </summary>
        internal static class Pathing
        {
            [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            public static extern int WNetGetConnection(
                [MarshalAs(UnmanagedType.LPTStr)] string localName,
                [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName,
                ref int length);
    
            /// <summary>
            ///     Given a path, returns the UNC path or the original. (No exceptions
            ///     are raised by this function directly). For example, "P:2008-02-29"
            ///     might return: "\networkserverSharesPhotos2008-02-09"
            ///     http://www.wiredprairie.us/blog/index.php/archives/22
            /// </summary>
            /// <param name="originalPath">The path to convert to a UNC Path</param>
            /// <returns>
            ///     A UNC path. If a network drive letter is specified, the
            ///     drive letter is converted to a UNC or network path. If the
            ///     originalPath cannot be converted, it is returned unchanged.
            /// </returns>        
            public static string GetUNCPath(string originalPath)
            {
                var sb = new StringBuilder(512);
                var size = sb.Capacity;
    
                // look for the {LETTER}: combination ...
                if (originalPath.Length > 2 && originalPath[1] == ':')
                {
                    // don't use char.IsLetter here - as that can be misleading
                    // the only valid drive letters are a-z && A-Z.
                    var c = originalPath[0];
                    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
                    {
                        var error = WNetGetConnection(originalPath.Substring(0, 2),
                            sb, ref size);
                        if (error == 0)
                        {
                            var dir = new DirectoryInfo(originalPath);
    
                            var path = Path.GetFullPath(originalPath)
                                .Substring(Path.GetPathRoot(originalPath).Length);
                            return Path.Combine(sb.ToString().TrimEnd(), path);
                        }
                    }
                }
    
                return originalPath;
            }
        }

    调用接口DiskDetectionUtils.DetectDrive即可,第一个参数是a-z的字符。比如:

    var ext = DiskDetectionUtils.DetectDrive(targetDirectory.Substring(0, 1));

    if(ext.HardwareType != HardwareType.Ssd)

    {

       // do sht.

    }

  • 相关阅读:
    ARM中断(一)
    窗口置顶小工具
    volatile关键字
    IIC总线
    ARM中断(三)
    BootLoader —— S3C2440
    视频那些事
    [轉]簡單的顯示隱藏實現
    Apache Service Monitor Start按鈕变灰 的解决方法
    [转载]经典java转码程序,实现native2ascii命令行的功能
  • 原文地址:https://www.cnblogs.com/bodong/p/14892682.html
Copyright © 2020-2023  润新知