Fork me on GitHub

调用devcon.exe控制usb设备

     3天前跟硕哥聊天时,他给我发了个有意思的程序--控制usb设备的拔插。当时我正好看到cookbook的IO处理,就觉得肯定是手到擒来(bs下自己)。第二天才开始动手,随手按照cookbook上的写了个:

1
2
3
4
5
6
7
8
9
10
11
private void InitUsbDrives()
 {
   DriveInfo[] allDrives = DriveInfo.GetDrives();
    foreach (DriveInfo d in allDrives)
    {
                if (d.DriveType == DriveType.Removable)
                {
                    listUsbDrives.Items.Add(d.Name);
                }
     }
}

结果什么也没有显示。这就奇怪了,这是为什么呢?原来GetDrives()方法只是获取逻辑盘符。我当时电脑上没有插入u盘,当然就没有显示咯。而硕哥发给我的程序显示的是所有usb接口的。那我就去搜,首先是msdn上关于io命名空间的查看,但是没有什么收获。只好求助google,什么遍历usb接口,监听usb接口,侦听usb端口,查看所有usb端口,跟usb相关的都找了。网上最多的是一个usb接口类的编写,但是没有实质的内容。当然,还是搜索到一定成果。比如有个也很多的监听方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public const int WM_DEVICECHANGE = 0x219;
        public const int DBT_DEVICEARRIVAL = 0x8000;
        public const int DBT_CONFIGCHANGECANCELED = 0x0019;
        public const int DBT_CONFIGCHANGED = 0x0018;
        public const int DBT_CUSTOMEVENT = 0x8006;
        public const int DBT_DEVICEQUERYREMOVE = 0x8001;
        public const int DBT_DEVICEQUERYREMOVEFAILED = 0x8002;
        public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
        public const int DBT_DEVICEREMOVEPENDING = 0x8003;
        public const int DBT_DEVICETYPESPECIFIC = 0x8005;
        public const int DBT_DEVNODES_CHANGED = 0x0007;
        public const int DBT_QUERYCHANGECONFIG = 0x0017;
        public const int DBT_USERDEFINED = 0xFFFF;
 
