windows平台c++获取硬盘序列号(msys环境)

windows平台c++获取硬盘序列号(msys环境)

vmware虚拟机环境有时候获取不到硬盘序列号,设置后可以,参见:https://jingyan.baidu.com/article/cbcede07d345db43f40b4d88.html

本文参考:https://blog.csdn.net/yanchenyu365/article/details/85061879

1.makefile文件

app : HardDrive.cpp HardDriveSerialNumer.cpp
    g++ -w -o $@ $^

2.main函数文件:HardDrive.cpp

#include "HardDriveSerialNumer.hpp"
#include <iostream>
#include <string.h>

int main()
{
    char SerialNumber[1024] = {""};
    memset(&SerialNumber, 0, sizeof(SerialNumber));

    MasterHardDiskSerial a;
    int ret = a.GetSerialNo(SerialNumber);

    if (ret == 0)
    {
        std::cout << "SN " << SerialNumber << std::endl;
    }
    else
    {
        std::cout << "can't get sn" << std::endl;
    }
}

3.头文件:HardDriveSerialNumer.hpp

#ifndef _HDD_SERIAL_INFO_H_
#define _HDD_SERIAL_INFO_H_

#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <vector>
#include <windows.h>
#include <winioctl.h>

#pragma pack(1)

#define IDENTIFY_BUFFER_SIZE 512

//  IOCTL commands
#define DFP_GET_VERSION 0x00074080
#define DFP_SEND_DRIVE_COMMAND 0x0007c084
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088

#define FILE_DEVICE_SCSI 0x0000001b
#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)
#define IOCTL_SCSI_MINIPORT 0x0004D008 //  see NTDDSCSI.H for definition

#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)
#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

