Download CHardDisk.h from here
  
Download CHardDisk.cpp from hereExplore My Other Channel for More Cool and Valuable Insights
👉 Youtube Learn Tech Tips👉 Tiktok
👉 Facebook:Create one class name CDiskInfo, post my code to your project
Source code:
CDiskInfo.h// huuvi168@gmail.com (Zidane)
#pragma once
#include <winioctl.h>
#define DI_SET_ERROR(pError, err_code) {if (pError) *pError = err_code;}
#define COM_GETDI_SUCCESS     0
#define COM_CREATE_INSTANCE_FAILED   -1
#define COM_CONNECT_SERVER_FAILED   -2
#define COM_SET_PROXY_PLANET_FAILED   -3
#define COM_EXE_QUERY_BOOTPARTITION_FAILED  -4
#define COM_ENUMERATOR_NEXT_WIN32DP_FAILED  -5
#define COM_GET_DEVICEID_DP_FAILED   -6
#define COM_EXE_QUERY_JOIN_DP_DD_FAILED   -7
#define COM_ENUMERATOR_NEXT_WIN32DD_FAILED  -8
#define COM_GET_DEVICEID_DD_FAILED   -9
#define INVALID_INFO_PC _T("000000000000000000000000000000000000000000000000")
class DiskInfo
{
public:
 DiskInfo(void);
 ~DiskInfo(void);
 static void GetHDSerialList(CStringArray &csOutList);
 static CString ConvertToHex(CString csString);
 static int GetIndexOfOSHardDisk();
 static bool GetOSHDSerial(CString& csOsHDSerial);
 static CString GetOSHDSerialByCom(int *pErr = 0);
private:
  static char * flipAndCodeBytes (const char * str, int pos, int flip,  char * buf);
  static wchar_t *ConvertToString (DWORD diskdata [MAX_PATH], int firstIndex, 
                                            int lastIndex, wchar_t* buf);
  static int ReadPhysicalDriveInNTUsingSmart (CStringArray &csSerialList); 
  static int ReadPhysicalDriveInNTWithZeroRights (CStringArray &csSerialList);
  static int ReadIdeDriveAsScsiDriveInNT (CStringArray &csSerialList);
  static int ReadPhysicalDriveInNTWithAdminRights (CStringArray &csSerialList);
  static BOOL DoIDENTIFY( HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP, 
   PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum, PDWORD lpcbBytesReturned );
  static void MergeList( CStringArray &csOutList, CStringArray const &csAddList);
};
CDiskInfo.cpp
// huuvi168@gmail.com (zidane)
#include "StdAfx.h"
#include "DiskInfo.h"
#include <windows.h>
#include <winioctl.h>
#include <cstdio>
#include <comdef.h>
#include <Wbemidl.h>
#ifdef USING_VMPROTECT
#include "VMProtectSDK.h"
#endif
#pragma comment(lib, "wbemuuid.lib")
typedef struct _MEDIA_SERAL_NUMBER_DATA {
 ULONG  SerialNumberLength; 
 ULONG  Result;
 ULONG  Reserved[2];
 UCHAR  SerialNumberData[1];
} MEDIA_SERIAL_NUMBER_DATA, *PMEDIA_SERIAL_NUMBER_DATA;
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;  
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;
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;
#define  SENDIDLENGTH  sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE 
#define  FILE_DEVICE_SCSI              0x0000001b
#define  IOCTL_SCSI_MINIPORT_IDENTIFY  ((FILE_DEVICE_SCSI << 16) + 0x0501)
//  Valid values for the bCommandReg member of IDEREGS.  
//  Returns ID sector for ATAPI.  
#define  IDE_ATAPI_IDENTIFY        0xA1 
//  Returns ID sector for ATA.
#define  IDE_ATA_IDENTIFY        0xEC
//  see NTDDSCSI.H for definition    
#define  IOCTL_SCSI_MINIPORT  0x0004D008  
#define  MAX_IDE_DRIVES           16
#define  DFP_GET_VERSION  0x00074080
#define  DFP_RECEIVE_DRIVE_DATA  0x0007c088
DiskInfo::DiskInfo(void)
{
}
DiskInfo::~DiskInfo(void)
{
}
int DiskInfo::ReadPhysicalDriveInNTWithZeroRights( CStringArray &csSerialList )
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("ProtectRPDInNTZR");
#endif
 int done = 0;
 csSerialList.RemoveAll();
 char buffer [10000];
 wchar_t driveName [256] = {0};  
 for (int drive = 0; drive < MAX_IDE_DRIVES; drive++)  
 {  
  HANDLE hPhysicalDriveIOCTL = 0;  
  //  Try to get a handle to PhysicalDrive IOCTL, report failure  
   //  and exit if can't.  
  
  swprintf (driveName, _T("\\\\.\\PhysicalDrive%d"), drive);  
  
  // swprintf ( driveName, 100, _T("\\\\.\\PhysicalDrive%d"), 
                                                                16, drive );
 
 //  Windows NT, Windows 2000, Windows XP - admin rights not required  
  hPhysicalDriveIOCTL = CreateFile (driveName, 0,  
    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,  
    OPEN_EXISTING, 0, NULL);  
  if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
    continue;
    
  STORAGE_PROPERTY_QUERY query;  
  DWORD cbBytesReturned = 0;  
 
  memset ((void *) & query, 0, sizeof (query));  
  query.PropertyId = StorageDeviceProperty;  
  query.QueryType = PropertyStandardQuery;  
  memset (buffer, 0, sizeof (buffer));  
 if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,  
   & query,  
   sizeof (query),  
   & buffer,  
   sizeof (buffer),  
   & cbBytesReturned, NULL) )  
  {           
   STORAGE_DEVICE_DESCRIPTOR * descrip = 
                                        (STORAGE_DEVICE_DESCRIPTOR *) & buffer;  
   CString csSerialNumber; 
           char szSerialNumber [512] = {0};
   wchar_t wcSerialNumber [512] = {0};
   
  flipAndCodeBytes (buffer, descrip -> SerialNumberOffset, 
                                                           1, szSerialNumber ); 
  mbstowcs_s(NULL, wcSerialNumber, sizeof(wcSerialNumber) / 
                               sizeof(wcSerialNumber[0]), szSerialNumber, 
                                                   strlen(szSerialNumber));
  csSerialNumber = wcSerialNumber;
  csSerialNumber.Trim();
   done = true;
   if (!csSerialNumber.IsEmpty() && 
                                 csSerialNumber.CompareNoCase(INVALID_INFO_PC))
   {
    // Get the disk drive geometry.  
    memset (buffer, 0, sizeof(buffer));  
    if ( DeviceIoControl (hPhysicalDriveIOCTL,  
     IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,  
     NULL,  
     0,  
     &buffer,  
     sizeof(buffer),  
     &cbBytesReturned,  
     NULL))  
    {           
   DISK_GEOMETRY_EX* geom = (DISK_GEOMETRY_EX*) &buffer;  
   if (geom->Geometry.MediaType == FixedMedia)
     {
      csSerialList.Add(csSerialNumber);
     }
    }  
   }
  }  
  CloseHandle (hPhysicalDriveIOCTL);  
 }  
 return done;
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
int DiskInfo::ReadPhysicalDriveInNTUsingSmart( CStringArray &csSerialList )
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("ProtectRPDInNTUS");
#endif
 csSerialList.RemoveAll();
 int done = FALSE;  
 int drive = 0;  
 
 wchar_t driveName [256];
 for (drive = 0; drive < MAX_IDE_DRIVES; drive++)  
 {  
  HANDLE hPhysicalDriveIOCTL = 0;  
  //  Try to get a handle to PhysicalDrive IOCTL, report failure  
  //  and exit if can't.  
  wsprintf (driveName, _T("\\\\.\\PhysicalDrive%d"), drive);  
  //  Windows NT, Windows 2000, Windows Server 2003, Vista  
  hPhysicalDriveIOCTL = CreateFile (driveName,  
   GENERIC_READ | GENERIC_WRITE,   
   FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,   
   NULL, OPEN_EXISTING, 0, NULL);  
  
  if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)  
  {  
   GETVERSIONINPARAMS GetVersionParams;  
   DWORD cbBytesReturned = 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),  
    &cbBytesReturned, NULL) )  
   {           
    // Print the SMART version  
    // PrintVersion (& GetVersionParams);  
    // Allocate the command buffer  
 ULONG CommandSize = sizeof(SENDCMDINPARAMS) + IDENTIFY_BUFFER_SIZE;  
 PSENDCMDINPARAMS Command = (PSENDCMDINPARAMS) malloc (CommandSize);  
    // Retrieve the IDENTIFY data  
    // Prepare the command  
  Command -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;  
    DWORD BytesReturned = 0;  
  if ( DeviceIoControl (hPhysicalDriveIOCTL,   
   SMART_RCV_DRIVE_DATA, Command, sizeof(SENDCMDINPARAMS),  
     Command, CommandSize,  
     &BytesReturned, NULL) )  
    {  
       // Print the IDENTIFY data  
       DWORD diskdata [256];  
       USHORT *pIdSector = (USHORT *)  
    (PIDENTIFY_DATA) ((PSENDCMDOUTPARAMS) Command) -> bBuffer;  
        for (int ijk = 0; ijk < 256; ijk++)  
     diskdata [ijk] = pIdSector [ijk];  
          if (diskdata [0] & 0x0040)
          {
      wchar_t szTemp[256] = {0};
      CString csTemp;
     ConvertToString(diskdata, 10, 19, szTemp);
      csTemp = szTemp;
      csTemp.Trim();
      if (!csTemp.IsEmpty() && csTemp.CompareNoCase(INVALID_INFO_PC) != 0)
     {
         csSerialList.Add(csTemp);
         done = TRUE;
     }
         }
    }  
    // Done  
    CloseHandle (hPhysicalDriveIOCTL);  
    free (Command);  
   }
  }
 }
 return done;
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
int DiskInfo::ReadIdeDriveAsScsiDriveInNT( CStringArray &csSerialList )
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("ProtectRIDASCSIDInNT");
#endif
 csSerialList.RemoveAll();
 int done = FALSE;
 wchar_t driveName [256] = {0};  
 HANDLE hScsiDriveIOCTL = 0;
 for (int controller = 0; controller < 16; controller++)  
 {  
  //  Try to get a handle to PhysicalDrive IOCTL, report failure  
  //  and exit if can't.  
  wsprintf (driveName, _T("\\\\.\\Scsi%d:"), controller);  
  //  Windows NT, Windows 2000, any rights should do  
  hScsiDriveIOCTL = CreateFile (driveName,  
   GENERIC_READ | GENERIC_WRITE,   
   FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,  
   OPEN_EXISTING, 0, NULL);  
 
  if (hScsiDriveIOCTL == INVALID_HANDLE_VALUE)
   continue;
  
  for (int drive = 0; drive < 2; drive++)  
  {  
   char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];  
   SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;  
   SENDCMDINPARAMS *pin =  
     (SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));  
   DWORD dummy;  
   memset (buffer, 0, sizeof (buffer));  
   p -> HeaderLength = sizeof (SRB_IO_CONTROL);  
   p -> Timeout = 10000;  
   p -> Length = SENDIDLENGTH;  
   p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;  
   strncpy ((char *) p -> Signature, "SCSIDISK", 8);  
   pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;  
   pin -> bDriveNumber = drive;  
  if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,   
    buffer,  
    sizeof (SRB_IO_CONTROL) +  
    sizeof (SENDCMDINPARAMS) - 1,  
    buffer,  
    sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,  
    &dummy, NULL))  
   {  
    SENDCMDOUTPARAMS *pOut =  
    (SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));  
    IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer);  
    if (pId -> sModelNumber [0])  
    {  
      DWORD diskdata [256];  
     int ijk = 0;  
     USHORT *pIdSector = (USHORT *) pId;  
     for (ijk = 0; ijk < 256; ijk++)  
        diskdata [ijk] = pIdSector [ijk];  
   //PrintIdeInfo (controller * 2 + drive, diskdata);
      if (diskdata [0] & 0x0040)
     {
        wchar_t szTemp[256] = {0};
        CString csTemp;
       ConvertToString(diskdata, 10, 19, szTemp);
        csTemp = szTemp;
        csTemp.Trim();
      
   if (!csTemp.IsEmpty() && csTemp.CompareNoCase(INVALID_INFO_PC) != 0)
        {
      csSerialList.Add(csTemp);
      done = TRUE;
        }
     }
    }  
   }  
  }  
  CloseHandle (hScsiDriveIOCTL);  
 }
 return done;
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
int DiskInfo::ReadPhysicalDriveInNTWithAdminRights( CStringArray &csSerialList )
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("ProtectRPDInNTWAR");
#endif
 csSerialList.RemoveAll();
 
 wchar_t driveName [256] = {0};
 GETVERSIONOUTPARAMS VersionParams;
 int done = FALSE;
 BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
 
 for (int drive = 0; drive < MAX_IDE_DRIVES; drive++)  
 {  
  HANDLE hPhysicalDriveIOCTL = 0;  
  //  Try to get a handle to PhysicalDrive IOCTL, report failure  
  //  and exit if can't.  
  wsprintf (driveName, _T("\\\\.\\PhysicalDrive%d"), drive);  
  //  Windows NT, Windows 2000, must have admin rights  
  hPhysicalDriveIOCTL = CreateFile (driveName,  
   GENERIC_READ | GENERIC_WRITE,   
   FILE_SHARE_READ | FILE_SHARE_WRITE , NULL,  
   OPEN_EXISTING, 0, NULL);  
  
  if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)  
   continue;
  DWORD cbBytesReturned = 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),  
   &cbBytesReturned, NULL))
  {
  
   if (VersionParams.bIDEDeviceMap > 0)
   {
  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 >> drive & 0x10) 
                                        ? IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
    memset (&scip, 0, sizeof(scip));  
    memset (IdOutCmd, 0, sizeof(IdOutCmd));  
    if ( DoIDENTIFY (hPhysicalDriveIOCTL,   
     &scip,   
     (PSENDCMDOUTPARAMS)&IdOutCmd,   
     (BYTE) bIDCmd,  
     (BYTE) drive,  
     &cbBytesReturned))  
    {  
     DWORD diskdata [256] = {0};  
     int ijk = 0;  
     USHORT *pIdSector = (USHORT *)  
     ((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;  
     for (ijk = 0; ijk < 256; ijk++)  
      diskdata [ijk] = pIdSector [ijk];  
     if (diskdata [0] & 0x0040)
     {
      wchar_t szTemp[256] = {0};
      CString csTemp;
     ConvertToString(diskdata, 10, 19, szTemp);
      csTemp = szTemp;
      csTemp.Trim();
    
 if (!csTemp.IsEmpty() && csTemp.CompareNoCase(INVALID_INFO_PC) != 0)
      {
       csSerialList.Add(csTemp);
       done = TRUE;
      }
     } 
    }  
   }
  }
  CloseHandle (hPhysicalDriveIOCTL); 
 }
 return done; 
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
BOOL DiskInfo::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 drive 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 DiskInfo::GetIndexOfOSHardDisk()
{
 int nDiskOS = 0;
 HANDLE m_hOSPartition = 0;
 wchar_t szSysDir[MAX_PATH] = {0};
 GetSystemDirectory(szSysDir, MAX_PATH);
 
 CString csPartitionOS;
 csPartitionOS.Format(_T("\\\\.\\%s"), CString(szSysDir).Left(2));
 
 m_hOSPartition = CreateFile (csPartitionOS, 0,  
  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,  
  OPEN_EXISTING, 0, NULL);  
 if (m_hOSPartition != INVALID_HANDLE_VALUE)   
 {
  //char buffer [10000];
  VOLUME_DISK_EXTENTS buffer;
  DWORD cbBytesReturned = 0;
if ( DeviceIoControl (m_hOSPartition, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,  
   NULL,  
   0,  
   &buffer,  
   sizeof (buffer),  
   & cbBytesReturned, NULL) )  
  {
   nDiskOS = buffer.Extents->DiskNumber;
  }
 }
 CloseHandle(m_hOSPartition);
 return nDiskOS;
}
bool DiskInfo::GetOSHDSerial(CString& csOsHDSerial)
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("GetOSHDSerial");
#endif
 int err = 0;
 //Get HD Serial by Com
 csOsHDSerial = GetOSHDSerialByCom(&err);
 if (!csOsHDSerial.IsEmpty())
  return true;
 wchar_t szErr[256] = {0};
 wsprintf(szErr, L"Get MCByCom failed %d", err);
 //CHelper::WriteLog(szErr);
 CStringArray csSerialList;
 GetHDSerialList(csSerialList);
 if (csSerialList.GetCount() <= 0)
  return false;
 int nOsDiskIndex = GetIndexOfOSHardDisk();
 if (nOsDiskIndex < 0 || nOsDiskIndex >= csSerialList.GetCount())
  return false;
 csOsHDSerial = csSerialList.GetAt(nOsDiskIndex);
 csSerialList.RemoveAll();
 return true;
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
wchar_t *DiskInfo::ConvertToString( DWORD diskdata [MAX_PATH], 
                                int firstIndex, int lastIndex, wchar_t* buf )
{
 int index = 0;  
 int position = 0;  
 //  each integer has two characters stored in it backwards  
 for (index = firstIndex; index <= lastIndex; index++)  
 {  
  //  get high byte for 1st character  
  buf [position++] = (wchar_t) (diskdata [index] / 256);  
  //  get low byte for 2nd character  
  buf [position++] = (wchar_t) (diskdata [index] % 256);  
 }  
 //  end the string   
 buf[position] = '\0';  
 //  cut off the trailing blanks  
 for (index = position - 1; index > 0 && isspace(buf [index]); index--)  
  buf [index] = '\0';  
 return buf;
}
char* DiskInfo::flipAndCodeBytes (const char * str, int pos, int flip, char * buf)  
{  
 int i;  
 int j = 0;  
 int k = 0;  
 buf [0] = '\0';  
 if (pos <= 0)  
  return buf;  
 if ( ! j)  
 {  
  char p = 0;  
  // First try to gather all characters representing hex digits only.  
  j = 1;  
  k = 0;  
  buf[k] = 0;  
  for (i = pos; j && str[i] != '\0'; ++i)  
  {  
   char c = tolower(str[i]);  
   if (isspace(c))  
    c = '0';  
   ++p;  
   buf[k] <<= 4;  
   if (c >= '0' && c <= '9')  
    buf[k] |= (unsigned char) (c - '0');  
   else if (c >= 'a' && c <= 'f')  
    buf[k] |= (unsigned char) (c - 'a' + 10);  
   else  
   {  
    j = 0;  
    break;  
   }  
   if (p == 2)  
   {  
         if (buf[k] != '\0' && ! isprint(buf[k]))  
    {  
     j = 0;  
     break;  
    }  
    ++k;  
    p = 0;  
    buf[k] = 0;  
   }  
  }  
 }  
 if ( ! j)  
 {  
  // There are non-digit characters, gather them as is.  
  j = 1;  
  k = 0;  
  for (i = pos; j && str[i] != '\0'; ++i)  
  {  
   char c = str[i];  
   if ( ! isprint(c))  
   {  
    j = 0;  
    break;  
   }  
   buf[k++] = c;  
  }  
 }  
 if ( ! j)  
 {  
  // The characters are not there or are not printable.  
  k = 0;  
 }  
 buf[k] = '\0';  
 if (flip)  
  // Flip adjacent characters  
  for (j = 0; j < k; j += 2)  
  {  
   char t = buf[j];  
   buf[j] = buf[j + 1];  
   buf[j + 1] = t;  
  }  
  // Trim any beginning and end space  
  i = j = -1;  
  for (k = 0; buf[k] != '\0'; ++k)  
  {  
   if (! isspace(buf[k]))  
   {  
    if (i < 0)  
     i = k;  
    j = k;  
   }  
  }  
  if ((i >= 0) && (j >= 0))  
  {  
   for (k = i; (k <= j) && (buf[k] != '\0'); ++k)  
    buf[k - i] = buf[k];  
   buf[k - i] = '\0';  
  }  
  return buf;  
}  
void DiskInfo::MergeList( CStringArray &csOutList, 
                                       CStringArray const &csAddList)
{
 CString csTmp;
 bool bExist;
 for (int i = 0; i < csAddList.GetCount(); i++)
 {
  csTmp = csAddList.GetAt(i);
  bExist = false;
  for (int j = 0; j < csOutList.GetCount(); j++)
  {
   if (csOutList.GetAt(j).CompareNoCase(csTmp) == 0)
   {
    bExist = true;
    break;
   }
  }
  if (!bExist)
   csOutList.Add(csTmp);
 }
}
void DiskInfo::GetHDSerialList(CStringArray &csHDSerialList)
{
 CStringArray csTmpList;
 csHDSerialList.RemoveAll();
 
 ReadPhysicalDriveInNTWithAdminRights(csTmpList);
 MergeList(csHDSerialList, csTmpList);
 ReadPhysicalDriveInNTUsingSmart(csTmpList);
 MergeList(csHDSerialList, csTmpList);
 ReadPhysicalDriveInNTWithZeroRights(csTmpList);
 MergeList(csHDSerialList, csTmpList);
 ReadIdeDriveAsScsiDriveInNT(csTmpList);
 MergeList(csHDSerialList, csTmpList);
}
CString DiskInfo::ConvertToHex(CString csString)
{
 CString csOutHex;
 for(register int i = 0; i < csString.GetLength(); i++)
 {
  csOutHex.AppendFormat(_T("%02x"), csString[i]);
 }
 return csOutHex;
}
CString DiskInfo::GetOSHDSerialByCom(int *pError)
{
#ifdef USING_VMPROTECT 
// VMProtectBegin("GetOSHDSerialByCom");
#endif
 HRESULT hr = CoInitialize(NULL);
    HRESULT hres;
    CString strRetId = _T("");
       
 DI_SET_ERROR(pError, COM_GETDI_SUCCESS);
 IWbemLocator *pLoc = NULL;
    hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, (LPVOID *) &pLoc);
    if (FAILED(hres))
    {
        DI_SET_ERROR(pError, COM_CREATE_INSTANCE_FAILED);
  CoUninitialize(); 
        return strRetId;                   // Program has failed.
    }
    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method
    IWbemServices *pSvc = NULL;
    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
         NULL,                    // User name. NULL = current user
         NULL,                    // User password. NULL = current
         0,                       // Locale. NULL indicates current
         NULL,                    // Security flags.
         0,                       // Authority (e.g. Kerberos)
         0,                       // Context object 
         &pSvc                    // pointer to IWbemServices proxy
         );
    
    if (FAILED(hres))
    {
        DI_SET_ERROR(pError, COM_CONNECT_SERVER_FAILED);
  pLoc->Release();   
        CoUninitialize(); 
        return strRetId;
        // Program has failed.
    }
    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------
    hres = CoSetProxyBlanket(
       pSvc,                        // Indicates the proxy to set
       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
       NULL,                        // Server principal name 
       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
       NULL,                        // client identity
       EOAC_NONE                    // proxy capabilities 
    );
    if (FAILED(hres))
    {
        DI_SET_ERROR(pError, COM_SET_PROXY_PLANET_FAILED);
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
        return strRetId;
        // Program has failed.
    }
 IEnumWbemClassObject* pEnumerator = NULL;
 IEnumWbemClassObject* pEnumerator1 = NULL;
 IEnumWbemClassObject* pEnumerator2 = NULL;
 IWbemClassObject *pclsObj = NULL;
 IWbemClassObject *pclsObj1 = NULL;
 IWbemClassObject *pclsObj2 = NULL;
 ULONG uReturn = 0;
 wchar_t wmihddsn[256] = {0};
 hres = pSvc->ExecQuery(
   bstr_t(_T("WQL")),
   bstr_t(_T("SELECT * FROM Win32_DiskPartition WHERE BootPartition=True")),
   WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
   NULL,
   &pEnumerator);
    if (!SUCCEEDED(hres) || !pEnumerator)
 {
  DI_SET_ERROR(pError, COM_EXE_QUERY_BOOTPARTITION_FAILED);
  if (pEnumerator)
   pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
 // get the first Win32_DiskPartition
 hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
 if (!SUCCEEDED(hr) || 0 == uReturn)
 {
  DI_SET_ERROR(pError, COM_ENUMERATOR_NEXT_WIN32DP_FAILED);
  if (pclsObj)
   pclsObj->Release();
  pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
 VARIANT vtProp;
 wchar_t tmp[1024];
 wchar_t query[1024];
 
 tmp[0]  = '\0';
 query[0] = '\0';
 // Get the value of the partition's DeviceID property
 hr = pclsObj->Get(_T("DeviceID"), 0, &vtProp, 0, 0);
 if (!SUCCEEDED(hr))
 {
  DI_SET_ERROR(pError, COM_GET_DEVICEID_DP_FAILED);
  pclsObj->Release();
  pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
 if(vtProp.vt == VT_BSTR) 
 {
  wcscpy(tmp, vtProp.bstrVal);
 }
 VariantClear(&vtProp);
 // "join" Win32_DiskPartition to Win32_DiskDrive
 wsprintf(query, _T("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='%s'} 
                                        WHERE ResultClass=Win32_DiskDrive"), tmp);
 hres = pSvc->ExecQuery(
    bstr_t(_T("WQL")),
    bstr_t(query),
    WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
    NULL,
    &pEnumerator1);
 if(!SUCCEEDED(hres) || !pEnumerator1)
 {
  DI_SET_ERROR(pError, COM_EXE_QUERY_JOIN_DP_DD_FAILED);
  if (pEnumerator1)
   pEnumerator1->Release();
  pclsObj->Release();
  pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
    
 // get the first Win32_DiskDrive
 hr = pEnumerator1->Next(WBEM_INFINITE, 1, &pclsObj1, &uReturn);
 if(!SUCCEEDED(hr) || 0 == uReturn)
 {
  DI_SET_ERROR(pError, COM_ENUMERATOR_NEXT_WIN32DD_FAILED);
  if (pclsObj1)
   pclsObj1->Release();
  pEnumerator1->Release();
  pclsObj->Release();
  pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
 // Get the value of the disk-drive's DeviceID
 hr = pclsObj1->Get(_T("DeviceID"), 0, &vtProp, 0, 0);
 if(!SUCCEEDED(hr))
 {
  DI_SET_ERROR(pError, COM_GET_DEVICEID_DD_FAILED);
  pclsObj1->Release();
  pEnumerator1->Release();
  pclsObj->Release();
  pEnumerator->Release();
  pSvc->Release();
        pLoc->Release();    
        CoUninitialize(); 
  return strRetId;
 }
 if(vtProp.vt == VT_BSTR)
 {
  wcscpy(tmp, vtProp.bstrVal);
 }
 VariantClear(&vtProp);
 // "join" Win32_DiskDrive to Win32_PhysicalMedia
 wsprintf(query, _T("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='%s'} 
                             WHERE ResultClass=Win32_PhysicalMedia"), tmp);
 hres = pSvc->ExecQuery(
     bstr_t(_T("WQL")),
     bstr_t(query),
     WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
     NULL,
     &pEnumerator2);
 hr = WBEM_S_NO_ERROR; 
 while (hr == WBEM_S_NO_ERROR && pEnumerator2)
 {
  // get the first Win32_PhysicalMedia
  pclsObj2 = NULL;
  hr = pEnumerator2->Next(WBEM_INFINITE, 1, &pclsObj2, &uReturn);
  if(!SUCCEEDED(hr) || 0 == uReturn || !pclsObj2)
  {
   if(pclsObj2) 
     pclsObj2->Release();
   continue;
  }
  // get the PhysicalMedia's SerialNumber
  hr = pclsObj2->Get(_T("SerialNumber"), 0, &vtProp, 0, 0);
  if(!SUCCEEDED(hr))
  {
   pclsObj2->Release();
   continue;
  }
  if(vtProp.vt == VT_BSTR && vtProp.bstrVal) 
  {
     wcscpy(wmihddsn, vtProp.bstrVal);
     strRetId = wmihddsn;
  }
  VariantClear(&vtProp);
  pclsObj2->Release();
  if (strRetId.GetLength() > 0)
  {
   strRetId.Trim();
   if (!strRetId.IsEmpty() && strRetId.CompareNoCase(INVALID_INFO_PC) != 0)
    break;
   else
    strRetId.Empty();
  }
 }
 
 if(pEnumerator2) 
  pEnumerator2->Release();
 pclsObj1->Release();
 pEnumerator1->Release();
 pclsObj->Release();
 pEnumerator->Release();
 pSvc->Release();
 pLoc->Release();    
 CoUninitialize();
 
 return strRetId;   // Program successfully completed.
#ifdef USING_VMPROTECT 
// VMProtectEnd();
#endif
}
How to use
CString csOSHDSerial;
DiskInfo::GetOSHDSerial(csOSHDSerial);
AfxMessageBox(csOSHDSerial);

Download CHardDisk.h from here
Download CHardDisk.cpp from here
If you have any feedback on How to get Hard Disk serial key using C++. please leave your comment, we can discuss about it
	Thank you for reading this post. I hope you found it helpful and easy to follow. If you have any feedback or questions about 
	   
		How to "get Hard Disk serial key using C++"
	  , 
	please share them in the comments below. I would love to hear from you and discuss this topic further  
 
	
 
✋✋✋✋ 
		Webzone Tech Tips
		 - I am Zidane, See you next time soon ✋✋✋✋ 
	
 
 
 
 
 
 
 
 
 

 
 
 
 
 
 
 
 
 
 
