Getting Real hdd serial with out admin right is hard.
I've found this small piece of software, which does exactly that what I want to implement in C#.net. Luckily, the source code is also available.
Basically I would like to implement the function ReadIdeDriveAsScsiDriveInNT from diskid32 in C#.
How I communicate with the device:
public class HDDSerial
{
public const int FILE_DEVICE_SCSI = 0x0000001b;
public const int IOCTL_SCSI_MINIPORT_IDENTIFY = ((FILE_DEVICE_SCSI << 16) + 0x0501);
public const int IOCTL_SCSI_MINIPORT = 0x0004D008;
public const int ATA_IDENTIFY = 0xEC;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
SafeFileHandle device,
int inputOutputControlCode,
ref byte[] inputBuffer,
int inputBufferSize,
ref byte[] outputBuffer,
int outputBufferSize,
ref uint bytesCount,
int overlapped);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern SafeFileHandle CreateFile(string lpFileName,
FileAccess dwDesiredAccess,
FileShare dwShareMode,
uint lpSecurityAttributes,
FileMode dwCreationDisposition,
int flagsAndAttributes,
uint hTemplateFile);
[StructLayout(LayoutKind.Sequential, Size = 8)]
private class IDEREGS
{
public byte Features;
public byte SectorCount;
public byte SectorNumber;
public byte CylinderLow;
public byte CylinderHigh;
public byte DriveHead;
public byte Command;
public byte Reserved;
}
[StructLayout(LayoutKind.Sequential, Size = 32)]
private class SENDCMDINPARAMS
{
public int BufferSize;
public IDEREGS DriveRegs;
public byte DriveNumber;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] Reserved2;
public SENDCMDINPARAMS()
{
DriveRegs = new IDEREGS();
Reserved = new byte[3];
Reserved2 = new int[4];
}
}
[StructLayout(LayoutKind.Sequential, Size = 12)]
private class DRIVERSTATUS
{
public byte DriveError;
public byte IDEStatus;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public int[] Reserved2;
public DRIVERSTATUS()
{
Reserved = new byte[2];
Reserved2 = new int[2];
}
}
[StructLayout(LayoutKind.Sequential)]
private class IDSECTOR
{
public short GenConfig;
public short NumberCylinders;
public short Reserved;
public short NumberHeads;
public short BytesPerTrack;
public short BytesPerSector;
public short SectorsPerTrack;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public short[] VendorUnique;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public char[] SerialNumber;
public short BufferClass;
public short BufferSize;
public short ECCSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public char[] FirmwareRevision;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public char[] ModelNumber;
public short MoreVendorUnique;
public short DoubleWordIO;
public short Capabilities;
public short Reserved1;
public short PIOTiming;
public short DMATiming;
public short BS;
public short NumberCurrentCyls;
public short NumberCurrentHeads;
public short NumberCurrentSectorsPerTrack;
public int CurrentSectorCapacity;
public short MultipleSectorCapacity;
public short MultipleSectorStuff;
public int TotalAddressableSectors;
public short SingleWordDMA;
public short MultiWordDMA;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 382)]
public byte[] Reserved2;
public IDSECTOR()
{
VendorUnique = new short[3];
Reserved2 = new byte[382];
FirmwareRevision = new char[8];
SerialNumber = new char[20];
ModelNumber = new char[40];
}
}
[StructLayout(LayoutKind.Sequential)]
private class SENDCMDOUTPARAMS
{
public int BufferSize;
public DRIVERSTATUS Status;
public IDSECTOR IDS;
public SENDCMDOUTPARAMS()
{
Status = new DRIVERSTATUS();
IDS = new IDSECTOR();
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 512)]
public struct IDENTIFY_DATA
{
public ushort wGenConfig;
public ushort wNumCyls;
public ushort wReserved;
public ushort wNumHeads;
public ushort wBytesPerTrack;
public ushort wBytesPerSector;
public ushort wSectorsPerTrack;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public ushort[] wVendorUnique;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] sSerialNumber;
public ushort wBufferType;
public ushort wBufferSize;
public ushort wECCSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] sFirmwareRev;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] sModelNumber;
public ushort wMoreVendorUnique;
public ushort wDoubleWordIO;
public ushort wCapabilities;
public ushort wReservedl;
public ushort wPIOTiming;
public ushort wDMATiming;
public ushort wBS;
public ushort wNumCurrentCyls;
public ushort wNumCurrentHeads;
public ushort wNumCurrentSectorsPerTrack;
public uint ulCurrentSectorCapacity;
public ushort wMultSectorStuff;
public uint ulTotalAddressableSectors;
public ushort wSingleWordDMA;
public ushort wMultiWordDMA;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] bReserved;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SRB_IO_CONTROL
{
public uint HeaderLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Signature;
public uint Timeout;
public uint ControlCode;
public uint ReturnCode;
public uint Length;
}
private SafeFileHandle OpenScsi(int scsiNumber)
{
var device = CreateFile(
string.Format(@"\\.\Scsi{0}:", scsiNumber),
FileAccess.Read | FileAccess.Write,
FileShare.ReadWrite,
0,
FileMode.Open,
0,
0);
if (device.IsInvalid)
{
throw new Exception(string.Format(@"Error during the creation of a safe file handle for \\.\Scsi{0}:", scsiNumber));
}
return device;
}
public string Swap(string input)
{
var characters = input.ToCharArray();
var returnValue = new StringBuilder();
for (var i = 0; i < characters.Length; i++)
{
if (i % 2 != 0)
{
continue;
}
if ((i + 1) < characters.Length)
{
returnValue.Append(characters[i + 1]);
}
returnValue.Append(characters[i]);
}
return returnValue.ToString();
}
public string GetSerialNumberUsingMiniportDriver(int busNumber, byte deviceNumber = 0)
{
using (var device = OpenScsi(busNumber))
{
var bytesReturned = default(uint);
var sic = new SRB_IO_CONTROL();
var sop = new SENDCMDOUTPARAMS();
var sip = new SENDCMDINPARAMS();
var id = new IDENTIFY_DATA();
var buffer = new byte[Marshal.SizeOf(sic) + Marshal.SizeOf(sop) + Marshal.SizeOf(id)];
sic.HeaderLength = (uint)Marshal.SizeOf(sic);
sic.Timeout = 10000;
sic.Length = (uint)(Marshal.SizeOf(sop) + Marshal.SizeOf(id));
sic.ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
sic.Signature = Encoding.ASCII.GetBytes("SCSIDISK".ToCharArray());
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sic));
Marshal.StructureToPtr(sic, ptr, true);
Marshal.Copy(ptr, buffer, 0, Marshal.SizeOf(sic));
sip.DriveRegs.Command = (byte)ATA_IDENTIFY;
sip.DriveNumber = deviceNumber;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sip));
Marshal.StructureToPtr(sip, ptr, true);
Marshal.Copy(ptr, buffer, Marshal.SizeOf(sic), Marshal.SizeOf(sip));
if (
!DeviceIoControl(
device,
IOCTL_SCSI_MINIPORT,
ref buffer,
(int)(Marshal.SizeOf(sic) + Marshal.SizeOf(sip) - 1),
ref buffer,
(int)(Marshal.SizeOf(sic) + Marshal.SizeOf(sop) + Marshal.SizeOf(id)),
ref bytesReturned,
0))
{
throw new Exception("Device Io Error");
}
var resultPtr = Marshal.AllocHGlobal(Marshal.SizeOf(id));
Marshal.Copy(buffer, Marshal.SizeOf(sic) + Marshal.SizeOf(sop), resultPtr, Marshal.SizeOf(id));
id = (IDENTIFY_DATA)Marshal.PtrToStructure(resultPtr, typeof(IDENTIFY_DATA));
var model = Encoding.ASCII.GetString(id.sSerialNumber).Replace('\0', ' ').Trim();
model = Swap(model);
return model.Trim();
}
}
}
I found "Device Io Error" here. Please, Any suggestion or link that will help to solve this problem. Thank you...
User contributions licensed under CC BY-SA 3.0