//  GETVERSIONOUTPARAMS contains the data returned from the
//  Get Driver Version function.
typedef struct _GETVERSIONOUTPARAMS
{
    BYTE bVersion;       // Binary driver version.
    BYTE bRevision;      // Binary driver revision.
    BYTE bReserved;      // Not used.
    BYTE bIDEDeviceMap;  // Bit map of IDE devices.
    DWORD fCapabilities; // Bit mask of driver capabilities.
    DWORD dwReserved[4]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;

//  Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
#define CAP_IDE_ID_FUNCTION 1            // ATA ID command supported
#define CAP_IDE_ATAPI_ID 2               // ATAPI ID command supported
#define CAP_IDE_EXECUTE_SMART_FUNCTION 4 // SMART commannds supported

//  Valid values for the bCommandReg member of IDEREGS.
#define IDE_ATAPI_IDENTIFY 0xA1 //  Returns ID sector for ATAPI.
#define IDE_ATA_IDENTIFY 0xEC   //  Returns ID sector for ATA.

// The following struct defines the interesting part of the IDENTIFY
// buffer:
typedef struct _IDSECTOR
{
    USHORT wGenConfig;
    USHORT wNumCyls;
    USHORT wReserved;
    USHORT wNumHeads;
    USHORT wBytesPerTrack;
    USHORT wBytesPerSector;
    USHORT wSectorsPerTrack;
    USHORT wVendorUnique[3];
    CHAR sSerialNumber[20];
    USHORT wBufferType;
    USHORT wBufferSize;
    USHORT wECCSize;
    CHAR sFirmwareRev[8];
    CHAR sModelNumber[40];
    USHORT wMoreVendorUnique;
    USHORT wDoubleWordIO;
    USHORT wCapabilities;
    USHORT wReserved1;
    USHORT wPIOTiming;
    USHORT wDMATiming;
    USHORT wBS;
    USHORT wNumCurrentCyls;
    USHORT wNumCurrentHeads;
    USHORT wNumCurrentSectorsPerTrack;
    ULONG ulCurrentSectorCapacity;
    USHORT wMultSectorStuff;
    ULONG ulTotalAddressableSectors;
    USHORT wSingleWordDMA;
    USHORT wMultiWordDMA;
    BYTE bReserved[128];
} IDSECTOR, *PIDSECTOR;

typedef struct _SRB_IO_CONTROL
{
    ULONG HeaderLength;
    UCHAR Signature[8];
    ULONG Timeout;
    ULONG ControlCode;
    ULONG ReturnCode;
    ULONG Length;
} SRB_IO_CONTROL, *PSRB_IO_CONTROL;

//  Max number of drives assuming primary/secondary, master/slave topology
//    Modified to read only the master serial
#define MAX_IDE_DRIVES 1

//
// IDENTIFY data (from ATAPI driver source)
//

#pragma pack(1)

typedef struct _IDENTIFY_DATA
{
    USHORT GeneralConfiguration;       // 00 00
    USHORT NumberOfCylinders;          // 02  1
    USHORT Reserved1;                  // 04  2
    USHORT NumberOfHeads;              // 06  3
    USHORT UnformattedBytesPerTrack;   // 08  4
    USHORT UnformattedBytesPerSector;  // 0A  5
    USHORT SectorsPerTrack;            // 0C  6
    USHORT VendorUnique1[3];           // 0E  7-9
    USHORT SerialNumber[10];           // 14  10-19
    USHORT BufferType;                 // 28  20
    USHORT BufferSectorSize;           // 2A  21
    USHORT NumberOfEccBytes;           // 2C  22
    USHORT FirmwareRevision[4];        // 2E  23-26
    USHORT ModelNumber[20];            // 36  27-46
    UCHAR MaximumBlockTransfer;        // 5E  47
    UCHAR VendorUnique2;               // 5F
    USHORT DoubleWordIo;               // 60  48
    USHORT Capabilities;               // 62  49
    USHORT Reserved2;                  // 64  50
    UCHAR VendorUnique3;               // 66  51
    UCHAR PioCycleTimingMode;          // 67
    UCHAR VendorUnique4;               // 68  52
    UCHAR DmaCycleTimingMode;          // 69
    USHORT TranslationFieldsValid : 1; // 6A  53
    USHORT Reserved3 : 15;
    USHORT NumberOfCurrentCylinders;  // 6C  54
    USHORT NumberOfCurrentHeads;      // 6E  55
    USHORT CurrentSectorsPerTrack;    // 70  56
    ULONG CurrentSectorCapacity;      // 72  57-58
    USHORT CurrentMultiSectorSetting; //     59
    ULONG UserAddressableSectors;     //     60-61
    USHORT SingleWordDMASupport : 8;  //     62
    USHORT SingleWordDMAActive : 8;
    USHORT MultiWordDMASupport : 8; //     63
    USHORT MultiWordDMAActive : 8;
    USHORT AdvancedPIOModes : 8; //     64
    USHORT Reserved4 : 8;
    USHORT MinimumMWXferCycleTime;     //     65
    USHORT RecommendedMWXferCycleTime; //     66
    USHORT MinimumPIOCycleTime;        //     67
    USHORT MinimumPIOCycleTimeIORDY;   //     68
    USHORT Reserved5[2];               //     69-70
    USHORT ReleaseTimeOverlapped;      //     71
    USHORT ReleaseTimeServiceCommand;  //     72
    USHORT MajorRevision;              //     73
    USHORT MinorRevision;              //     74
    USHORT Reserved6[50];              //     75-126
    USHORT SpecialFunctionsEnabled;    //     127
    USHORT Reserved7[128];             //     128-255
} IDENTIFY_DATA, *PIDENTIFY_DATA;

#pragma pack()

//  Required to ensure correct PhysicalDrive IOCTL structure setup
#pragma pack(4)

//
// IOCTL_STORAGE_QUERY_PROPERTY
//
// Input Buffer:
//      a STORAGE_PROPERTY_QUERY structure which describes what type of query
//      is being done, what property is being queried for, and any additional
//      parameters which a particular property query requires.
//
//  Output Buffer:
//      Contains a buffer to place the results of the query into.  Since all
//      property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER,
//      the IOCTL can be called once with a small buffer then again using
//      a buffer as large as the header reports is necessary.
//

//
// Types of queries
//

//
// define some initial property id's
//

//
// Query structure - additional parameters for specific queries can follow
// the header
//

#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)

//
// Device property descriptor - this is really just a rehash of the inquiry
// data retrieved from a scsi device
//
// This may only be retrieved from a target device.  Sending this to the bus
// will result in an error
//

#pragma pack(4)

// (* Output Bbuffer for the VxD (rt_IdeDinfo record) *)
typedef struct _rt_IdeDInfo_
{
    BYTE IDEExists[4];
    BYTE DiskExists[8];
    WORD DisksRawInfo[8 * 256];
} rt_IdeDInfo, *pt_IdeDInfo;

// (* IdeDinfo "data fields" *)
typedef struct _rt_DiskInfo_
{
    BOOL DiskExists;
    BOOL ATAdevice;
    BOOL RemovableDevice;
    WORD TotLogCyl;
    WORD TotLogHeads;
    WORD TotLogSPT;
    char SerialNumber[20];
    char FirmwareRevision[8];
    char ModelNumber[40];
    WORD CurLogCyl;
    WORD CurLogHeads;
    WORD CurLogSPT;
} rt_DiskInfo;

#define SENDIDLENGTH sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE
#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)

class MasterHardDiskSerial
{
public:
    MasterHardDiskSerial();
    ~MasterHardDiskSerial();
    //int GetSerialNo(std::vector<char> &serialNumber);
    int GetSerialNo(char *SerialNumber);
    int GetErrorMessage(TCHAR *_ptszErrorMessage = NULL);

private:
    char *ConvertToString(DWORD dwDiskdata[256], int iFirstIndex, int iLastIndex, char *pcBuf = NULL);
    BOOL DoIDENTIFY(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE, BYTE, PDWORD);
    int ReadPhysicalDriveInNTWithAdminRights(void);
    int ReadPhysicalDriveInNTUsingSmart(void);
    int ReadPhysicalDriveInNTWithZeroRights(void);
    int ReadIdeDriveAsScsiDriveInNT(void);
    char *flipAndCodeBytes(int iPos, int iFlip, const char *pcStr = NULL, char *pcBuf = NULL);
    void PrintIdeInfo(int iDrive, DWORD dwDiskdata[256]);
    long getHardDriveComputerID();

private:
    char m_cszHardDriveSerialNumber[1024];
    char m_cszHardDriveModelNumber[1024];
    char m_cszErrorMessage[256];
    BYTE byIdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
};

#endif // _HDD_SERIAL_INFO_H_

4.实现文件:HardDriveSerialNumer.hpp

//#include "pch.h" //vs控制台项目自动生成
#include "HardDriveSerialNumer.hpp"
#include <iostream>

int MasterHardDiskSerial::ReadPhysicalDriveInNTWithAdminRights(void)
{
   int iDone = FALSE;
   int iDrive = 0;

   for (iDrive = 0; iDrive < MAX_IDE_DRIVES; iDrive++)
   {
      HANDLE hPhysicalDriveIOCTL = 0;

      //  Try to get a handle to PhysicalDrive IOCTL, report failure
      //  and exit if can't.
      char cszDriveName[256];

      sprintf_s(cszDriveName, 256, "\\.\PhysicalDrive%d", iDrive);

      //  Windows NT, Windows 2000, must have admin rights
      hPhysicalDriveIOCTL = CreateFileA(cszDriveName,
                                        GENERIC_READ | GENERIC_WRITE,
                                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                        OPEN_EXISTING, 0, NULL);
      if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
      {
         SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
         sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR ,CreateFileA(%s) returned INVALID_HANDLE_VALUE", __LINE__, cszDriveName);
      }
      else
      {
         GETVERSIONOUTPARAMS VersionParams;
         DWORD dwBytesReturned = 0;

         // Get the version, etc of PhysicalDrive IOCTL
         memset((void *)&VersionParams, 0, sizeof(VersionParams));

         if (!DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION,
                              NULL,
                              0,
                              &VersionParams,
                              sizeof(VersionParams),
                              &dwBytesReturned, NULL))
         {

            DWORD dwErr = GetLastError();
            SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));

            sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR DeviceIoControl() %ld, DFP_GET_VERSION) returned 0, error is %d
", __LINE__, (long long)hPhysicalDriveIOCTL, (int)dwErr);
         }

         // If there is a IDE device at number "iI" issue commands
         // to the device
         if (VersionParams.bIDEDeviceMap <= 0)
         {
            SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
            sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithAdminRights ERROR No device found at iPosition %d (%d)", __LINE__, (int)iDrive, (int)VersionParams.bIDEDeviceMap);
         }
         else
         {
            BYTE bIDCmd = 0; // IDE or ATAPI IDENTIFY cmd
            SENDCMDINPARAMS scip;
            //SENDCMDOUTPARAMS OutCmd;

            // Now, get the ID sector for all IDE devices in the system.
            // If the device is ATAPI use the IDE_ATAPI_IDENTIFY command,
            // otherwise use the IDE_ATA_IDENTIFY command
            bIDCmd = (VersionParams.bIDEDeviceMap >> iDrive & 0x10) ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;

            memset(&scip, 0, sizeof(scip));
            memset(byIdOutCmd, 0, sizeof(byIdOutCmd));

            if (DoIDENTIFY(hPhysicalDriveIOCTL,
                           &scip,
                           (PSENDCMDOUTPARAMS)&byIdOutCmd,
                           (BYTE)bIDCmd,
                           (BYTE)iDrive,
                           &dwBytesReturned))
            {
               DWORD dwDiskData[256];
               int iIjk = 0;
               USHORT *punIdSector = (USHORT *)((PSENDCMDOUTPARAMS)byIdOutCmd)->bBuffer;

               for (iIjk = 0; iIjk < 256; iIjk++)
                  dwDiskData[iIjk] = punIdSector[iIjk];

               PrintIdeInfo(iDrive, dwDiskData);

               iDone = TRUE;
            }
         }

         CloseHandle(hPhysicalDriveIOCTL);
      }
   }

   return iDone;
}

