C# - 访问外部硬盘上高偏移量(超过 4G)的原始扇区
C# - Accessing Raw Sectors in high offset (over 4G) on external HDD
我在程序中使用 "Kernel32.dll" 功能来访问 WinXP SP3 OS(外部 HDD)上的原始磁盘扇区。
一切正常,直到程序到达扇区号 8388607 - 这意味着 SetFilePointer 中的字节偏移量超过 32 位(uint!)。
但是我的代码,如下所示,使用所有变量作为 "long"。我做错了什么?
代码(在 "Dump" 按钮上单击):
int drive = DRV.SelectedIndex; // DRV is the drive combo box
long bps = BytesPerSector(drive), spt = GetTotalSectors(drive);
string dr = DRV.SelectedItem.ToString();
int moveToHigh, read = 0;
uint GENERIC_READ = 0x80000000;
uint OPEN_EXISTING = 3;
SafeFileHandle handleValue = CreateFile(dr, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (handleValue.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
// idx = Loop starting index
// FS = The starting sector index
// TS = The final sector index
long idx = (FS == -1) ? 0 : FS, tot = (TS == -1) ? spt : TS;
for ( ; idx < tot; idx++)
{
byte[] b = new byte[bps];
// HERE IS THE ISSUE!!!
SetFilePointer(handleValue, idx*bps), out moveToHigh, EMoveMethod.Current);
if (ReadFile(handleValue, b, bps, out read, IntPtr.Zero) == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (this.IsDisposed == true) { handleValue.Close(); break; }
Application.DoEvents();
}
handleValue.Close();
kernel32.dll外部函数:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] long lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
我尝试了很多东西,但不知道哪里出了问题,应用程序以致命异常结束,要求发送错误报告
非常感谢
您的 P/Invoke 定义有误。该函数采用 32 位值,但您将其定义为 64 位值。它不会正常工作,绝对不会超过 32 位变量的取值范围。
请参阅 pinvoke.net:
中有关如何使用的定义和示例
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SetFilePointer(IntPtr handle, int lDistanceToMove, out int lpDistanceToMoveHigh, uint dwMoveMethod);
int lo = (int)(offset & 0xffffffff);
int hi = (int)(offset >> 32);
lo = SetFilePointer(handle, lo, out hi, moveMethod);
因此您需要将 64 位值一分为二,并为函数提供两部分。
也不要对整数使用双精度数。当准确性结束并且没有理由使用它们时,您会遇到麻烦。
我在程序中使用 "Kernel32.dll" 功能来访问 WinXP SP3 OS(外部 HDD)上的原始磁盘扇区。
一切正常,直到程序到达扇区号 8388607 - 这意味着 SetFilePointer 中的字节偏移量超过 32 位(uint!)。 但是我的代码,如下所示,使用所有变量作为 "long"。我做错了什么?
代码(在 "Dump" 按钮上单击):
int drive = DRV.SelectedIndex; // DRV is the drive combo box
long bps = BytesPerSector(drive), spt = GetTotalSectors(drive);
string dr = DRV.SelectedItem.ToString();
int moveToHigh, read = 0;
uint GENERIC_READ = 0x80000000;
uint OPEN_EXISTING = 3;
SafeFileHandle handleValue = CreateFile(dr, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (handleValue.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
// idx = Loop starting index
// FS = The starting sector index
// TS = The final sector index
long idx = (FS == -1) ? 0 : FS, tot = (TS == -1) ? spt : TS;
for ( ; idx < tot; idx++)
{
byte[] b = new byte[bps];
// HERE IS THE ISSUE!!!
SetFilePointer(handleValue, idx*bps), out moveToHigh, EMoveMethod.Current);
if (ReadFile(handleValue, b, bps, out read, IntPtr.Zero) == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (this.IsDisposed == true) { handleValue.Close(); break; }
Application.DoEvents();
}
handleValue.Close();
kernel32.dll外部函数:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] long lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
我尝试了很多东西,但不知道哪里出了问题,应用程序以致命异常结束,要求发送错误报告
非常感谢
您的 P/Invoke 定义有误。该函数采用 32 位值,但您将其定义为 64 位值。它不会正常工作,绝对不会超过 32 位变量的取值范围。
请参阅 pinvoke.net:
中有关如何使用的定义和示例[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SetFilePointer(IntPtr handle, int lDistanceToMove, out int lpDistanceToMoveHigh, uint dwMoveMethod);
int lo = (int)(offset & 0xffffffff);
int hi = (int)(offset >> 32);
lo = SetFilePointer(handle, lo, out hi, moveMethod);
因此您需要将 64 位值一分为二,并为函数提供两部分。
也不要对整数使用双精度数。当准确性结束并且没有理由使用它们时,您会遇到麻烦。