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

调用Windows API WriteFile写入SD物理磁盘报错ERROR_ACCESS_DENIED(0x5)求解

问题根本原因
  • 权限不符合要求:Windows默认禁止普通用户权限的程序访问物理磁盘的写入接口,需要以管理员身份运行程序才能拿到写入权限,这是返回ERROR_ACCESS_DENIED最常见的原因。
  • 驱动器被系统占用:只要SD卡的卷处于系统挂载状态,资源管理器、杀毒软件、索引服务等后台进程就可能持有卷的访问句柄,未成功锁定和卸载卷的前提下直接写入会被系统拦截。
  • CreateFile参数错误:访问物理驱动器不能使用FILE_ATTRIBUTE_NORMAL参数,必须添加FILE_FLAG_NO_BUFFERING、FILE_FLAG_WRITE_THROUGH标记绕过系统缓存,否则写入请求会被系统校验拦截。
  • 写入对齐不符合要求:Windows要求直接写入物理磁盘的起始偏移、写入长度都必须是磁盘物理扇区的整数倍,原代码固定写512字节,如果SD卡实际物理扇区为4KB也会触发错误。
物理驱动器直接写入实现步骤
  • 程序运行前申请管理员权限,编译时可嵌入manifest配置requireAdministrator权限级,避免手动右键提权。
  • 打开物理驱动器句柄后,先调用DeviceIoControl传入FSCTL_LOCK_VOLUME控制码独占锁定卷,再传入FSCTL_DISMOUNT_VOLUME控制码强制卸载文件系统,确保没有其他进程占用磁盘。
  • 调用DeviceIoControl传入IOCTL_DISK_GET_DRIVE_GEOMETRY获取磁盘实际扇区大小,所有读写操作的偏移、长度都按该值对齐。
  • 写入操作完成后,调用DeviceIoControl传入FSCTL_UNLOCK_VOLUME释放卷锁,再关闭句柄。
修正后的代码示例
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windows.h>

DWORD lastError;

int main (void) {
  uint16_t y;
  uint8_t* buffer;
  DWORD bytesWritten, bytesReturned;
  DISK_GEOMETRY dg;
  DWORD sectorSize;

  // 打开物理驱动器,添加无缓存、直写标记
  HANDLE sdCardHandle = CreateFile("\\\\.\\PhysicalDrive2", 
                                   GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ | FILE_SHARE_WRITE, 
                                   NULL, 
                                   OPEN_EXISTING, 
                                   FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, 
                                   NULL);

  if(sdCardHandle == INVALID_HANDLE_VALUE) {
    lastError = GetLastError();
    printf("CreateFile error: 0x%X\n", lastError);
    return -1;
  }

  // 获取磁盘扇区大小
  if (!DeviceIoControl(sdCardHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytesReturned, NULL)) {
    lastError = GetLastError();
    printf("Get geometry error: 0x%X\n", lastError);
    CloseHandle(sdCardHandle);
    return -1;
  }
  sectorSize = dg.BytesPerSector;
  buffer = (uint8_t*)malloc(sectorSize);

  // 锁定并卸载卷(如果磁盘有多个分区需要遍历所有卷执行该操作)
  if (!DeviceIoControl(sdCardHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL)) {
    lastError = GetLastError();
    printf("Lock volume error: 0x%X\n", lastError);
    free(buffer);
    CloseHandle(sdCardHandle);
    return -1;
  }
  if (!DeviceIoControl(sdCardHandle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL)) {
    lastError = GetLastError();
    printf("Dismount volume error: 0x%X\n", lastError);
    DeviceIoControl(sdCardHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL);
    free(buffer);
    CloseHandle(sdCardHandle);
    return -1;
  }
  
  for (y = 1; y < 10001; y++) { 
    memset(buffer, y, sectorSize);
    if (WriteFile(sdCardHandle, buffer, sectorSize, &bytesWritten, NULL) == 0) {
      lastError = GetLastError();
      printf("WriteFile error: 0x%X\n", lastError);
      break;
    }
    printf("%d\n", y);
  }

  // 清理操作
  DeviceIoControl(sdCardHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytesReturned, NULL);
  free(buffer);
  CloseHandle(sdCardHandle);
  return 0;
}
额外注意事项
  • 物理驱动器编号需要确认正确,错写其他磁盘会导致不可逆的数据丢失。
  • 写入完成后建议安全弹出SD卡再重新插入,确保系统读取到最新的磁盘数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 10:36:03