int MasterHardDiskSerial::ReadPhysicalDriveInNTUsingSmart(void)
{
   int iDone = FALSE;
   int iDrive = 0;

   for (iDrive = 0; iDrive < MAX_IDE_DRIVES; iDrive++)
   {
      HANDLE hPhysicalDriveIOCTL = 0;

      //  Try to get a handle to PhysicalDrive IOCTL, report failure
      //  and exit if can't.
      char cszDriveName[256];

      sprintf_s(cszDriveName, 256, "\\.\PhysicalDrive%d", iDrive);

      //  Windows NT, Windows 2000, Windows Server 2003, Vista
      hPhysicalDriveIOCTL = CreateFileA(cszDriveName,
                                        GENERIC_READ | GENERIC_WRITE,
                                        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                                        NULL, OPEN_EXISTING, 0, NULL);
      // if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
      //    printf ("Unable to open physical iDrive %d, error code: 0x%lX
",
      //            iDrive, GetLastError ());

      if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
      {
         SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
         sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTUsingSmart ERROR, CreateFileA(%s) returned INVALID_HANDLE_VALUE Error Code %d", __LINE__, cszDriveName, GetLastError());
      }
      else
      {
         GETVERSIONINPARAMS GetVersionParams;
         DWORD dwBytesReturned = 0;

         // Get the version, etc of PhysicalDrive IOCTL
         memset((void *)&GetVersionParams, 0, sizeof(GetVersionParams));

         if (!DeviceIoControl(hPhysicalDriveIOCTL, SMART_GET_VERSION,
                              NULL,
                              0,
                              &GetVersionParams, sizeof(GETVERSIONINPARAMS),
                              &dwBytesReturned, NULL))
         {
            DWORD dwErr = GetLastError();
            SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
            sprintf_s(m_cszErrorMessage, 256, "
%d ReadPhysicalDriveInNTUsingSmart ERROR DeviceIoControl(%ld, SMART_GET_VERSION) returned 0, error is %d", __LINE__, (long long)hPhysicalDriveIOCTL, (int)dwErr);
         }
         else
         {
            // Print the SMART version
            // PrintVersion (& GetVersionParams);
            // Allocate the command cszBuffer
            ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;
            PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS)malloc(CommandSize);
            // Retrieve the IDENTIFY data
            // Prepare the command
#define ID_CMD 0xEC // Returns ID sector for ATA
            Command->irDriveRegs.bCommandReg = ID_CMD;
            DWORD BytesReturned = 0;
            if (!DeviceIoControl(hPhysicalDriveIOCTL,
                                 SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),
                                 Command, CommandSize,
                                 &BytesReturned, NULL))
            {
               SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
               sprintf_s(m_cszErrorMessage, 256, "SMART_RCV_DRIVE_DATA IOCTL");

               // Print the error
               //PrintError ("SMART_RCV_DRIVE_DATA IOCTL", GetLastError());
            }
            else
            {
               // Print the IDENTIFY data
               DWORD dwDiskData[256];
               USHORT *punIdSector = (USHORT *)(PIDENTIFY_DATA)((PSENDCMDOUTPARAMS)Command)->bBuffer;

               for (int iIjk = 0; iIjk < 256; iIjk++)
                  dwDiskData[iIjk] = punIdSector[iIjk];

               PrintIdeInfo(iDrive, dwDiskData);
               iDone = TRUE;
            }
            // Done
            CloseHandle(hPhysicalDriveIOCTL);
            free(Command);
         }
      }
   }

   return iDone;
}

