如何在C#中管理可移动驱动器

230 阅读8分钟

如何在C#中管理可移动驱动器

我们时常使用可移动IO设备将文件传入或传出我们的PC,也可以用来存储文件。

然而,出于安全、隐私和其他方面的考虑,我们需要一个工具来管理这些设备以及它们如何与我们的计算机互动。

在本教程中,我们将创建一个.NET 桌面工具,使我们能够管理Windows计算机上的USB端口。我们将能够改变可移动驱动器的读/写权限。

我们将从创建用户界面的详细指南开始,然后研究读/写操作背后的代码。

先决条件

要继续学习本教程,您将需要

  1. 带有.NET 框架的[Visual Studio]。
  2. C#和.NET 框架的基本知识。
  3. 一个闪存盘或任何其他可移动的驱动器,用于测试目的。

第1步 - 创建项目

我们将首先打开Visual Studio,从Get started 选项中选择create new project

在下一个窗口(Create a new project),我们将选择Windows Forms App 模板,然后点击Next

creating a new winforms project

在下一个窗口(Configure your new project),我们将把我们的项目重命名为IOManager ,其他字段保留其默认值,然后点击Next 按钮。

configure your new project

Additional information 窗口中,我们将保留其默认值并点击Create

Additional information

加载该项目后,你应该看到与此类似的东西。

Initial window

第2步 - 设计用户界面

重命名表单标题

要重新命名表单标题,点击Form 1 ,在properties 边栏中的Text ,改为I/O Manager

Renaming Form1

改变背景颜色

点击I/O Manager 表单,在Properties 边栏下的BackColor ,将背景颜色改为Teal

Changing form1 background color

改变表格边框

这个属性改变了我们表单的边框的外观。例如,它删除了maximizeminimize 按钮。

要做到这一点,请点击I/O Manager 表格,并在Properties 侧边栏下的FormBorderStyle ,选择FixedToolWindow

Form border style

添加指示标签

Toolbox ,在表格的top center ,拖放一个label 。点击label ,在其属性中的Text ,改为Please unplug then plug all USB devices

同时,将字体大小改为14 ,将粗体设置为True

Label1 properties

添加USB端口控件

Toolbox ,在instruction label 的正下方拖放一个groupbox ,并在其size 属性下将其尺寸设置为560, 150

groupBox1 的文本改为Enable/Disable ,然后将其background color 改为更兼容的颜色。我们将把我们的颜色改为ActiveCaption

接下来,将两个radio buttons 拖入组框,并将其text 属性改为Enable USB PortsDisable USB Ports

现在你应该有这样的东西了。

Groupbox1

添加读/写控件

在这一步,我们将拖放另一个groupbox ,就在第一个的下面(为了更好的设计,请确保你将它们对齐),然后将text 的属性改为Read/Write

我们还需要在大小属性下将其尺寸设置为560, 150 。建议将其背景颜色与第一个组框(ActiveCaption)相匹配。

让我们在这个组框中添加两个单选按钮,并将其文本属性分别改为Activate read only for removable drivesClear read only for removable drives

Both radioButtons

添加控制按钮

为了完成用户界面,我们需要添加我们的控制按钮。拖放一个按钮,把它放在Read/Write 组框的下面。

然后为该按钮设置以下属性。

  • 背景色为Black
  • FlatStyle为Popup
  • 字体名称为Perpetua Titling MT
  • 字体大小为12
  • 前面的颜色为White
  • 大小属性为:100, 40

Button properties

复制该按钮,并在水平线上粘贴两次(在组框下面相邻)。

然后将它们的Text 属性分别编辑为OK,CancelClose 。最后的结果应该是这样的。

With all buttons

第3步--向表单添加代码

添加必要的命名空间

要编辑表单的代码,右击表单(茶色背景),然后选择view code 。Visual Studio将加载Form1.cs

现在,我们可以在默认的命名空间下面加上注释new

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;                  // new
using System.Runtime.InteropServices;   // new

我们新添加的命名空间。

  • Microsoft.Win32 - 它为我们提供了一个处理操纵系统注册表的事件的类。

  • System.Runtime.InteropServices - 它提供了对COM互操作和平台调用服务的支持。

声明和初始化变量

就在Form1() 构造函数的下面,添加以下代码。

RegistryKey registryKey_1, registryKey_2;
Int32 rbtn_Value1, rbtn_Value2, usb_Ports_Status, read_write_Status;
string registryPath = "System\\CurrentControlSet\\Services\\USBSTOR";
string ReadAndWriteRegistryPath_1 = "System\\CurrentControlSet\\Control\\StorageDevicePolicies";
string ReadAndWriteRegistryPath_2 = "System\\CurrentControlSet\\Control";
bool isUserAdmin;
[DllImport("shell32")]static extern bool IsUserAnAdmin();

