在Windows上读取/写入未格式化的SD卡

时间:2018-08-01 01:03:02

标签: c++ windows winapi

我正在尝试读取/写入未格式化的SD卡,但是出现问题。我正在使用Windows API打开SD卡的句柄并对其进行读/写,但是根据我的方法,我会遇到各种错误。 下面是我尝试通过卷标访问SD卡的方法:

HANDLE sdCardHandle = CreateFile("\\\\.\\E:", 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;
}

// I have also tried using VirtualAlloc() to get a sector aligned buffer
unit8_t buffer[512] = { 0 };
DWORD bytesWritten = 0;

if(WriteFile(sdCardHandle, buffer, 512, &bytesWritten, NULL) != TRUE)
{
  DWORD lastError = GetLastError();
  CloseHandle(sdCardHandle);
  return;
}

但是WriteFile失败,最后一个错误是87,这是无效参数。我曾尝试在写入之前锁定该卷并卸载该卷,但失败了。

下一个尝试是尝试通过在管理员模式下运行以下命令来写入物理驱动器:

HANDLE sdCardHandle = CreateFile("\\\\.\\PhysicalDrive1", 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;
}

// I have also tried using VirtualAlloc() to get a sector aligned buffer
unit8_t buffer[512] = { 0 };
DWORD bytesWritten = 0;

if(WriteFile(sdCardHandle, buffer, 512, &bytesWritten, NULL) != TRUE)
{
  DWORD lastError = GetLastError();
  CloseHandle(sdCardHandle);
  return;
}

这也会失败,但返回错误23,这是严重的CRC错误。我也尝试过先卸载并锁定卷,但没有任何改变。如果还有其他需要做或尝试的事,请告诉我。

2 个答案:

答案 0 :(得分:1)

来自CreateFile

  

卷句柄可以根据需要自行打开为非缓存句柄   特定的文件系统,即使非缓存选项不是   在CreateFile中指定。您应该假设所有Microsoft文件   系统打开卷句柄为非缓存。的限制   文件的非缓存I / O也适用于卷。

因此我们需要假设将使用FILE_FLAG_NO_BUFFERINGFILE_NO_INTERMEDIATE_BUFFERING):

  

Specifying this flag对呼叫者的   其他ZwXxxFile例程的参数。

     
      
  • 传递给ByteOffsetNtReadFile的任何可选NtWriteFile必须是扇区大小的倍数。
  •   
  • 传递给LengthNtReadFile的{​​{1}}必须是扇区大小的整数。请注意,将读取操作指定为   长度恰好是扇区大小的缓冲区可能会导致
      较少的有效字节数被传输到该缓冲区
      如果在传输过程中到达文件末尾。
  •   
  • 缓冲区必须根据基础设备的对齐要求进行对齐。要获取此信息,   调用NtWriteFile获取文件对象的句柄   代表物理设备,并将该句柄传递给NtCreateFile。有关系统的FILE_XXX_ALIGNMENT值的列表,请参见NtQueryInformationFile
  •   

请注意,这里-Alignment and File Access Requirements是错误的信息:

  

用于读写操作的文件访问缓冲区地址应为   物理扇区对齐,这意味着在内存中的地址上对齐   是卷物理扇区大小的整数倍。   视磁盘而定,此要求可能不会得到执行。

这是错误的-读写操作的缓冲区地址必须与物理扇区对齐。它必须根据基础设备的对齐要求进行对齐。这是绝对不同的东西。 我们可以从FILE_ALIGNMENT_INFO(赢8个以上)或通过FILE_ALIGNMENT_INFORMATIONDEVICE_OBJECT通过NtQueryInformationFile来获得这种对齐方式

在当前代码中,您将缓冲区大小硬编码为512。但是设备的扇区大小可以更大。

  

//我也尝试过使用VirtualAlloc()来对齐扇区   缓冲

我怎么说-您需要扇区对齐的缓冲区(通常设备对齐2-4个字节)。但是您需要扇区大小的缓冲区积分。因此在读取数据之前-您需要先查询扇区大小并要求设备对齐

FileAlignmentInformation

也作为单独的注释-当您使用HANDLE sdCardHandle = CreateFile(L"\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (sdCardHandle != INVALID_HANDLE_VALUE) { FILE_ALIGNMENT_INFO fai; if (GetFileInformationByHandleEx(sdCardHandle, FileAlignmentInfo, &fai, sizeof(fai))) { ULONG BytesReturned; STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR saad; STORAGE_PROPERTY_QUERY spq = { StorageAccessAlignmentProperty, PropertyStandardQuery }; if (DeviceIoControl(sdCardHandle, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), &saad, sizeof(saad), &BytesReturned, 0)) { if (PBYTE pb = new BYTE[saad.BytesPerPhysicalSector + fai.AlignmentRequirement]) { PBYTE buf = (PBYTE)(((ULONG_PTR)pb + fai.AlignmentRequirement) & ~(ULONG_PTR)fai.AlignmentRequirement); if (ReadFile(sdCardHandle, buf, saad.BytesPerPhysicalSector, &BytesReturned, 0)) { __nop(); } else { GetLastError();//RtlGetLastNtStatus(); } delete [] pb; } } } CloseHandle(sdCardHandle); } 时-任何文件属性都将被忽略(仅在创建新文件时使用)。结果使用OPEN_EXISTING-毫无意义(但不会出错-只会被忽略)

答案 1 :(得分:-1)

感谢大家提供的所有帮助和建议。事实证明,我一直都在正确地进行操作。但是,SD卡读取器导致了该错误。我认为问题是BitDefender可能不允许读/写操作发送到物理磁盘。我改用USB适配器,将SD卡显示为USB驱动器,并且我的读/写工作正常!希望这对遇到类似问题的人有所帮助。