char *MasterHardDiskSerial::flipAndCodeBytes(int iPos, int iFlip, const char *pcszStr, char *pcszBuf)
{
   int iI;
   int iJ = 0;
   int iK = 0;

   pcszBuf[0] = '';
   if (iPos <= 0)
      return pcszBuf;

   if (!iJ)
   {
      char cP = 0;
      // First try to gather all characters representing hex digits only.
      iJ = 1;
      iK = 0;
      pcszBuf[iK] = 0;
      for (iI = iPos; iJ && !(pcszStr[iI] == ''); ++iI)
      {
         char cC = tolower(pcszStr[iI]);
         if (isspace(cC))
            cC = '0';
         ++cP;
         pcszBuf[iK] <<= 4;

         if (cC >= '0' && cC <= '9')
            pcszBuf[iK] |= (char)(cC - '0');
         else if (cC >= 'a' && cC <= 'f')
            pcszBuf[iK] |= (char)(cC - 'a' + 10);
         else
         {
            iJ = 0;
            break;
         }

         if (cP == 2)
         {
            if ((pcszBuf[iK] != '') && !isprint(pcszBuf[iK]))
            {
               iJ = 0;
               break;
            }
            ++iK;
            cP = 0;
            pcszBuf[iK] = 0;
         }
      }
   }

   if (!iJ)
   {
      // There are non-digit characters, gather them as is.
      iJ = 1;
      iK = 0;
      for (iI = iPos; iJ && (pcszStr[iI] != ''); ++iI)
      {
         char cC = pcszStr[iI];

         if (!isprint(cC))
         {
            iJ = 0;
            break;
         }

         pcszBuf[iK++] = cC;
      }
   }

   if (!iJ)
   {
      // The characters are not there or are not printable.
      iK = 0;
   }

   pcszBuf[iK] = '';

   if (iFlip)
      // Flip adjacent characters
      for (iJ = 0; iJ < iK; iJ += 2)
      {
         char t = pcszBuf[iJ];
         pcszBuf[iJ] = pcszBuf[iJ + 1];
         pcszBuf[iJ + 1] = t;
      }

   // Trim any beginning and end space
   iI = iJ = -1;
   for (iK = 0; (pcszBuf[iK] != ''); ++iK)
   {
      if (!isspace(pcszBuf[iK]))
      {
         if (iI < 0)
            iI = iK;
         iJ = iK;
      }
   }

   if ((iI >= 0) && (iJ >= 0))
   {
      for (iK = iI; (iK <= iJ) && (pcszBuf[iK] != ''); ++iK)
         pcszBuf[iK - iI] = pcszBuf[iK];
      pcszBuf[iK - iI] = '';
   }

   return pcszBuf;
}

