将文件写入 SD 卡(物理硬盘)失败并显示 ERROR_ACCESS_DENIED (0x5)

WriteFile to SD card (physical hard disk) fails with ERROR_ACCESS_DENIED (0x5)

我正在尝试直接使用 Windows API 写入物理硬盘(SD 卡/FAT32):WriteFile () 但它总是以 ERROR_ACCESS_DENIED (0x5) 失败。我已经尝试了一些其他帖子建议的许多选项,例如 unmount/lock 但似乎没有任何效果。

有没有人更清楚这个问题的根本原因是什么以及我们如何直接从 Windows API 访问物理驱动器?

这是我使用的示例代码:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windows.h>

DWORD lastError;

int main (void) {
  uint16_t x, y;
  uint8_t  buffer[512];
  DWORD    bytesWritten, status;

  HANDLE sdCardHandle = CreateFile("\\.\PhysicalDrive2", GENERIC_READ    | GENERIC_WRITE,
                                                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

  if(sdCardHandle == INVALID_HANDLE_VALUE) {
    CloseHandle(sdCardHandle);
    return -1;
  }
  
  for (y = 1; y < 10001; y++) { 
    memset(buffer, y, sizeof(buffer));
    if (WriteFile(sdCardHandle, buffer, sizeof(buffer), &bytesWritten, NULL) == 0) {
      lastError = GetLastError();
      printf("WriteFile error: 0x%X\n", lastError);
      CloseHandle(sdCardHandle);
      return -2;
    }
    printf("%d\n", y);
  }

  CloseHandle(sdCardHandle);
  return 0;
}

谢谢!

感谢大家的评论。

所以我找到了解决这个问题的方法(在 Windows 10 中)。 解决方法 锁定、卸载并创建磁盘作为 GPT 以使 Windows 思考它是未分配的磁盘。无论出于何种原因,如果它被格式化为 FAT/FAT32,我将无法将文件写入卡。

以下是适用于我的示例代码:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windows.h>

static CREATE_DISK   raw; // dummy raw to create disk as GPT to trick Windows to see it as unallocated
static DWORD         lastError;
static HANDLE        sd_handle;

int main (void) {
  uint16_t x, y;
  uint8_t  i, buffer[512];
  DWORD    bytes;

  if ((sd_handle = CreateFile("\\.\PhysicalDrive2", 
                              GENERIC_READ|GENERIC_WRITE,
                              FILE_SHARE_READ|FILE_SHARE_WRITE, 
                              NULL, 
                              OPEN_EXISTING, 
                              FILE_FLAG_NO_BUFFERING,
                              NULL)) == INVALID_HANDLE_VALUE) {
    printf("Error 0x%X openning Physical Drive\n", GetLastError());  
    return -1;
  }

  // Workaround to lock, dismount, and create disk as GPT to trick Windows to see drive as unallocated
  if (!DeviceIoControl(sd_handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
    puts("Error: Cannot lock volume");
    CloseHandle(sd_handle);
    return -2;
  }

  if (!DeviceIoControl(sd_handle, FSCTL_DISMOUNT_VOLUME , NULL, 0, NULL, 0, &bytes, NULL)) {
    puts("Error: Cannot dismount volume");
    CloseHandle(sd_handle);
    return -3;
  }

  raw.PartitionStyle = PARTITION_STYLE_GPT;
  if (!DeviceIoControl(sd_handle, IOCTL_DISK_CREATE_DISK, &raw, sizeof(raw), NULL, 0, &bytes, NULL)) {
    puts("Error: Cannot create disk");
    CloseHandle(sd_handle);
    return -4;
  }

  // unlock, close, and reopen again to allow Windows to see it as newly unallocated drive
  if (!DeviceIoControl(sd_handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
    puts("Error: Cannot unlock volume");
    CloseHandle(sd_handle);
    return -5;
  }

  CloseHandle(sd_handle);

  if ((sd_handle = CreateFile("\\.\PhysicalDrive2", 
                              GENERIC_READ|GENERIC_WRITE,
                              FILE_SHARE_READ|FILE_SHARE_WRITE, 
                              NULL, 
                              OPEN_EXISTING, 
                              FILE_FLAG_NO_BUFFERING,
                              NULL)) == INVALID_HANDLE_VALUE) {
    printf("Error 0x%X openning Physical Drive\n", GetLastError());  
    return -6;
  }


  // Note for WriteFile:
  // The GetLastError code ERROR_IO_PENDING is not a failure; 
  // it designates the write operation is pending completion asynchronously.
  for (i = 1; i < 100; i++) {
    memset(buffer, i, sizeof(buffer));
    if (!WriteFile(sd_handle, buffer, sizeof(buffer), &bytes, NULL)
     &&((lastError = GetLastError()) != ERROR_IO_PENDING)) {
      printf("WriteFile error: 0x%X\n", lastError);
      CloseHandle(sd_handle);
      return -7;
    }
  }
}

同样,这只是我发现对我有用的解决方法,但我还不知道确切原因是什么。如果有人知道根本原因并愿意分享,那就太好了。