protected override void WndProc(ref Message m)
        {
            try
            {
                if (m.Msg == WM_DEVICECHANGE)
                {
                    switch (m.WParam.ToInt32())
                    {
                        case WM_DEVICECHANGE:
                            break;
                        case DBT_DEVICEARRIVAL://U盘有插入
                            this.timer1.Enabled = true;
                            DriveInfo[] s = DriveInfo.GetDrives();
                            foreach (DriveInfo DriveI in s)
                            {
                                if (DriveI.DriveType == DriveType.Removable)
                                {
                                   // Ls.Show();
                                   // this.Hide();
                                   // MessageBox.Show("sss");
                                    
                                    break;
                                }
                                int devType = Marshal.ReadInt32(m.LParam, 4);
                                if (devType == DBT_DEVTYP_VOLUME)
                                {
                                    DEV_BROADCAST_VOLUME vol;
                                    vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
                                    ID=vol.dbcv_unitmask.ToString("x");
                                    this.Text = IO(ID);
                                   this.Tag = IO(ID);
                                   //if (item.Length ==0||IO(ID)!=this.Tag.ToString ())
                                   //{
                                       
                                   //}
                                }
                                this.label1.Text = this.Text;
                            }
                            break;
                        case DBT_CONFIGCHANGECANCELED:
                            break;
                        case DBT_CONFIGCHANGED:
                            break;
                        case DBT_CUSTOMEVENT:
                            break;
                        case DBT_DEVICEQUERYREMOVE:
                            break;
                        case DBT_DEVICEQUERYREMOVEFAILED:
                            break;
                        case DBT_DEVICEREMOVECOMPLETE: //U盘卸载
                            DriveInfo[] I = DriveInfo.GetDrives();
                            foreach (DriveInfo DrInfo in I)
                            {
                                int devType = Marshal.ReadInt32(m.LParam, 4);
                                if (devType == DBT_DEVTYP_VOLUME)
                                {
                                    DEV_BROADCAST_VOLUME vol;
                                    vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
                                    ID = vol.dbcv_unitmask.ToString("x");
                                    this.Text = IO(ID) + "盘退出!\n";
                                    
                                    
                                }
                                this.label1.Text += this.Text;
                               // MessageBox.Show("U盘已经卸载", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            break;
                        case DBT_DEVICEREMOVEPENDING:
                            break;
                        case DBT_DEVICETYPESPECIFIC:
                            break;
                        case DBT_DEVNODES_CHANGED:
                            break;
                        case DBT_QUERYCHANGECONFIG:
                            break;
                        case DBT_USERDEFINED:
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            base.WndProc(ref m);
        }

这个代码有几个版本,但大致都是差不多的,就是重写WndProc(ref Message m),判断传入的消息是否为u盘插入信息,然后显示u盘此时的盘符。有个比较好的版本,还可以启用
和禁用usb端口。但是这不是我需要的效果。继续找寻,在csdn某个问题贴中又找到一点有用的信息:

1
2
3
4
5
string[] comPorts = System.IO.Ports.SerialPort.GetPortNames();
foreach(string s in comPorts)
{
   listUsbDrives.Items.Add(s);
}

 

 

显示出了com1和com2两个结果,自我感觉离真相不远了。SerialPort是串口的意识,那是不是有UsbPort呢?马上兴奋地查看msdn,结果失望了。
不存在!而且唯一有的就是SerialPort。但是提供了我一个思路,usb是计算机的物理端口,那么我查看计算机信息不就有么?有这个类来帮助我查看吗?
是有的,System.Management。但是自己不太会用,就有google了一下。大致用法如此:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private ManagementClass mc;
private ManagementObjectCollection moc;
private void InitUsbDrives()
{
            mc = new ManagementClass("Win32_USBController");
            moc = mc.GetInstances();
            String USBInfo = string.Empty;
            foreach (ManagementObject mo in moc)
            {
                foreach (PropertyData pd in mo.Properties)
                {
 
                    if (pd.Name.Equals("DeviceID"))
                    {
                        USBInfo = pd.Value + "\n";
                    }
                    if (pd.Name.Equals("Manufacturer"))
                    {
                        USBInfo = USBInfo + " 厂商:" + pd.Value + "\n";
                    }
                    else if (pd.Name.Equals("Name"))
                    {
                        USBInfo = USBInfo + " USB控制器名称:" + pd.Value + "\n";
                    }
                    else if (pd.Name.Equals("Status"))
                    {
                        USBInfo = USBInfo + " USB状态态:" + pd.Value + "\n";
                    }
                    else if (pd.Name.Equals("PNPDeviceID"))
                    {
                        USBInfo = USBInfo + " USB控制器ID:" + pd.Value;
                    }
 
                }
                listUsbDrives.Items.Add(USBInfo);
            }
}

 

但是这样并不能按我想要的方式显示,然后感觉肯定和Win32_USBController有关系,所以继续上msdn。查看了改函数:
http://msdn.microsoft.com/en-us/library/aa394504(VS.85).aspx
只有英文的,所以边看边翻译。将可能是的参数试了个遍,这下终于八九不离十了。就打算动手写,这时,这时~我注意到硕哥发我的rar中
有个devcon.exe。这东西是什么呢?于是借助Reflector查看了下硕哥发我的程序。发现真是调用这个东东,继续google下,发现这个工具很好用。
devcon帮助文档:http://hapeacock.blog.51cto.com/193534/86899
devcon设备启用和禁用:http://www.clxp.net.cn/article.asp?id=443
C#cookbook的IO中正好有关于命令行交互的,于是乎,很晚了,就去睡了。躺在床上就在想,该怎么写呢? 第二天起来后就继续工作:

1
首先是cmd的调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static string RunProcessCmd(string command)
        {
            Process application = new Process();
            application.StartInfo.FileName = @"cmd.exe";
            application.StartInfo.Arguments = "/c" + command;
            application.StartInfo.RedirectStandardInput = true;
            application.StartInfo.RedirectStandardOutput = true;
            application.StartInfo.UseShellExecute = false;
            application.StartInfo.CreateNoWindow = true;
            application.Start();
            application.StandardInput.WriteLine("exit");
            string str = application.StandardOutput.ReadToEnd();
            application.Close();
            return str;
        }

接下来是运行devcon:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void InitUsbDrives()
       {
           string[] drives = Regex.Split(RunProcessCmd("devcon.exe status usb*"), "\\.\r\n");
           listUsbDrives.Items.Clear();
           int index = 1;
           foreach (string s in drives)
           {
               string[] strDives = Regex.Split(s, "   ");
               if (strDives.Length == 3)
               {
                   Drives _drives = new Drives()
                                        {
                                            ID = strDives[0],
                                            Name = index + ": " + strDives[1].Substring(6),
                                            Status = strDives[2]
                                        };
                   listUsbDrives.Items.Add(_drives);
               }
                
           }

费了些周折,总算是完成了。上个图:

posted @   idoku  阅读(2015)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示