int MasterHardDiskSerial::ReadPhysicalDriveInNTWithZeroRights(void)
{
   int iDone = FALSE;
   int iDrive = 0;

   for (iDrive = 0; iDrive < MAX_IDE_DRIVES; iDrive++)
   {
      HANDLE hPhysicalDriveIOCTL = 0;

      //  Try to get a handle to PhysicalDrive IOCTL, report failure
      //  and exit if can't.
      char cszDriveName[256];

      sprintf_s(cszDriveName, 256, "\\.\PhysicalDrive%d", iDrive);

      //  Windows NT, Windows 2000, Windows XP - admin rights not required
      hPhysicalDriveIOCTL = CreateFileA(cszDriveName, 0,
                                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                        OPEN_EXISTING, 0, NULL);
      if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
      {
         SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
         sprintf_s(m_cszErrorMessage, 256, "%d ReadPhysicalDriveInNTWithZeroRights ERROR CreateFileA(%s) returned INVALID_HANDLE_VALUE", __LINE__, cszDriveName);
      }
      else
      {
         STORAGE_PROPERTY_QUERY query;
         DWORD dwBytesReturned = 0;
         char cszBuffer[10000];

         memset((void *)&query, 0, sizeof(query));
         query.PropertyId = StorageDeviceProperty;
         query.QueryType = PropertyStandardQuery;

         memset(cszBuffer, 0, sizeof(cszBuffer));

         if (DeviceIoControl(hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,
                             &query,
                             sizeof(query),
                             &cszBuffer,
                             sizeof(cszBuffer),
                             &dwBytesReturned, NULL))
         {
            STORAGE_DEVICE_DESCRIPTOR *descrip = (STORAGE_DEVICE_DESCRIPTOR *)&cszBuffer;
            char cszSerialNumber[1000];
            char cszModelNumber[1000];
            char cszVendorId[1000];
            char cszProductRevision[1000];

            flipAndCodeBytes(descrip->VendorIdOffset,
                             0, cszBuffer, cszVendorId);
            flipAndCodeBytes(descrip->ProductIdOffset,
                             0, cszBuffer, cszModelNumber);
            flipAndCodeBytes(descrip->ProductRevisionOffset,
                             0, cszBuffer, cszProductRevision);
            flipAndCodeBytes(descrip->SerialNumberOffset,
                             0, cszBuffer, cszSerialNumber);

            if (0 == m_cszHardDriveSerialNumber[0] &&
                //  serial number must be alphanumeric
                //  (but there can be leading spaces on IBM drives)
                (iswalnum(cszSerialNumber[0]) || iswalnum(cszSerialNumber[19])))
            {
               strcpy_s(m_cszHardDriveSerialNumber, 1024, cszSerialNumber);
               strcpy_s(m_cszHardDriveModelNumber, 1024, cszModelNumber);
               iDone = TRUE;
            }
            // Get the disk iDrive geometry.
            memset(cszBuffer, 0, sizeof(cszBuffer));
            if (!DeviceIoControl(hPhysicalDriveIOCTL,
                                 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
                                 NULL,
                                 0,
                                 &cszBuffer,
                                 sizeof(cszBuffer),
                                 &dwBytesReturned,
                                 NULL))
            {
               SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
               sprintf_s(m_cszErrorMessage, "%s ReadPhysicalDriveInNTWithZeroRights ERROR DeviceIoControl(), IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) returned 0", cszDriveName);
            }
            else
            {
               DISK_GEOMETRY_EX *geom = (DISK_GEOMETRY_EX *)&cszBuffer;
               int iFixed = (geom->Geometry.MediaType == FixedMedia);
               __int64 i64Size = geom->DiskSize.QuadPart;
            }
         }
         else
         {
            DWORD dwErr = GetLastError();
            SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
            sprintf_s(m_cszErrorMessage, "DeviceIOControl IOCTL_STORAGE_QUERY_PROPERTY error = %d
", dwErr);
         }

         CloseHandle(hPhysicalDriveIOCTL);
      }
   }

   return iDone;
}

BOOL MasterHardDiskSerial::DoIDENTIFY(HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
                                      PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
                                      PDWORD lpcbBytesReturned)
{
   // Set up data structures for IDENTIFY command.
   pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;
   pSCIP->irDriveRegs.bFeaturesReg = 0;
   pSCIP->irDriveRegs.bSectorCountReg = 1;
   //pSCIP -> irDriveRegs.bSectorNumberReg = 1;
   pSCIP->irDriveRegs.bCylLowReg = 0;
   pSCIP->irDriveRegs.bCylHighReg = 0;

   // Compute the iDrive number.
   pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

   // The command can either be IDE identify or ATAPI identify.
   pSCIP->irDriveRegs.bCommandReg = bIDCmd;
   pSCIP->bDriveNumber = bDriveNum;
   pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;

   return (DeviceIoControl(hPhysicalDriveIOCTL, DFP_RECEIVE_DRIVE_DATA,
                           (LPVOID)pSCIP,
                           sizeof(SENDCMDINPARAMS) - 1,
                           (LPVOID)pSCOP,
                           sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
                           lpcbBytesReturned, NULL));
}

int MasterHardDiskSerial::ReadIdeDriveAsScsiDriveInNT(void)
{
   int iDone = FALSE;
   int iController = 0;

   for (iController = 0; iController < 2; iController++)
   {
      HANDLE hScsiDriveIOCTL = 0;
      char cszDriveName[256];

      //  Try to get a handle to PhysicalDrive IOCTL, report failure
      //  and exit if can't.
      sprintf_s(cszDriveName, "\\.\Scsi%d:", iController);

      //  Windows NT, Windows 2000, any rights should do
      hScsiDriveIOCTL = CreateFileA(cszDriveName,
                                    GENERIC_READ | GENERIC_WRITE,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                    OPEN_EXISTING, 0, NULL);

      if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)
      {
         int iDrive = 0;

         for (iDrive = 0; iDrive < 2; iDrive++)
         {
            char cszBuffer[sizeof(SRB_IO_CONTROL) + SENDIDLENGTH];
            SRB_IO_CONTROL *cP = (SRB_IO_CONTROL *)cszBuffer;
            SENDCMDINPARAMS *pin =
                (SENDCMDINPARAMS *)(cszBuffer + sizeof(SRB_IO_CONTROL));
            DWORD dwDummy;

            memset(cszBuffer, 0, sizeof(cszBuffer));
            cP->HeaderLength = sizeof(SRB_IO_CONTROL);
            cP->Timeout = 10000;
            cP->Length = SENDIDLENGTH;
            cP->ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
            strncpy((char *)cP->Signature, "SCSIDISK", 8);

            pin->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
            pin->bDriveNumber = iDrive;

            if (DeviceIoControl(hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
                                cszBuffer,
                                sizeof(SRB_IO_CONTROL) +
                                    sizeof(SENDCMDINPARAMS) - 1,
                                cszBuffer,
                                sizeof(SRB_IO_CONTROL) + SENDIDLENGTH,
                                &dwDummy, NULL))
            {
               SENDCMDOUTPARAMS *pOut =
                   (SENDCMDOUTPARAMS *)(cszBuffer + sizeof(SRB_IO_CONTROL));
               IDSECTOR *pId = (IDSECTOR *)(pOut->bBuffer);
               if (pId->sModelNumber[0])
               {
                  DWORD dwDiskData[256];
                  int iIjk = 0;
                  USHORT *punIdSector = (USHORT *)pId;

                  for (iIjk = 0; iIjk < 256; iIjk++)
                     dwDiskData[iIjk] = punIdSector[iIjk];

                  PrintIdeInfo(iController * 2 + iDrive, dwDiskData);

                  iDone = TRUE;
               }
            }
         }
         CloseHandle(hScsiDriveIOCTL);
      }
   }

   return iDone;
}

void MasterHardDiskSerial::PrintIdeInfo(int iDrive, DWORD dwDiskData[256])
{
   char cszSerialNumber[1024];
   char cszModelNumber[1024];
   char cszRevisionNumber[1024];
   char bufferSize[32];

   __int64 i64Sectors = 0;
   __int64 i64Byte = 0;

   //  copy the hard iDrive serial number to the cszBuffer
   ConvertToString(dwDiskData, 10, 19, cszSerialNumber);
   ConvertToString(dwDiskData, 27, 46, cszModelNumber);
   ConvertToString(dwDiskData, 23, 26, cszRevisionNumber);
   sprintf_s(bufferSize, 32, "%u", dwDiskData[21] * 512);

   if (0 == m_cszHardDriveSerialNumber[0] &&
       //  serial number must be alphanumeric
       //  (but there can be leading spaces on IBM drives)
       (isalnum(cszSerialNumber[0]) || isalnum(cszSerialNumber[19])))
   {
      strcpy_s(m_cszHardDriveSerialNumber, 1024, cszSerialNumber);
      strcpy_s(m_cszHardDriveModelNumber, 1024, cszModelNumber);
   }
}

long MasterHardDiskSerial::getHardDriveComputerID()
{
   int iDone = FALSE;
   // char string [1024];
   __int64 i64Id = 0;
   OSVERSIONINFO version;

   strcpy_s(m_cszHardDriveSerialNumber, 1024, "");

   memset(&version, 0, sizeof(version));
   version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
   GetVersionEx(&version);
   if (version.dwPlatformId == VER_PLATFORM_WIN32_NT)
   {
      //  this works under WinNT4 or Win2K if you have admin rights
      iDone = ReadPhysicalDriveInNTWithAdminRights();

      //  this should work in WinNT or Win2K if previous did not work
      //  this is kind of a backdoor via the SCSI mini port driver into
      //     the IDE drives
      if (!iDone)
         iDone = ReadIdeDriveAsScsiDriveInNT();

      //  this works under WinNT4 or Win2K or WinXP if you have any rights
      if (!iDone)
         iDone = ReadPhysicalDriveInNTWithZeroRights();

      //  this works under WinNT4 or Win2K or WinXP or Windows Server 2003 or Vista if you have any rights
      if (!iDone)
         iDone = ReadPhysicalDriveInNTUsingSmart();
   }

   if (m_cszHardDriveSerialNumber[0] > 0)
   {
      char *cP = m_cszHardDriveSerialNumber;

      //  ignore first 5 characters from western digital hard drives if
      //  the first four characters are WD-W
      if (!strncmp(m_cszHardDriveSerialNumber, "WD-W", 4))
         cP += 5;
      for (; cP && *cP; cP++)
      {
         if ('-' == *cP)
            continue;
         i64Id *= 10;
         switch (*cP)
         {
         case '0':
            i64Id += 0;
            break;
         case '1':
            i64Id += 1;
            break;
         case '2':
            i64Id += 2;
            break;
         case '3':
            i64Id += 3;
            break;
         case '4':
            i64Id += 4;
            break;
         case '5':
            i64Id += 5;
            break;
         case '6':
            i64Id += 6;
            break;
         case '7':
            i64Id += 7;
            break;
         case '8':
            i64Id += 8;
            break;
         case '9':
            i64Id += 9;
            break;
         case 'a':
         case 'A':
            i64Id += 10;
            break;
         case 'b':
         case 'B':
            i64Id += 11;
            break;
         case 'c':
         case 'C':
            i64Id += 12;
            break;
         case 'd':
         case 'D':
            i64Id += 13;
            break;
         case 'e':
         case 'E':
            i64Id += 14;
            break;
         case 'f':
         case 'F':
            i64Id += 15;
            break;
         case 'g':
         case 'G':
            i64Id += 16;
            break;
         case 'h':
         case 'H':
            i64Id += 17;
            break;
         case 'i':
         case 'I':
            i64Id += 18;
            break;
         case 'j':
         case 'J':
            i64Id += 19;
            break;
         case 'k':
         case 'K':
            i64Id += 20;
            break;
         case 'l':
         case 'L':
            i64Id += 21;
            break;
         case 'm':
         case 'M':
            i64Id += 22;
            break;
         case 'n':
         case 'N':
            i64Id += 23;
            break;
         case 'o':
         case 'O':
            i64Id += 24;
            break;
         case 'p':
         case 'P':
            i64Id += 25;
            break;
         case 'q':
         case 'Q':
            i64Id += 26;
            break;
         case 'r':
         case 'R':
            i64Id += 27;
            break;
         case 's':
         case 'S':
            i64Id += 28;
            break;
         case 't':
         case 'T':
            i64Id += 29;
            break;
         case 'u':
         case 'U':
            i64Id += 30;
            break;
         case 'v':
         case 'V':
            i64Id += 31;
            break;
         case 'w':
         case 'W':
            i64Id += 32;
            break;
         case 'x':
         case 'X':
            i64Id += 33;
            break;
         case 'y':
         case 'Y':
            i64Id += 34;
            break;
         case 'z':
         case 'Z':
            i64Id += 35;
            break;
         }
      }
   }

   i64Id %= 100000000;
   if (strstr(m_cszHardDriveModelNumber, "IBM-"))
      i64Id += 300000000;
   else if (strstr(m_cszHardDriveModelNumber, "MAXTOR") ||
            strstr(m_cszHardDriveModelNumber, "Maxtor"))
      i64Id += 400000000;
   else if (strstr(m_cszHardDriveModelNumber, "WDC "))
      i64Id += 500000000;
   else
      i64Id += 600000000;

   return (long)i64Id;
}

