调用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
相关产品推荐
相关产品推荐

