Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to get Hard-Disk SerialNumber in C# (no WMI)?
    text
    copied!<p>I know there are two articles in CodeProject (one uses WMI and the other no WMI but in C++). I tried the WMI way, not only it's slow, but it is also unreliable. So, that's why I decided not to pursue that way. I want to do it in C# through pInvoke. I tried it but got stuck in DeviceIoControl API. Can anybody give me a hint? Here is my code:</p> <pre><code>using System; using System.ComponentModel; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace Chemulator.Common { public class HDSerialNumber { [StructLayout(LayoutKind.Sequential)] private struct IDEREGS { public byte bFeaturesReg; public byte bSectorCountReg; public byte bSectorNumberReg; public byte bCylLowReg; public byte bCylHighReg; public byte bDriveHeadReg; public byte bCommandReg; public byte bReserved; } [StructLayout(LayoutKind.Sequential)] private struct SENDCMDINPARAMS { public Int32 cBufferSize; public IDEREGS irDriveRegs; public byte bDriveNumber; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] bReserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public Int32[] dwReserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] bBuffer; } [StructLayout(LayoutKind.Sequential)] private struct DRIVERSTATUS { public byte bDriverError; public byte bIDEError; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] bReserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public Int32[] dwReserved; } [StructLayout(LayoutKind.Sequential)] private struct SENDCMDOUTPARAMS { public Int32 cBufferSize; public DRIVERSTATUS DriverStatus; [MarshalAs(UnmanagedType.ByValArray, SizeConst = IDENTIFY_BUFFER_SIZE)] public byte[] bBuffer; } [StructLayout(LayoutKind.Sequential)] private struct GETVERSIONOUTPARAMS { public byte bVersion; public byte bRevision; public byte bReserved; public byte bIDEDeviceMap; public Int32 fCapabilities; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public Int32 dwReserved; } [StructLayout(LayoutKind.Sequential)] private struct STORAGE_PROPERTY_QUERY { public Int32 PropertyId; public Int32 QueryType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] AdditionalParameters; } [StructLayout(LayoutKind.Sequential)] private struct STORAGE_DEVICE_DESCRIPTOR { public Int32 Version; public Int32 Size; public byte DeviceType; public byte DeviceTypeModifier; public byte RemovableMedia; public byte CommandQueueing; public Int32 VendorIdOffset; public Int32 ProductIdOffset; public Int32 ProductRevisionOffset; public Int32 SerialNumberOffset; public byte BusType; public Int32 RawPropertiesLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)] public byte[] RawDeviceProperties; } [DllImport("kernel32.dll", SetLastError = true)] private static extern SafeFileHandle CreateFile(string lpFileName, Int32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32")] private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, ref uint lpBytesReturned, IntPtr lpOverlapped); private const Int32 OPEN_EXISTING = 3; private const Int32 GENERIC_READ = unchecked((int)0x80000000); private const Int32 GENERIC_WRITE = 0x40000000; private const Int32 FILE_SHARE_READ = 0x1; private const Int32 FILE_SHARE_WRITE = 0x2; private const Int32 FILE_SHARE_DELETE = 0x4; private const Int32 SMART_GET_VERSION = 0x74080; private const Int32 SMART_RCV_DRIVE_DATA = 0x7C088; private const Int32 ID_CMD = 0xEC; private const Int32 IDENTIFY_BUFFER_SIZE = 512; private const Int32 CAP_SMART_CMD = 0x4; private const Int32 IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400; private const Int32 PropertyStandardQuery = 0; private const Int32 StorageDeviceProperty = 0; public static string GetSerialNumber(int diskNumber) { string str = GetSerialNumberUsingStorageQuery(diskNumber); if (string.IsNullOrEmpty(str)) str = GetSerialNumberUsingSmart(diskNumber); return str; } public static string GetSerialNumberUsingStorageQuery(int diskNumber) { using (SafeFileHandle hDisk = OpenDisk(diskNumber)) { uint iBytesReturned = 0; var spq = new STORAGE_PROPERTY_QUERY(); var sdd = new STORAGE_DEVICE_DESCRIPTOR(); spq.PropertyId = StorageDeviceProperty; spq.QueryType = PropertyStandardQuery; if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, spq, (uint)Marshal.SizeOf(spq), sdd, (uint)Marshal.SizeOf(sdd), ref iBytesReturned, IntPtr.Zero)) throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY)"); var result = new StringBuilder(); if (sdd.SerialNumberOffset &gt; 0) { var rawDevicePropertiesOffset = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length; int pos = sdd.SerialNumberOffset - rawDevicePropertiesOffset; while (pos &lt; iBytesReturned &amp;&amp; sdd.RawDeviceProperties[pos] != 0) { result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1)); pos += 1; } } return result.ToString(); } } public static string GetSerialNumberUsingSmart(int diskNumber) { using (SafeFileHandle hDisk = OpenDisk(diskNumber)) { if (IsSmartSupported(hDisk)) { Int32 iBytesReturned = 0; var sci = new SENDCMDINPARAMS(); var sco = new SENDCMDOUTPARAMS(); sci.irDriveRegs.bCommandReg = ID_CMD; sci.bDriveNumber = (byte)diskNumber; sci.cBufferSize = IDENTIFY_BUFFER_SIZE; if (DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, sci, (uint)Marshal.SizeOf(sci), sco, (uint)Marshal.SizeOf(sco), ref iBytesReturned, IntPtr.Zero)) throw CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)"); var result = new StringBuilder(); for (int index = 20; index &lt; 39; index += 2) { result.Append(Encoding.ASCII.GetString(sco.bBuffer, index + 1, 1)); result.Append(Encoding.ASCII.GetString(sco.bBuffer, index, 1)); } return result.ToString(); } return string.Empty; } } private static Win32Exception CreateWin32Exception(Int32 errorCode, string context) { var win32Exception = new Win32Exception(errorCode); win32Exception.Data["Context"] = context; return win32Exception; } private static SafeFileHandle OpenDisk(int diskNumber) { SafeFileHandle hDevice = CreateFile(string.Format(@"\\.\PhysicalDrive{0}", diskNumber), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (!hDevice.IsInvalid) return hDevice; else throw CreateWin32Exception(Marshal.GetLastWin32Error(), "CreateFile"); } private static bool IsSmartSupported(SafeFileHandle hDisk) { uint iBytesReturned = 0; var gvo = new GETVERSIONOUTPARAMS(); IntPtr pGVO = Marshal.AllocHGlobal(512); if (DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, pGVO, 512, ref iBytesReturned, IntPtr.Zero)) return false; return (gvo.fCapabilities &amp; CAP_SMART_CMD) &gt; 0; } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload