1.测试

2.代码
cs
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Windows.Forms;
namespace USBImageCreator
{
public partial class MainForm : Form
{
// 声明UI控件
private ComboBox driveComboBox = new ComboBox();
private TextBox pathTextBox = new TextBox();
private ProgressBar progressBar = new ProgressBar();
private Label statusLabel = new Label();
// 导入Windows API函数
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int SetFilePointer(
IntPtr hFile,
int lDistanceToMove,
ref int lpDistanceToMoveHigh,
uint dwMoveMethod);
// 常量定义
const uint GENERIC_READ = 0x80000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint OPEN_EXISTING = 3;
const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
const uint IOCTL_DISK_GET_LENGTH_INFO = 0x0007405C;
const int SECTOR_SIZE = 512;
const int INVALID_HANDLE_VALUE = -1;
// 全局变量
private IntPtr _driveHandle = IntPtr.Zero;
private long _totalSectors;
private long _sectorsCopied;
private string _imagePath;
private BackgroundWorker _worker;
public MainForm()
{
InitializeComponent();
CheckAdminStatus();
InitializeUI();
}
private void CheckAdminStatus()
{
using (var identity = WindowsIdentity.GetCurrent())
{
var principal = new WindowsPrincipal(identity);
if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
{
var result = MessageBox.Show("此程序需要管理员权限才能访问物理驱动器。\n是否现在以管理员身份重启?",
"需要管理员权限", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
RestartAsAdmin();
}
else
{
Environment.Exit(0);
}
}
}
}
private void RestartAsAdmin()
{
var startInfo = new ProcessStartInfo
{
FileName = Application.ExecutablePath,
UseShellExecute = true,
Verb = "runas"
};
try
{
Process.Start(startInfo);
Environment.Exit(0);
}
catch (Exception ex)
{
MessageBox.Show($"无法以管理员身份重启: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(1);
}
}
private void InitializeUI()
{
// 设置窗体属性
this.Size = new Size(550, 350);
this.BackColor = Color.FromArgb(45, 45, 48);
this.ForeColor = Color.White;
this.Font = new Font("Segoe UI", 9);
this.Text = "U盘映像生成工具";
// 标题标签
var titleLabel = new Label
{
Text = "U盘映像生成工具",
Font = new Font("Segoe UI", 14, FontStyle.Bold),
ForeColor = Color.LightSkyBlue,
AutoSize = true,
Location = new Point(20, 20)
};
// 选择U盘标签
var selectLabel = new Label
{
Text = "选择U盘:",
AutoSize = true,
Location = new Point(20, 70)
};
// U盘下拉框
driveComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
driveComboBox.Location = new Point(100, 67);
driveComboBox.Size = new Size(300, 25);
driveComboBox.BackColor = Color.FromArgb(60, 60, 65);
driveComboBox.ForeColor = Color.White;
driveComboBox.FlatStyle = FlatStyle.Flat;
// 刷新按钮
var refreshButton = new Button
{
Text = "刷新",
Location = new Point(410, 65),
Size = new Size(80, 30),
FlatStyle = FlatStyle.Flat,
BackColor = Color.FromArgb(70, 70, 75),
ForeColor = Color.White
};
refreshButton.Click += (s, e) => LoadDrives();
// 选择保存位置标签
var saveLabel = new Label
{
Text = "保存位置:",
AutoSize = true,
Location = new Point(20, 120)
};
// 保存路径文本框
pathTextBox.Location = new Point(100, 117);
pathTextBox.Size = new Size(300, 25);
pathTextBox.BackColor = Color.FromArgb(60, 60, 65);
pathTextBox.ForeColor = Color.White;
pathTextBox.ReadOnly = true;
// 浏览按钮
var browseButton = new Button
{
Text = "浏览...",
Location = new Point(410, 115),
Size = new Size(80, 30),
FlatStyle = FlatStyle.Flat,
BackColor = Color.FromArgb(70, 70, 75),
ForeColor = Color.White
};
browseButton.Click += BrowseButton_Click;
// 进度条
progressBar.Location = new Point(20, 170);
progressBar.Size = new Size(500, 25);
progressBar.Style = ProgressBarStyle.Continuous;
// 进度标签
statusLabel.AutoSize = true;
statusLabel.Location = new Point(20, 210);
statusLabel.Text = "就绪";
// 开始按钮
var startButton = new Button
{
Text = "开始创建映像",
Location = new Point(150, 250),
Size = new Size(200, 40),
FlatStyle = FlatStyle.Flat,
BackColor = Color.FromArgb(0, 122, 204),
ForeColor = Color.White,
Font = new Font("Segoe UI", 10, FontStyle.Bold)
};
startButton.Click += StartButton_Click;
// 添加控件
this.Controls.Add(titleLabel);
this.Controls.Add(selectLabel);
this.Controls.Add(driveComboBox);
this.Controls.Add(refreshButton);
this.Controls.Add(saveLabel);
this.Controls.Add(pathTextBox);
this.Controls.Add(browseButton);
this.Controls.Add(progressBar);
this.Controls.Add(statusLabel);
this.Controls.Add(startButton);
// 加载驱动器
LoadDrives();
}
private void LoadDrives()
{
driveComboBox.Items.Clear();
var drives = DriveInfo.GetDrives();
foreach (var drive in drives)
{
if (drive.DriveType == DriveType.Removable && drive.IsReady)
{
try
{
double sizeGB = drive.TotalSize / (1024.0 * 1024 * 1024);
string item = $"{drive.Name} ({drive.VolumeLabel} - {sizeGB:0.00} GB)";
driveComboBox.Items.Add(item);
}
catch
{
// 忽略无法访问的驱动器
}
}
}
if (driveComboBox.Items.Count > 0)
{
driveComboBox.SelectedIndex = 0;
}
else
{
driveComboBox.Items.Add("未检测到可移动磁盘");
driveComboBox.SelectedIndex = 0;
}
}
private void BrowseButton_Click(object sender, EventArgs e)
{
using (var saveDialog = new SaveFileDialog())
{
saveDialog.Filter = "磁盘映像文件 (*.img)|*.img|所有文件 (*.*)|*.*";
saveDialog.Title = "保存U盘映像";
saveDialog.DefaultExt = "img";
if (saveDialog.ShowDialog() == DialogResult.OK)
{
pathTextBox.Text = saveDialog.FileName;
}
}
}
private void StartButton_Click(object sender, EventArgs e)
{
if (driveComboBox.SelectedIndex < 0 || driveComboBox.SelectedItem.ToString().Contains("未检测到"))
{
MessageBox.Show("请选择有效的U盘", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (string.IsNullOrEmpty(pathTextBox.Text))
{
MessageBox.Show("请选择映像文件保存位置", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string selectedDrive = driveComboBox.SelectedItem.ToString();
string driveLetter = selectedDrive.Substring(0, 2); // 获取盘符 (如 "D:")
_imagePath = pathTextBox.Text;
// 初始化后台工作线程
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += Worker_DoWork;
_worker.ProgressChanged += Worker_ProgressChanged;
_worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
// 禁用UI控件
driveComboBox.Enabled = false;
pathTextBox.Enabled = false;
((Control)sender).Enabled = false;
// 开始创建映像
_worker.RunWorkerAsync(driveLetter);
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
string driveLetter = e.Argument as string;
_sectorsCopied = 0;
try
{
// 打开物理驱动器
_driveHandle = OpenPhysicalDrive(driveLetter);
if (_driveHandle.ToInt32() == INVALID_HANDLE_VALUE)
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, $"无法打开驱动器 {driveLetter} (错误代码: {error})");
}
// 获取总扇区数
_totalSectors = GetDiskSizeInSectors(_driveHandle);
long totalBytes = _totalSectors * SECTOR_SIZE;
// 创建映像文件
using (var fs = new FileStream(_imagePath, FileMode.Create, FileAccess.Write))
{
const int BUFFER_SECTORS = 2048; // 每次读取的扇区数(1MB缓冲)
byte[] buffer = new byte[BUFFER_SECTORS * SECTOR_SIZE];
var timer = new Stopwatch();
timer.Start();
while (_sectorsCopied < _totalSectors)
{
if (_worker.CancellationPending)
{
e.Cancel = true;
return;
}
// 计算本次读取扇区数
int sectorsToRead = (int)Math.Min(
BUFFER_SECTORS,
_totalSectors - _sectorsCopied
);
// 从驱动器读取
if (!ReadSectors(_driveHandle, buffer, _sectorsCopied, sectorsToRead))
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error, $"读取驱动器失败 (错误代码: {error})");
}
// 写入映像文件
fs.Write(buffer, 0, sectorsToRead * SECTOR_SIZE);
// 更新进度
_sectorsCopied += sectorsToRead;
double progress = (double)_sectorsCopied / _totalSectors * 100;
double speedMB = (_sectorsCopied * SECTOR_SIZE) /
(timer.Elapsed.TotalSeconds * 1024 * 1024);
_worker.ReportProgress((int)progress,
$"进度: {progress:0.00}% | 速度: {speedMB:0.0} MB/s");
}
timer.Stop();
_worker.ReportProgress(100, $"映像创建完成! 耗时: {timer.Elapsed.TotalSeconds:0.0}秒");
}
}
finally
{
// 关闭驱动器句柄
if (_driveHandle != IntPtr.Zero)
CloseHandle(_driveHandle);
}
}
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
statusLabel.Text = e.UserState as string;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show($"创建映像时出错:\n{e.Error.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (e.Cancelled)
{
statusLabel.Text = "操作已取消";
}
else
{
// 成功完成
if (File.Exists(_imagePath))
{
long fileSize = new FileInfo(_imagePath).Length;
double sizeGB = fileSize / (1024.0 * 1024 * 1024);
statusLabel.Text = $"映像创建成功! 大小: {sizeGB:0.00} GB";
}
}
// 启用UI控件
driveComboBox.Enabled = true;
pathTextBox.Enabled = true;
foreach (Control c in Controls)
{
if (c is Button btn && btn.Text == "开始创建映像")
{
btn.Enabled = true;
break;
}
}
}
// 打开物理驱动器
static IntPtr OpenPhysicalDrive(string drivePath)
{
string physicalPath = @"\\.\" + drivePath.TrimEnd('\\');
return CreateFile(
physicalPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
IntPtr.Zero
);
}
// 获取磁盘扇区总数
static long GetDiskSizeInSectors(IntPtr driveHandle)
{
byte[] outBuffer = new byte[8];
GCHandle pinnedBuffer = GCHandle.Alloc(outBuffer, GCHandleType.Pinned);
IntPtr bufferPtr = pinnedBuffer.AddrOfPinnedObject();
try
{
uint bytesReturned;
if (!DeviceIoControl(
driveHandle,
IOCTL_DISK_GET_LENGTH_INFO,
IntPtr.Zero,
0,
bufferPtr,
(uint)outBuffer.Length,
out bytesReturned,
IntPtr.Zero))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
long totalBytes = BitConverter.ToInt64(outBuffer, 0);
return totalBytes / SECTOR_SIZE; // 转换为扇区数
}
finally
{
pinnedBuffer.Free();
}
}
// 读取扇区数据
static bool ReadSectors(IntPtr driveHandle, byte[] buffer, long startSector, int sectorCount)
{
uint bytesRead;
long offset = startSector * SECTOR_SIZE;
// 设置文件指针
if (SetFilePointer(driveHandle, offset) != offset)
return false;
return ReadFile(driveHandle, buffer, (uint)(sectorCount * SECTOR_SIZE),
out bytesRead, IntPtr.Zero);
}
// 设置文件指针
static long SetFilePointer(IntPtr hFile, long distance)
{
const uint FILE_BEGIN = 0;
int low = (int)(distance & 0xFFFFFFFF);
int high = (int)(distance >> 32);
return SetFilePointer(hFile, low, ref high, FILE_BEGIN);
}
//[STAThread]
//static void Main()
//{
// Application.EnableVisualStyles();
// Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new MainForm());
//}
}
}