using System; using System.Runtime.InteropServices; using System.Text; using System.ComponentModel; using Microsoft.Win32.SafeHandles; namespace HamrahsoftAssistant { internal class HamrahsoftHD { #region Win32 Definitions [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 int cBufferSize; public IDEREGS irDriveRegs; public byte bDriveNumber; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] bReserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[] 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 int[] dwReserved; } [StructLayout(LayoutKind.Sequential)] private struct SENDCMDOUTPARAMS { public int cBufferSize; public DRIVERSTATUS DriverStatus; [MarshalAs(UnmanagedType.ByValArray, SizeConst = IDENTIFY_BUFFER_SIZE)] public byte[] bBuffer; } [StructLayout(LayoutKind.Sequential)] private struct GETVERSIONINPARAMS { public byte bVersion; public byte bRevision; public byte bReserved; public byte bIDEDeviceMap; public int fCapabilities; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[] dwReserved; } [StructLayout(LayoutKind.Sequential)] private struct STORAGE_PROPERTY_QUERY { public int PropertyId; public int QueryType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] AdditionalParameters; } [StructLayout(LayoutKind.Sequential)] private struct STORAGE_DEVICE_DESCRIPTOR { public int Version; public int Size; public byte DeviceType; public byte DeviceTypeModifier; public byte RemovableMedia; public byte CommandQueueing; public int VendorIdOffset; public int ProductIdOffset; public int ProductRevisionOffset; public int SerialNumberOffset; public byte BusType; public int RawPropertiesLength; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10240)] public byte[] RawDeviceProperties; } [StructLayout(LayoutKind.Sequential)] private struct SCSI_PASS_THROUGH { public short Length; public byte ScsiStatus; public byte PathId; public byte TargetId; public byte Lun; public byte CdbLength; public byte SenseInfoLength; public byte DataIn; public int DataTransferLength; public int TimeOutValue; public IntPtr DataBufferOffset; public int SenseInfoOffset; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte[] Cdb; } [StructLayout(LayoutKind.Sequential)] private struct SCSI_PASS_THROUGH_WITH_BUFFER { public SCSI_PASS_THROUGH Spt; public int Filler; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] Buffer; } [DllImport("kernel32.dll", SetLastError = true)] private static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] private static extern int DeviceIoControl(SafeFileHandle hDevice, int dwIoControlCode, [In()]ref SENDCMDINPARAMS lpInBuffer, int nInBufferSize, [In(), Out()]ref SENDCMDOUTPARAMS lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, int lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern int DeviceIoControl(SafeFileHandle hDevice, int dwIoControlCode, IntPtr lpInBuffer, int nInBufferSize, [In(), Out()]ref GETVERSIONINPARAMS lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, int lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern int DeviceIoControl(SafeFileHandle hDevice, int dwIoControlCode, [In()]ref STORAGE_PROPERTY_QUERY lpInBuffer, int nInBufferSize, [In(), Out()]ref STORAGE_DEVICE_DESCRIPTOR lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, int lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern int DeviceIoControl(SafeFileHandle hDevice, int dwIoControlCode, [In()]ref SCSI_PASS_THROUGH_WITH_BUFFER lpInBuffer, int nInBufferSize, [In(), Out()]ref SCSI_PASS_THROUGH_WITH_BUFFER lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, int lpOverlapped); private const int OPEN_EXISTING = 3; private const int GENERIC_READ = unchecked((int)0x80000000); private const int GENERIC_WRITE = 0x40000000; private const int FILE_SHARE_READ = 0x1; private const int FILE_SHARE_WRITE = 0x2; private const int FILE_SHARE_DELETE = 0x4; private const int SMART_GET_VERSION = 0x74080; private const int SMART_RCV_DRIVE_DATA = 0x7C088; private const int ID_CMD = 0xEC; private const int IDENTIFY_BUFFER_SIZE = 512; private const int CAP_SMART_CMD = 0x4; private const int IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400; private const int IOCTL_SCSI_PASS_THROUGH = 0x4D004; private const int SCSI_IOCTL_DATA_IN = 0x1; private const int PropertyStandardQuery = 0; private const int StorageDeviceProperty = 0; private const int ERROR_INVALID_FUNCTION = 0x1; #endregion public static string GetSerialNumberUsingStorageQuery(int diskNumber) { using (SafeFileHandle hDisk = OpenDisk(diskNumber)) { int iBytesReturned = 0; STORAGE_PROPERTY_QUERY spq = new STORAGE_PROPERTY_QUERY(); STORAGE_DEVICE_DESCRIPTOR sdd = new STORAGE_DEVICE_DESCRIPTOR(); spq.PropertyId = StorageDeviceProperty; spq.QueryType = PropertyStandardQuery; if (DeviceIoControl(hDisk, IOCTL_STORAGE_QUERY_PROPERTY, ref spq, Marshal.SizeOf(spq), ref sdd, Marshal.SizeOf(sdd), ref iBytesReturned, 0) == 0) { throw (CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(IOCTL_STORAGE_QUERY_PROPERTY) ")); } StringBuilder result = new StringBuilder(); if (sdd.SerialNumberOffset > 0) { int rawDevicePropertiesOffset = Marshal.SizeOf(sdd) - sdd.RawDeviceProperties.Length; int pos = sdd.SerialNumberOffset - rawDevicePropertiesOffset; while (pos < iBytesReturned && sdd.RawDeviceProperties[pos] != 0) { result.Append(Encoding.ASCII.GetString(sdd.RawDeviceProperties, pos, 1)); pos++; } } return result.ToString().Trim(); } } public static string GetSerialNumberUsingSmart(int diskNumber) { using (SafeFileHandle hDisk = OpenDisk(diskNumber)) { if (IsSmartSupported(hDisk)) { int iBytesReturned = 0; SENDCMDINPARAMS sci = new SENDCMDINPARAMS(); SENDCMDOUTPARAMS sco = new SENDCMDOUTPARAMS(); sci.irDriveRegs.bCommandReg = (byte)ID_CMD; sci.bDriveNumber = (byte)diskNumber; sci.cBufferSize = IDENTIFY_BUFFER_SIZE; if (DeviceIoControl(hDisk, SMART_RCV_DRIVE_DATA, ref sci, Marshal.SizeOf(sci), ref sco, Marshal.SizeOf(sco), ref iBytesReturned, 0) == 0) { throw (CreateWin32Exception(Marshal.GetLastWin32Error(), "DeviceIoControl(SMART_RCV_DRIVE_DATA)")); } StringBuilder result = new StringBuilder(); for (int index = 20; index <= 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().Trim(); } else { return string.Empty; } } } public static string GetSerialNumberUsingScsiPassThrough(int diskNumber) { using (SafeFileHandle hDisk = OpenDisk(diskNumber)) { int iBytesReturned = 0; SCSI_PASS_THROUGH_WITH_BUFFER spt = new SCSI_PASS_THROUGH_WITH_BUFFER(); spt.Spt.Length = (short)(Marshal.SizeOf(spt.Spt)); spt.Spt.CdbLength = (byte)16; spt.Spt.DataIn = (byte)SCSI_IOCTL_DATA_IN; spt.Spt.DataTransferLength = 64; spt.Spt.DataBufferOffset = new IntPtr(Marshal.SizeOf(spt) - 64); spt.Spt.TimeOutValue = 60; byte[] cdb = new byte[16]; cdb[0] = (byte)(0x12); // INQUIRY cdb[1] = (byte)(0x1); // EVPD bit cdb[2] = (byte)(0x80); // Page code (indicates Serial Number) cdb[4] = (byte)64; // Allocation length spt.Spt.Cdb = cdb; if (DeviceIoControl(hDisk, IOCTL_SCSI_PASS_THROUGH, ref spt, Marshal.SizeOf(spt), ref spt, Marshal.SizeOf(spt), ref iBytesReturned, 0) == 0) { int iErrorCode = Marshal.GetLastWin32Error(); if (iErrorCode != ERROR_INVALID_FUNCTION) { throw (CreateWin32Exception(iErrorCode, "DeviceIoControl(IOCTL_SCSI_PASS_THROUGH)")); } } StringBuilder result = new StringBuilder(); int pos = IntPtr.Size; while (pos < spt.Spt.DataTransferLength && spt.Buffer[pos] != 0) { result.Append(Encoding.ASCII.GetString(spt.Buffer, pos, 1)); pos++; } return result.ToString().Trim(); } } private static Win32Exception CreateWin32Exception(int errorCode, string context) { Win32Exception 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) { int iBytesReturned = 0; GETVERSIONINPARAMS gvi = new GETVERSIONINPARAMS(); if (DeviceIoControl(hDisk, SMART_GET_VERSION, IntPtr.Zero, 0, ref gvi, Marshal.SizeOf(gvi), ref iBytesReturned, 0) == 0) { return false; } return (gvi.fCapabilities & CAP_SMART_CMD) > 0; } public string SerialNumber { get { return GetSerialNumberUsingSmart(0); } } // =========== فراخواني اين كلاس در ماژول 1 } }