上述片段中的字符串包含了通往windows操作系统设备配置的路径(即:windows注册表)。

在加载表单时

在本节中,我们将添加在表单启动后立即执行的代码。

Form1 的设计中,double-clickteal 的背景上。你将被引导到Form1_Load() 方法。

要为表单加载事件添加代码,请双击表单本身,让它为你创建Form_Load() 方法。拷贝粘贴整个方法可能会导致你的应用程序发生故障。

Form_Load() 方法中,添加以下代码。

private void Form1_Load(object sender, EventArgs e)
        {
            isUserAdmin = IsUserAnAdmin();
            if (isUserAdmin == false) // If user is not an admin
            {
                MessageBox.Show("You don't have admin privileges", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); // Show message
            }
            else
            {
                registryKey_1 = Registry.LocalMachine.OpenSubKey(registryPath, true);
                usb_Ports_Status = Convert.ToInt32(registryKey_1.GetValue("Start"));
                //check the current state of the usb ports,whether they are enabled or disabled
                // 3 for enabled & 4 for Disabled
                if (usb_Ports_Status == 3){
                    radioButton1.Checked = true;
                }else if (usb_Ports_Status == 4){
                    radioButton2.Checked = true;
                }registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_1, true);
                
                try{
                    read_write_Status = Convert.ToInt32(registryKey_2.GetValue("WriteProtect"));
                    //check the current state of the removable drive,whether its are write protected or not
                    // 1 for write protected & 0 for not write protected
                    if (read_write_Status == 1)
                    {
                        radioButton3.Checked = true;
                    }
                    else if (read_write_Status == 0)
                    {
                        radioButton4.Checked = true;
                    }
                }
                catch (NullReferenceException) { }
            }

        }

当表单加载时,上述方法检查当前运行程序的用户是否有管理权限。它还会评估USB端口的状态,然后评估插入的可移动驱动器的读写状态。

然后,它根据USB端口和可移动驱动器的状态检查radio buttons 。即:如果USB端口已经启用,它检查enable USB ports 单选按钮选项。

单选按钮

在我们的表格中,单选按钮的顺序是1到4(即:radioButton1radioButton4 )。

前两个单选按钮持有用于改变USB端口状态的值。如果数值是3 ,那么它们就是enabled ,如果是4 ,那么它们就是disabled

最后两个放射性按钮持有用于启用/禁用可移动驱动器的Read/Write 权限的值。如果值是1 ,则启用readonly ,如果是0 ,则禁用readonly

注意:要为每个辐射按钮添加代码,双击辐射按钮,让它为你创建radioButton_CheckedChanged() 方法。复制粘贴整个方法可能会导致错误。

下面是所有单选按钮的代码。

private void radioButton1_CheckedChanged(object sender, EventArgs e){
    groupBox1.Enabled = true;
    rbtn_Value1 = 3;
}

private void radioButton2_CheckedChanged(object sender, EventArgs e){
    groupBox1.Enabled = true;
    rbtn_Value1 = 4;
}

private void radioButton3_CheckedChanged(object sender, EventArgs e){
    rbtn_Value2 = 1;
}

private void radioButton4_CheckedChanged(object sender, EventArgs e){
    rbtn_Value2 = 0;
}

按钮

我们将使用Click() 方法来检查我们表单中的按钮是否被按下。

我们将利用button1 (OK),根据单选按钮设置的值,改变USB端口的状态和可移动驱动器read/write 的权限。

注意:要为每个按钮添加代码,请双击按钮,让它为你创建button_Click() 方法。复制粘贴整个方法可能会导致你的应用程序出现故障。

下面是我们的OK 按钮的代码。

private void button1_Click(object sender, EventArgs e){
            try{
                registryKey_1 = Registry.LocalMachine.OpenSubKey(registryPath, true);
                registryKey_1.SetValue("Start", rbtn_Value1);
                if (groupBox1.Enabled == true)
                {
                    registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_2, true);
                    registryKey_2.CreateSubKey("StorageDevicePolicies");
                    registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_1, true);
                    registryKey_2.SetValue("WriteProtect", rbtn_Value2);
                }
            }
            catch (Exception ex){
               // In case of an error
            }
            if ((rbtn_Value1 == 3) && (rbtn_Value2 == 1)){
                MessageBox.Show("USB Ports and Readonly Enabled");
            }
            else if ((rbtn_Value1 == 3) && (rbtn_Value2 == 0)){
                MessageBox.Show("USB Ports Enabled \n     and \n Readonly Disabled");
            }else{
                MessageBox.Show("USB Port are disabled");
            }
        }

Cancel checked radiobuttons 按钮(button1)用于 ,使用 属性,如下图所示。uncheck Checked

private void button2_Click(object sender, EventArgs e)
    {
        radioButton1.Checked = false;
        radioButton2.Checked = false;
        radioButton3.Checked = false;
        radioButton4.Checked = false;
    }