//int MasterHardDiskSerial::GetSerialNo(std::vector<char> &serialNumber)
int MasterHardDiskSerial::GetSerialNo(char *SerialNumber)
{
   getHardDriveComputerID();
   size_t numberLength = strlen(m_cszHardDriveSerialNumber);
   if (numberLength == 0)
      return -1;
   //serialNumber.resize(numberLength);
   //std::cout << "size " << serialNumber.size() << std::endl;
   //memcpy(&serialNumber.front(), m_cszHardDriveSerialNumber, serialNumber.size()); //m_cszHardDriveSerialNumber;
   memcpy(SerialNumber, m_cszHardDriveSerialNumber, numberLength);
   return 0;
}

char *MasterHardDiskSerial::ConvertToString(DWORD dwDiskData[256],
                                            int iFirstIndex,
                                            int iLastIndex,
                                            char *pcszBuf)
{
   int iIndex = 0;
   int iPosition = 0;

   //  each integer has two characters stored in it backwards

   // Removes the spaces from the serial no
   for (iIndex = iFirstIndex; iIndex <= iLastIndex; iIndex++)
   {
      //  get high byte for 1st character
      char ctemp = (char)(dwDiskData[iIndex] / 256);
      char cszmyspace[] = " ";
      if (!(ctemp == *cszmyspace))
      {
         pcszBuf[iPosition++] = ctemp;
      }
      //  get low byte for 2nd character
      char ctemp1 = (char)(dwDiskData[iIndex] % 256);
      if (!(ctemp1 == *cszmyspace))
      {
         pcszBuf[iPosition++] = ctemp1;
      }
   }

   //  end the string
   pcszBuf[iPosition] = '';

   //  cut off the trailing blanks
   for (iIndex = iPosition - 1; iIndex > 0 && isspace(pcszBuf[iIndex]); iIndex--)
      pcszBuf[iIndex] = '';

   return pcszBuf;
}

int MasterHardDiskSerial::GetErrorMessage(TCHAR *tszErrorMessage)
{
   if (strlen(m_cszErrorMessage) != 0)
   {
      mbstowcs((wchar_t *)tszErrorMessage, m_cszErrorMessage, sizeof(m_cszErrorMessage));
      return 0;
   }
   else
      return -1;
}

MasterHardDiskSerial::MasterHardDiskSerial()
{
   SecureZeroMemory(m_cszErrorMessage, sizeof(m_cszErrorMessage));
   SecureZeroMemory(m_cszHardDriveModelNumber, sizeof(m_cszHardDriveModelNumber));
   SecureZeroMemory(m_cszHardDriveSerialNumber, sizeof(m_cszHardDriveSerialNumber));
}

MasterHardDiskSerial::~MasterHardDiskSerial()
{
}
原文地址:https://www.cnblogs.com/Netsharp/p/14077129.html