c# U盘映像生成工具

发布于:2025-07-08 ⋅ 阅读:(16) ⋅ 点赞:(0)

1.测试

2.代码

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());
        //}
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到