You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取HDD SMART属性遇错误5(拒绝访问)的原因排查与修复方案

错误代码5(拒绝访问)的原因及修复方案

为啥会出现拒绝访问?主要有这几个原因

  • 磁盘路径写错了:原代码里的磁盘路径是L"\\.\PhysicalDrive",但C++宽字符串里反斜杠得写俩,正确路径应该是L"\\\\.\\PhysicalDrive",路径错了要么打不开磁盘,要么权限验证过不了。
  • 没先开SMART功能:很多磁盘得先发命令启用SMART才能读数据,直接读就会被拒。
  • 权限不够:就算是管理员,CreateFile只请求GENERIC_READ权限可能不够,有些场景得加上GENERIC_WRITE权限才行。
  • 结构体/参数错了:SENDCMDINPARAMS、SENDCMDOUTPARAMS的大小计算或者参数赋值不对,系统不认这个请求,直接拒绝。
  • 硬件本身限制:有些SSD或者老硬盘可能没开SMART,或者不支持标准的SMART命令。

怎么修复?按下面步骤来

  1. 改对磁盘路径:把路径里的单反斜杠改成俩,确保能正确指向物理磁盘。
  2. 先启用SMART:读数据前先发命令开SMART功能。
  3. 调权限参数:CreateFile请求GENERIC_READ | GENERIC_WRITE权限,保证操作权限够。
  4. 检查硬件设置:进BIOS或者系统存储设置里确认磁盘的SMART功能是开着的。

修正后的完整代码

#include <windows.h>
#include <iostream>
#include <string>

// 定义SMART相关常量
#define SMART_CMD 0xB0
#define READ_ATTRIBUTES 0xD0
#define SMART_ENABLE_OPERATION 0xD8
#define SMART_CYL_LOW 0x4F
#define SMART_CYL_HI 0xC2
#define READ_ATTRIBUTE_BUFFER_SIZE 512
#define SMART_SEND_DRIVE_DATA 0x0007C088
#define SMART_RCV_DRIVE_DATA 0x0007C084

#pragma pack(push, 1)
// 强制结构体按1字节对齐,避免内存偏移问题
typedef struct _SENDCMDINPARAMS {
    DWORD cBufferSize;
    union {
        struct {
            BYTE bFeaturesReg;
            BYTE bSectorCountReg;
            BYTE bSectorNumberReg;
            BYTE bCylLowReg;
            BYTE bCylHighReg;
            BYTE bDriveHeadReg;
            BYTE bCommandReg;
        } irDriveRegs;
        DWORD dwDriveRegs;
    };
    DWORD dwReserved;
} SENDCMDINPARAMS, *PSENDCMDINPARAMS;

typedef struct _SENDCMDOUTPARAMS {
    DWORD cBufferSize;
    DWORD dwReserved;
    BYTE bBuffer[READ_ATTRIBUTE_BUFFER_SIZE];
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS;
#pragma pack(pop)

void GetSMART()
{
    int driveNumber = 0; // 磁盘编号,可根据实际磁盘调整
    std::wstring drivePath = L"\\\\.\\PhysicalDrive" + std::to_wstring(driveNumber);
    
    // 打开物理磁盘,申请读写权限
    HANDLE hDrive = CreateFile(drivePath.c_str(), 
                               GENERIC_READ | GENERIC_WRITE, 
                               FILE_SHARE_READ | FILE_SHARE_WRITE, 
                               nullptr, 
                               OPEN_EXISTING, 
                               FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, 
                               nullptr);
    
    if (hDrive == INVALID_HANDLE_VALUE) {
        DWORD errorCode = GetLastError();
        std::cout << "打开磁盘失败,错误代码:" << errorCode << std::endl;
        return;
    }

    DWORD bytesReturned;
    bool isSuccess;

    // 第一步:发送命令启用SMART功能
    SENDCMDINPARAMS enableParams = {0};
    enableParams.cBufferSize = 0;
    enableParams.irDriveRegs.bFeaturesReg = SMART_ENABLE_OPERATION;
    enableParams.irDriveRegs.bSectorCountReg = 0;
    enableParams.irDriveRegs.bSectorNumberReg = 0;
    enableParams.irDriveRegs.bCylLowReg = 0;
    enableParams.irDriveRegs.bCylHighReg = 0;
    enableParams.irDriveRegs.bDriveHeadReg = 0xA0 | ((static_cast<BYTE>(driveNumber) & 1) << 4);
    enableParams.irDriveRegs.bCommandReg = SMART_CMD;

    isSuccess = DeviceIoControl(hDrive, 
                                SMART_SEND_DRIVE_DATA, 
                                &enableParams, 
                                sizeof(SENDCMDINPARAMS) - 1, 
                                nullptr, 
                                0, 
                                &bytesReturned, 
                                nullptr);
    if (!isSuccess) {
        DWORD errorCode = GetLastError();
        std::cout << "启用SMART失败,错误代码:" << errorCode << std::endl;
        CloseHandle(hDrive);
        return;
    }

    // 第二步:读取SMART属性数据
    SENDCMDINPARAMS readParams = {0};
    readParams.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE;
    readParams.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES;
    readParams.irDriveRegs.bSectorCountReg = 1;
    readParams.irDriveRegs.bSectorNumberReg = 1;
    readParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
    readParams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
    readParams.irDriveRegs.bDriveHeadReg = 0xA0 | ((static_cast<BYTE>(driveNumber) & 1) << 4);
    readParams.irDriveRegs.bCommandReg = SMART_CMD;

    SENDCMDOUTPARAMS outParams = {0};
    isSuccess = DeviceIoControl(hDrive, 
                                SMART_RCV_DRIVE_DATA, 
                                &readParams, 
                                sizeof(SENDCMDINPARAMS) - 1, 
                                &outParams, 
                                sizeof(SENDCMDOUTPARAMS), 
                                &bytesReturned, 
                                nullptr);

    if (!isSuccess) {
        DWORD errorCode = GetLastError();
        LPSTR errorMessage = nullptr;
        DWORD result = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr,
            errorCode,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            reinterpret_cast<LPSTR>(&errorMessage),
            0,
            nullptr
        );
        if (result != 0) {
            std::cout << "获取S.M.A.R.T.数据失败,错误代码:" << errorCode << std::endl;
            std::cout << "错误信息:" << errorMessage << std::endl;
        } else {
            std::cout << "无法获取错误信息。" << std::endl;
        }
        LocalFree(errorMessage);
        CloseHandle(hDrive);
        return;
    }

    // 示例:输出获取到的SMART数据前16字节
    std::cout << "成功获取S.M.A.R.T.数据,前16字节:" << std::endl;
    for (int i = 0; i < 16; ++i) {
        printf("%02X ", outParams.bBuffer[i]);
    }
    std::cout << std::endl;

    CloseHandle(hDrive);
}

int main()
{
    GetSMART();
    return 0;
}

代码修正说明

  • 路径修正:把L"\\.\PhysicalDrive"改成L"\\\\.\\PhysicalDrive",解决转义错误问题。
  • 结构体对齐:用#pragma pack强制结构体按1字节对齐,避免系统因内存偏移拒绝请求。
  • 新增SMART启用步骤:先发送启用命令,符合多数磁盘的操作逻辑。
  • 权限调整:CreateFile申请读写权限,确保操作权限足够。
  • 错误处理完善:补充了磁盘打开、SMART启用阶段的错误输出,方便排查问题。
  • 缓冲区修正:把原错误的数组定义改成正确的结构体实例,避免内存溢出或参数错误。

内容的提问来源于stack exchange,提问作者Bogdaniv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:27:20