Get Physical Drive Serial Number – Part 1

One frequently asked question is “how to (programmatically) get the serial number of a physical drive?” or “how to find my hard disk serial number?“.
One first simple attempt may be to call GetVolumeInformation. However, this function retrieves a serial number which is assigned by the operating system to a volume when it is formatted. It’s not what we want.
To get the serial number assigned to the hard disk (or another type of physical drive) by the manufacturer, we have to find other ways, like for example calling DeviceIoControl function or using Win32_PhysicalMedia WMI class.
Let’s begin with the first one.

Get serial number by using DeviceIoControl

To get the serial number of a physical drive, we can call DeviceIoControl with IOCTL_STORAGE_QUERY_PROPERTY control code.
Just follow these steps:

  1. Call CreateFile function to get a handle to physical drive. First argument (lpFileName) may be \\.\PhysicalDrive0, \\.\PhysicalDrive1, \\.\PhysicalDrive2… for drive #0, #1, #2, and so on.
  2. Set the STORAGE_PROPERTY_QUERY input data structure.
  3. Call DeviceIoControl once for retrieving necessary size, then allocate the output buffer.
  4. Call DeviceIoControl twice to get the storage device descriptor. The output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure, followed by additional info like vendor ID, product ID, serial number, and so on. The serial number is a null-terminated ASCII string located at SerialNumberOffset bytes counted form the beginning of the output buffer.

Now let’s put all together in an MFC sample application which gets then displays the serial number for physical drive #0.

Notes

  • The above example intentionally shows a “flat” global function, just for learning purpose. Of course, each one may improve it by using a more object-oriented approach.
  • May notice that STORAGE_DEVICE_DESCRIPTOR gets more info than serial number (device type, vendor ID, product ID, and so on). This is a subject of improving, as well.
  • Next article will describe how to get serial number using WMI (Windows Management Instrumentation).

See also

Resources

5 thoughts on “Get Physical Drive Serial Number – Part 1

  1. Pingback: Anonymous

  2. BELADEL ILYES ABDELRAZAK

    This is a very useful piece code, however I got strange output when I test it on WinXP, I believe this because it reads the hard disk as IDE.
    Here is a converted version that is a cross compiler friendly(VC, MinGW):

    DWORD GetPhysicalDriveSerialNumber(UINT nDriveNumber, std:string &strSerialNumber)
    {
    DWORD dwRet = NO_ERROR;

    // Format physical drive path (may be ‘\\.\PhysicalDrive0’, ‘\\.\PhysicalDrive1’ and so on).
    std::string strDrivePath;
    strDrivePath = “\\\\.\\PhysicalDrive%u” + QString::number(nDriveNumber).toStdString();

    // Get a handle to physical drive
    HANDLE hDevice = ::CreateFile(L”\\\\.\\PhysicalDrive0″, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
    NULL, OPEN_EXISTING, 0, NULL);

    if(INVALID_HANDLE_VALUE == hDevice)
    return ::GetLastError();

    // Set the input data structure
    STORAGE_PROPERTY_QUERY storagePropertyQuery;
    ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY));
    storagePropertyQuery.PropertyId = StorageDeviceProperty;
    storagePropertyQuery.QueryType = PropertyStandardQuery;

    // Get the necessary output buffer size
    STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = {0};
    DWORD dwBytesReturned = 0;
    if(! ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
    &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
    &storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER),
    &dwBytesReturned, NULL))
    {
    dwRet = ::GetLastError();
    ::CloseHandle(hDevice);
    return dwRet;
    }

    // Alloc the output buffer
    const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
    BYTE* pOutBuffer = new BYTE[dwOutBufferSize];
    ZeroMemory(pOutBuffer, dwOutBufferSize);

    // Get the storage device descriptor
    if(! ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
    &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
    pOutBuffer, dwOutBufferSize,
    &dwBytesReturned, NULL))
    {
    dwRet = ::GetLastError();
    delete []pOutBuffer;
    ::CloseHandle(hDevice);
    return dwRet;
    }

    // Now, the output buffer points to a STORAGE_DEVICE_DESCRIPTOR structure
    // followed by additional info like vendor ID, product ID, serial number, and so on.
    STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer;
    const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
    if(dwSerialNumberOffset != 0)
    {
    // Finally, get the serial number
    //strSerialNumbe = string(pOutBuffer + dwSerialNumberOffset);
    strSerialNumber = std::string( reinterpret_cast(pOutBuffer + dwSerialNumberOffset) ) ;
    }

    // Do cleanup and return
    delete []pOutBuffer;
    ::CloseHandle(hDevice);
    return dwRet;
    }

    Reply

Leave a Reply