DiskIO是可以从底层直接读写系统中的磁盘,比如SD卡,你甚至可以把你的系统盘的启动引导修改了,如果你想的话。。。
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace WindowsAPI
{
public class TFDriveInfo
{
public System.IO.DriveInfo TFInfo { get; }
public string DType => TFInfo.DriveType == System.IO.DriveType.Removable ? "可移动设备:" : TFInfo.DriveType == System.IO.DriveType.CDRom ? "光盘:" : TFInfo.DriveType == System.IO.DriveType.Fixed ? "本地磁盘:" : "未知设备:";
public override string ToString() => $"{DType}{TFInfo.VolumeLabels}({TFInfo.Names})";
public TFDriveInfo(System.IO.DriveInfo tFInfo)
{
TFInfo = tFInfo;
}
}
public class TFDiskInfo
{
public int DiskId { get; }
public HardDiskInfo TFInfo { get; }
public override string ToString() => $"Disk{DiskId}:{TFInfo.ModuleNumbers}({TFInfo.Capacitys}Mb)";
public TFDiskInfo(int id, HardDiskInfo tFInfo)
{
DiskId = id;
TFInfo = tFInfo;
}
}
public class TFDiskDriveInfo
{
public string Name { get; set; } = string.Empty;
public string SerialNumber { get; set; } = string.Empty;
public string Signature { get; set; } = string.Empty;
public string Index { get; set; } = string.Empty;
public string MediaType { get; set; } = string.Empty;
public string Size { get; set; } = string.Empty;
public string Status { get; set; } = string.Empty;
public string Caption { get; set; } = string.Empty;
public long LSize => long.Parse(Size);
public string DiskType => MediaType.StartsWith("Fixed") ? "本地磁盘" : MediaType.StartsWith("Extern") ? "外部磁盘" : MediaType.StartsWith("Remov") ? "可移动存储" : "未知磁盘";
public override string ToString() => $"{DiskType}:{Index}({Status})({Caption})";
}
public class DiskIO : IDisposable
{
/// <summary>
/// 当前被操作设备的名称
/// </summary>
public string DirverNames { get; private set; }
/// <summary>
/// 当前操作设备的句柄
/// </summary>
private SafeFileHandle DirverHandles;
/// <summary>
/// 当前被操作设备的大小
/// </summary>
public long Sector { get; private set; }
/// <summary>
/// 通过盘符创建对象可以读写指定的磁盘内容
/// </summary>
/// <param name="driveInfo"></param>
public DiskIO(System.IO.DriveInfo driveInfo)
{
OpenDriver(driveInfo);
}
/// <summary>
/// 通过物理磁盘编号创建可以读写指定的物理磁盘,可以修改mbr表等
/// </summary>
/// <param name="driverId"></param>
public DiskIO(string drivername, long size)
{
OpenDriver(drivername, size);
}
/// <summary>
/// 打开指定的可读写设备
/// </summary>
/// <param name="dirverName"></param>
/// <param name="lsize"></param>
public void OpenDriver(string dirverName, long lsize)
{
SectorLength = lsize;
DirverName = dirverName.Trim();
DirverHandle?.Close();
DirverHandle?.Dispose();
DirverHandle = Kernel32.OpenWriteRead(DirverName);
}
/// <summary>
/// 打开一个盘符
/// </summary>
/// <param name="driveInfo"></param>
public void OpenDriver(System.IO.DriveInfo driveInfos)
{
OpenDriver("\\\\.\\" + driveInfo.Name.Trim('\\'), driveInfo.TotalSize / 512);
}
/// <summary>
/// 打开指定的物理磁盘
/// </summary>
/// <param name="driverId"></param>
public void OpenDriver(int driverId)
{
OpenDriver($"\\\\.\\PHYSICALDRIVE{driverId}", 8000000000000L / 512);//最大8T
}
///// <summary>
///// 获取所有已经连接的TF卡的PHYSICALDRIVE名称,key用来打开设备
///// </summary>
///// <returns></returns>
//public static TFDiskDriveInfo[] GetHddInfos()
//{
// var list = new List<TFDiskDriveInfo>();
// try
// {
// using var opSearch = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");//Win32_USBHub//Win32_DiskDrive//
// foreach (ManagementObject opInfo in opSearch.Get().Cast<ManagementObject>())
// {
// var name = $"{opInfo["Name"]}";
// var snum = $"{opInfo["SerialNumber"]}";
// //var pnpid = $"{opInfo["PNPDeviceID"]}";
// //var des = $"{opInfo["Description"]}";
// var sign = $"{opInfo["Signature"]}";
// var idex = $"{opInfo["Index"]}";
// //var mms = $"{opInfo["MaxMediaSize"]}";
// var mt = $"{opInfo["MediaType"]}";
// var sz = $"{opInfo["Size"]}";
// var stat = $"{opInfo["Status"]}";
// //var sname = $"{opInfo["SystemName"]}";
// //var tsec = $"{opInfo["TotalSectors"]}";
// var capt = $"{opInfo["Caption"]}";
// //var part = $"{opInfo["Partitions"]}";
// list.Add(new TFDiskDriveInfo()
// {
// Name = name,
// SerialNumber = snum,
// Signature = sign,
// Index = idex,
// MediaType = mt,
// Size = sz,
// Status = stat,
// Caption = capt,
// });
// }
// }
// catch
// {
// }
// return list.Where(x => x.MediaType.StartsWith("Remov")).ToArray();
//}
/// <summary>
/// 获得硬盘信息
/// </summary>
/// <param name="driveIndex">
/// 硬盘序号byte temp = new byte(); temp = 0x0;
///参数根据你的硬盘的数量定 0表示第一个硬盘
///</param>
/// <returns>硬盘信息</returns>
/// <remarks>
/// 参考lu0的文章:http://lu0s1.3322.org/App/2k1103.html
/// by sunmast for everyone
/// thanks lu0 for his great works
/// 在Windows 98/ME中,S.M.A.R.T并不缺省安装,请将SMARTVSD.VXD拷贝到%SYSTEM%\IOSUBSYS目录下。
/// 在Windows 2000/2003下,需要Administrators组的权限。
/// 只能获取SATA硬盘的信息
/// </remarks>
/// <example>
/// AtapiDevice.GetHddInfo()
/// </example>
public static HardDiskInfo GetHddInfo(byte driveIndexs)
{
switch(Environment.OSVersion.Platform)
{
case PlatformID.Win32Windows: return GetHddInfo9x(driveIndex);
case PlatformID.Win32NT: return GetHddInfoNT(driveIndex);
case PlatformID.Win32S: throw new NotSupportedException("Win32s is not supported.");
case PlatformID.WinCE: throw new NotSupportedException("WinCE is not supported.");
default: throw new NotSupportedException("Unknown Platform.");
};
}
private static HardDiskInfo GetHddInfo9x(byte driveIndexs)
{
var vers = new GetVersionOutParams();
var inParam = new SendCmdInParams();
var outParam = new SendCmdOutParams();
uint bytesReturned = 0;
SafeFileHandle hDevice = Kernel32.CreateFile(@"\\.\Smartvsd", 0, 0, IntPtr.Zero, CreationDisposition.CREATE_NEW, 0, IntPtr.Zero);
if (hDevice.IsInvalid)
{
throw new Exception("Open smartvsd.vxd failed.");
}
if (0 == Kernel32.DeviceIoControl(hDevice, IoControlCode.DFP_GET_VERSION, IntPtr.Zero, 0, ref vers, (uint)Marshal.SizeOf(vers), ref bytesReturned, IntPtr.Zero))
{
//CloseHandle(hDevice);
hDevice.Dispose();
throw new Exception("DeviceIoControl failed:DFP_GET_VERSION");
}
// If IDE identify command not supported, fails
if (0 == (vers.fCapabilities & 1))
{
//CloseHandle(hDevice);
hDevice.Dispose();
throw new Exception("Error: IDE identify command not supported.");
}
if (0 != (driveIndex & 1))
{
inParam.irDriveRegs.bDriveHeadReg = 0xb1;
}
else
{
inParam.irDriveRegs.bDriveHeadReg = 0xa1;
}
if (0 != (vers.fCapabilities & (16 >> driveIndex)))
{
// We don''t detect a ATAPI device.
//CloseHandle(hDevice);
hDevice.Dispose();
throw new Exception($"Drive {driveIndex} is a ATAPI device, we don''t detect it");
}
else
{
inParam.irDriveRegs.bCommandReg = 0xec;
}
inParam.bDriveNumber = driveIndex;
inParam.irDriveRegs.bSectorCountReg = 5;
inParam.irDriveRegs.bSectorNumberReg = 5;
inParam.cBufferSize = 128;
if (0 == Kernel32.DeviceIoControl(hDevice, IoControlCode.DFP_RECEIVE_DRIVE_DATA, ref inParam, (uint)Marshal.SizeOf(inParam), ref outParam, (uint)Marshal.SizeOf(outParam), ref bytesReturned, IntPtr.Zero))
{
hDevice.Dispose();
throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
}
hDevice.Dispose();
return GetHardDiskInfo(outParam.bBuffer);
}
private static HardDiskInfo GetHddInfoNT(byte driveIndex)
{
var vers = new GetVersionOutParams();
var inParam = new SendCmdInParams();
var outParam = new SendCmdOutParams();
uint bytesReturned = 0;
// We start in NT/Win2000
SafeFileHandle hDevice = Kernel32.OpenWriteRead($"\\\\.\\PhysicalDrive{driveIndex}");
if (hDevice.IsInvalid)
{
throw new Exception("CreateFile faild.");
}
if (0 == Kernel32.DeviceIoControl(hDevice, IoControlCode.DFP_GET_VERSION, IntPtr.Zero, 0, ref vers, (uint)Marshal.SizeOf(vers), ref bytesReturned, IntPtr.Zero))
{
hDevice.Dispose();
throw new Exception($"Drive {(driveIndex + 1)} may not exists.");
}
// If IDE identify command not supported, fails
if (0 == (vers.fCapabilities & 1))
{
hDevice.Dispose();
throw new Exception("Error: IDE identify command not supported.");
}
// Identify the IDE drives
if (0 != (driveIndex & 1))
{
inParam.irDriveRegs.bDriveHeadReg = 0xb0;
}
else
{
inParam.irDriveRegs.bDriveHeadReg = 0xa0;
}
if (0 != (vers.fCapabilities & (16 >> driveIndex)))
{
// We don''t detect a ATAPI device.
hDevice.Dispose();
throw new Exception($"Drive {(driveIndex + 1)} is a ATAPI device, we don''t detect it");
}
else
{
inParam.irDriveRegs.bCommandReg = 0xec;
}
inParam.bDriveNumber = driveIndex;
inParam.irDriveRegs.bSectorCountReg = 1;
inParam.irDriveRegs.bSectorNumberReg = 1;
inParam.cBufferSize = 512;
if (0 == Kernel32.DeviceIoControl(hDevice, IoControlCode.DFP_RECEIVE_DRIVE_DATA, ref inParam, (uint)Marshal.SizeOf(inParam), ref outParam, (uint)Marshal.SizeOf(outParam), ref bytesReturned, IntPtr.Zero))
{
hDevice.Dispose();
throw new Exception("DeviceIoControl failed: DFP_RECEIVE_DRIVE_DATA");
}
hDevice.Dispose();
return GetHardDiskInfo(outParam.bBuffer);
}
private static HardDiskInfo GetHardDiskInfo(IdSector phdinfo)
{
HardDiskInfo hddInfo = new HardDiskInfo();
ChangeByteOrder(phdinfo.sModelNumber);
hddInfo.ModuleNumber = Encoding.ASCII.GetString(phdinfo.sModelNumber).Trim();
ChangeByteOrder(phdinfo.sFirmwareRev);
hddInfo.Firmware = Encoding.ASCII.GetString(phdinfo.sFirmwareRev).Trim();
ChangeByteOrder(phdinfo.sSerialNumber);
hddInfo.SerialNumber = Encoding.ASCII.GetString(phdinfo.sSerialNumber).Trim();
hddInfo.Capacity = phdinfo.ulTotalAddressableSectors / 2 / 1024;
return hddInfo;
}
private static void ChangeByteOrder(byte[] charArray)
{
byte temp;
for (int i = 0; i < charArray.Length; i += 2)
{
temp = charArray[i];
charArray[i] = charArray[i + 1];
charArray[i + 1] = temp;
}
}
/// <summary>
/// 重新设置读写位置
/// </summary>
/// <param name="lIndex"></param>
/// <param name="hptr"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public uint SeekTo(long lIndex, IntPtr hptr)
{
var seek = Kernel32.SetFilePointer(DirverHandle, lIndex, ref hptr, EMoveMethod.Begin);
if (seek == Kernel32.INVALID_SET_FILE_POINTER)
{//检查可能出现的错误
var err = Kernel32.GetLastError();
if (err != 0) throw new Exception($"读写时出现错误:{err:X}");
}
return seek;
}
/// <summary>
/// 写入扇区512字节
/// </summary>
/// <param name="SectorBytes"></param>
/// <param name="addr">指定写入的地址,必须扇区对齐</param>
public uint WritSector(byte[] SectorBytes, long addr)
{
if (SectorBytes.Length % 512 != 0) throw new ArgumentException("数据大小应该对齐到512的整数倍", nameof(SectorBytes));
if (addr > SectorLength) throw new ArgumentException("读写区域超出范围", nameof(addr));
SeekTo(addr, IntPtr.Zero);
Kernel32.WriteFile(DirverHandle, SectorBytes, (uint)SectorBytes.Length, out uint dwCB, IntPtr.Zero);
return dwCB;
}
/// <summary>
/// 读取512单扇区
/// </summary>
/// <param name="ReturnByte"></param>
/// <param name="addr"></param>
public uint ReadSector([Out] byte[] ReturnByte, long addr)
{
if (addr > SectorLength) throw new ArgumentException("读写区域超出范围", nameof(addr));
SeekTo(addr, IntPtr.Zero);
Kernel32.ReadFile(DirverHandle, ReturnByte, (uint)ReturnByte.Length, out uint dwCB, IntPtr.Zero);
return dwCB;
}
/// <summary>
/// 释放对象
/// </summary>
public void Dispose()
{
DirverHandle?.Close();
DirverHandle?.Dispose();
GC.SuppressFinalize(this);
}
}
}