Close 按钮(button3)用于退出应用程序。

private void button3_Click(object sender, EventArgs e)
        {
            this.Close();
        }

第4步--添加Manifest文件

我们的WinForms应用程序将需要Admin 权限,以便能够对USB端口和可移动驱动器进行修改。

这个功能需要我们添加一个manifest 文件,它将帮助我们的应用程序申请管理权限。

Solution Explorer 侧边栏中,右键单击IOManager ,然后单击Add> New Item> Application Manifest File (Windows Only)> Add ,然后打开生成的app.manifest 文件。

修改<security> 标签内的以下一行。

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

用这个:

<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />

这告诉Windows确保应用程序的用户是一个管理员。

我们的Form1.cs 文件看起来应该如下所示。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Microsoft.Win32;                  // new
using System.Runtime.InteropServices;   // new

namespace IOManager
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        RegistryKey registryKey_1, registryKey_2;
        Int32 rbtn_Value1, rbtn_Value2, usb_Ports_Status, read_write_Status;
        string registryPath = "System\\CurrentControlSet\\Services\\USBSTOR";
        string ReadAndWriteRegistryPath_1 = "System\\CurrentControlSet\\Control\\StorageDevicePolicies";
        string ReadAndWriteRegistryPath_2 = "System\\CurrentControlSet\\Control";
        bool isUserAdmin;
        [DllImport("shell32")]static extern bool IsUserAnAdmin();

        private void Form1_Load(object sender, EventArgs e)
        {
            isUserAdmin = IsUserAnAdmin();
            if (isUserAdmin == false)
            {
                MessageBox.Show("You don't have admini privileges", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                registryKey_1 = Registry.LocalMachine.OpenSubKey(registryPath, true);
                usb_Ports_Status = Convert.ToInt32(registryKey_1.GetValue("Start"));
                //check the current state of the usb ports,whether they are enabled or disabled
                // 3 for enabled & 4 for Disabled
                if (usb_Ports_Status == 3)
                {
                    radioButton1.Checked = true;
                }
                else if (usb_Ports_Status == 4)
                {
                    radioButton2.Checked = true;
                }
                registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_1, true);
                try
                {
                    read_write_Status = Convert.ToInt32(registryKey_2.GetValue("WriteProtect"));
                    //check the current state of the removable drive,whether its are write protected or not
                    // 1 for write protected & 0 for not write protected
                    if (read_write_Status == 1)
                    {
                        radioButton3.Checked = true;
                    }
                    else if (read_write_Status == 0)
                    {
                        radioButton4.Checked = true;
                    }
                }
                catch (NullReferenceException) { }
            }

        }

        
        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            groupBox1.Enabled = true;
            rbtn_Value1 = 3;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            groupBox1.Enabled = true;
            rbtn_Value1 = 4;
        }

        private void radioButton3_CheckedChanged(object sender, EventArgs e)
        {
            rbtn_Value2 = 1;
        }

        private void radioButton4_CheckedChanged(object sender, EventArgs e)
        {
            rbtn_Value2 = 0;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                registryKey_1 = Registry.LocalMachine.OpenSubKey(registryPath, true);
                registryKey_1.SetValue("Start", rbtn_Value1);
                if (groupBox1.Enabled == true)
                {
                    registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_2, true);
                    registryKey_2.CreateSubKey("StorageDevicePolicies");
                    registryKey_2 = Registry.LocalMachine.OpenSubKey(ReadAndWriteRegistryPath_1, true);
                    registryKey_2.SetValue("WriteProtect", rbtn_Value2);
                }
            }
            catch (Exception ex)
            { }
            if ((rbtn_Value1 == 3) && (rbtn_Value2 == 1))
            {
                MessageBox.Show("USB Ports and Readonly Enabled");
            }
            else if ((rbtn_Value1 == 3) && (rbtn_Value2 == 0))
            {
                MessageBox.Show("USB Ports Enabled \n     and \n Readonly Disabled");
            }
            else
            {
                MessageBox.Show("USB Port are disabled");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            radioButton1.Checked = false;
            radioButton2.Checked = false;
            radioButton3.Checked = false;
            radioButton4.Checked = false;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        
    }
}

测试

我们现在可以运行和测试该应用程序。记住在检查完radiobuttons ,并按下OK ,要拔掉然后再重新插入USB设备。

注意,当你在Visual Studio中运行该应用程序时,它需要重新启动以获得管理员权限。因此,请授予该应用程序进行修改的权限。

总结

在本教程中,我们已经学会了如何设计一个Winforms应用程序,与USB端口一起工作,以及可移动驱动器的读写权限。

我们还研究了如何在我们的应用程序中启用管理权限。请随意为应用程序添加更多的功能。