调用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); } } |
费了些周折,总算是完成了。上个图:
作 者:doku
出 处:http://www.cnblogs.com/kulong995/
关于作者:喜欢编程,喜欢美食,专注于.NET项目开发。
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?