RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1096363
Accepted
D .Stark
D .Stark
Asked:2020-03-18 22:36:22 +0000 UTC2020-03-18 22:36:22 +0000 UTC 2020-03-18 22:36:22 +0000 UTC

获取磁盘的序列号和总线类型

  • 772

要获得我使用的序列号和轮胎类型IOCTL_STORAGE_QUERY_PROPERTY。但是,STORAGE_DEVICE_DESCRIPTOR它不包含正确的信息。至于序列号,据我了解,事情是这样的:原则上它可能不在某些磁盘上,同一组字节可以有不同的解释(如果有的话,有没有通用的方法?)。该字段BusType还显示了 RAID 总线的类型,尽管事实上我有 NVM Express。如何获取正确的信息?该解决方案应该可以在 Windows XP 下运行。

c++
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    MSDN.WhiteKnight
    2020-03-26T12:48:49Z2020-03-26T12:48:49Z

    我不知道通用方法,但是对于任何支持 ATA-2 命令集的硬盘驱动器,返回序列号的 IDENTIFY DEVICE 命令应该可以工作。这里不可能对字节进行不同的解释,因为实际上只有 ANSI 字符。当然,该命令只返回缝合到设备中的内容。可能只是垃圾而不是唯一编号,就像 SMBIOS 表中著名的“由 OEM 填充”一样。根据一台设备的错误结果,不能断定该方法不起作用。您需要拥有几种不同的设备并对其进行试验。

    这是获取序列号的示例代码(需要管理员权限):

    #include <windows.h>
    #include <stdio.h>
    
    typedef struct
    {
        WORD wGenConfig;
        WORD wNumCyls;
        WORD wReserved;
        WORD wNumHeads;
        WORD wBytesPerTrack;
        WORD wBytesPerSector;
        WORD wSectorsPerTrack;
        WORD wVendorUnique[3];
        BYTE sSerialNumber[20];
        WORD wBufferType;
        WORD wBufferSize;
        WORD wECCSize;
        BYTE sFirmwareRev[8];
        BYTE sModelNumber[39];
        WORD wMoreVendorUnique;
        WORD wDoubleWordIO;
        WORD wCapabilities;
        WORD wReserved1;
        WORD wPIOTiming;
        WORD wDMATiming;
        WORD wBS;
        WORD wNumCurrentCycles;
        WORD wNumCurrentHeads;
        WORD wNumCurrentSectorsPerTrack;
        WORD ulCurrentSectorCapacity;
        WORD wMultiSectorStuff;
        DWORD ulTotalAddressableSectors;
        WORD wSingleWordDMA;
        WORD wMultiWordDMA;
        BYTE bReserved[127];
    }ST_IDSECTOR; //ATA 7.17.7.1 - IDENTIFY DEVICE data
    
    typedef struct
    {
        BYTE m_ucAttribIndex;
        DWORD m_dwAttribValue;
        BYTE m_ucValue;
        BYTE m_ucWorst;
        DWORD m_dwThreshold;
    }ST_SMART_INFO;
    
    typedef struct
    {
        GETVERSIONINPARAMS m_stGVIP;
        ST_IDSECTOR m_stInfo;
        ST_SMART_INFO m_stSmartInfo[256];
        BYTE m_ucSmartValues;
        BYTE m_ucDriveIndex;
        char m_csErrorString[1000];
    }ST_DRIVE_INFO;
    
    #define DRIVE_HEAD_REG  0xA0
    #define OUT_BUFFER_SIZE IDENTIFY_BUFFER_SIZE+16
    
    void SwapBytes(char* p, size_t len) {
    
        if (len % 2 != 0)len--;
    
        char t;
        for (int i = 0; i < len - 1; i += 2) {
            t = p[i];
            p[i] = p[i + 1];
            p[i + 1] = t;
        }
    }
    
    BOOL CollectDriveInfo(HANDLE hDevice, UCHAR ucDriveIndex, ST_IDSECTOR* pInfo)
    {
        BOOL bRet = FALSE;
        SENDCMDINPARAMS stCIP = { 0 };
        DWORD dwRet = 0;
    
        char szOutput[OUT_BUFFER_SIZE] = { 0 };
    
        stCIP.cBufferSize = IDENTIFY_BUFFER_SIZE;
        stCIP.bDriveNumber = ucDriveIndex;
        stCIP.irDriveRegs.bFeaturesReg = 0;
        stCIP.irDriveRegs.bSectorCountReg = 1;
        stCIP.irDriveRegs.bSectorNumberReg = 1;
        stCIP.irDriveRegs.bCylLowReg = 0;
        stCIP.irDriveRegs.bCylHighReg = 0;
        stCIP.irDriveRegs.bDriveHeadReg = DRIVE_HEAD_REG;
        stCIP.irDriveRegs.bCommandReg = ID_CMD; //ATA 7.17 - IDENTIFY DEVICE
    
        bRet = DeviceIoControl(hDevice, SMART_RCV_DRIVE_DATA, &stCIP, sizeof(stCIP), szOutput, OUT_BUFFER_SIZE, &dwRet, NULL);
        if (bRet)
        {
            CopyMemory(pInfo, szOutput + 16, sizeof(ST_IDSECTOR));      
        }
        else
            dwRet = GetLastError();
        return bRet;
    }
    
    BOOL GetDriveInfo(BYTE ucDriveIndex, ST_DRIVE_INFO* pInfo)
    {
        HANDLE hDevice = NULL;
        char szT1[MAX_PATH] = { 0 };
        BOOL bRet = FALSE;
        DWORD dwRet = 0;    
    
        sprintf_s(szT1, sizeof(szT1), "\\\\.\\PHYSICALDRIVE%d", ucDriveIndex);
        hDevice = CreateFileA(szT1, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
        if (hDevice != INVALID_HANDLE_VALUE)
        {
            bRet = DeviceIoControl(hDevice, SMART_GET_VERSION, NULL, 0, &pInfo->m_stGVIP, sizeof(GETVERSIONINPARAMS), &dwRet, NULL);
            if (bRet)
            {
                if ((pInfo->m_stGVIP.fCapabilities & CAP_ATA_ID_CMD) == CAP_ATA_ID_CMD)
                {               
                    bRet = CollectDriveInfo(hDevice, ucDriveIndex,&pInfo->m_stInfo);
                }
                else printf("ATA IDENTIFY DEVICE command is not supported");
            }
            else printf("S.M.A.R.T error");
            CloseHandle(hDevice);
        }
        else printf("CreateFile error %d\n",GetLastError());
        return bRet;
    }
    
    int main()
    {   
        ST_DRIVE_INFO info;
        BOOL res = GetDriveInfo(0,&info);
    
        if (res == FALSE) {
            printf("GetDriveInfo Error\n");
            getchar();
            return 1;
        }
    
        char sbuf[50] = "";
        char* pch = NULL;   
    
        ZeroMemory(sbuf, sizeof(sbuf));
        strncpy_s(sbuf, sizeof(sbuf), (char*)info.m_stInfo.sSerialNumber, 20);
        SwapBytes(sbuf, 20);
    
        pch = &(sbuf[0]);
        while (true) {
            if (*pch != ' ')break;
            if (pch >= &(sbuf[18]))break;
            pch++;
        }
    
        printf("Serial number: %s\n", pch);
        getchar();
    
        return 0;
    }
    

    对于 NVM Express 驱动器,驱动程序可以工作在 ATA 仿真模式,然后设备可以响应 IDENTIFY DEVICE 命令,但在检查功能时不返回 CAP_ATA_ID_CMD 标志。(NVM Express 有自己的命令系统,也有 IDENTIFY 命令,但格式不同。)如果需要处理这种情况,最好不进行初步检查就立即发送命令并查看错误代码。

    来源

    • SMART_RCV_DRIVE_DATA
    • 使用 SMART 的硬盘信息
    • ATA/ATAPI 命令集 2
    • 2

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5