C#上的SetFilePointer突然停止工作

时间:2013-12-21 06:45:23

标签: c# pinvoke

背景:
在我的项目中,我需要逐个部门扫描我的硬盘驱动器。我正在使用Pinvoke of Kernel32.dll。 HDD的大小为160GB(接近312,000,000 LBA)。 循环扫描每个迭代8000个扇区。

问题:
不知何故,在成功扫描40000个扇区之后,循环堆栈没有移动,我甚至无法终止应用程序,除非我将断开HDD(外部媒体)。 我知道我的媒体没有任何损坏的部门。

使用Kernel32.dll的SetFilePointer设置文件指针时,我注意偏移的低位和高位,但是偏移量甚至没有达到1GB,所以我想在这一点上没有什么可做的,但在其他地方(我想是的,但我不确定,我对这个Pinvoke很新)。

这是我的以下代码:

    public enum EMoveMethod : uint
    {
        Begin = 0,
        Current = 1,
        End = 2
    }

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern int SetFilePointer(
        [In] SafeFileHandle hFile,
        [In] int lDistanceToMove,
        [In, Out] ref 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.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
       int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

    static public int BytesPerSector(int drive)
    {
        int driveCounter = 0;
        try
        {
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskDrive");
            foreach (ManagementObject queryObj in searcher.Get())
            {
                if (driveCounter == drive)
                {
                    var t = queryObj["BytesPerSector"];
                    return int.Parse(t.ToString());
                }
                driveCounter++;
            }
        }
        catch (ManagementException) { return -1; }
        return 0;
    }

    static public int GetTotalSectors(int drive)
    {
        int driveCount = 0;
        try
        {
            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskDrive");
            foreach (ManagementObject queryObj in searcher.Get())
            {
                if (driveCount == drive)
                {
                    var t = queryObj["TotalSectors"];
                    return int.Parse(t.ToString());
                }
                driveCount++;
            }
        }
        catch (ManagementException) { return -1; }
        return -1;
    }

    static private byte[] DumpSector(string drive, int sector, int bytesPerSector)
    {
        const uint GENERIC_READ = 0x80000000;
        const uint OPEN_EXISTING = 3;

        byte[] buf = null;
        try
        {
            SafeFileHandle handleValue = CreateFile(drive, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
            if (handleValue.IsInvalid) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); }
            long sec = (long)sector * (long)bytesPerSector;
            buf = new byte[bytesPerSector];
            int read = 0, moveToHigh = (int)(sec >> 32);
            int Res=SetFilePointer(handleValue, (int)(sec & 0xffffffff), ref moveToHigh, EMoveMethod.Begin);
            if (Res == -1) { Console.WriteLine("ERROR: ");  return null; }
            if (ReadFile(handleValue, buf, bytesPerSector, out read, IntPtr.Zero)==0)
            {
                Console.WriteLine("ERROR: "); return null; 
            }
            handleValue.Close();
        }
        catch (Exception Ex) { Console.WriteLine("ERROR: {0}", Ex.Message); return null; }
        return buf;
    }

    static void Scanner()
    {
        if (DRV == -1) { Console.WriteLine("ERROR: Please select drive using <A>+ drive index number."); return; } // error
        const int BFB = 8000;
        byte[] b = DumpSector(HDDs[DRV], MyOffset, BlockSize * BFB);
        int Sec16 = 0, IntOff = 0, JMP = 0;
        string DMP = "";
        long FF = ((long)MyOffset * BlockSize) + (IntOff * 16);
        Console.Write("0x{0}   ", FF.ToString("X10"));
        for (int byt = 0; byt < b.Length; byt++)
        {
            DMP += (char)b[byt];
            Console.Write("{0} ", b[byt].ToString("X2"));
            Sec16++; FF++;
            if (Sec16 == 8) Console.Write("  ");
            if (Sec16 == 16)
            {
                Console.Write("  {0}", DMP.Replace("\x07", "").Replace("\x08", "").Replace("\x0a", "").Replace("\x0d", "").Replace("\x09", "")); Console.WriteLine();
                DMP = ""; Sec16 = 0; IntOff++; JMP++;
                if (JMP == 32) { JMP = 0; IntOff += 224; FF += 3584; byt += 3584; }
                Console.Write("0x{0}   ", FF.ToString("X10"));
            }
        }
        Console.WriteLine("- End of scan -");
    }

该程序是控制台应用程序,以加快进程。

1 个答案:

答案 0 :(得分:0)

即使您滥用了某些API,您的程序也不会停止。这不太可能是API使用错误。

这可能是硬件错误。不可杀戮过程是典型的症状。当最后一个挂起的IO完成时,只能通过Windows杀死进程。磁盘驱动程序正在等待完成您的IO,但磁盘从不响应(或仅在长时间超时后)。