二、技术要点
WMI最初是内置在 Windows 2000、Windows XP 和 Windows Server 2003 系列操作系统中核心的管理支持技术,目前WMI 已经是一种规范和基础结构,通过它可以访问、配置、管理和监视几乎所有的 Windows 资源例如磁盘、事件日志、文件、文件夹、文件系统、网络组件、操作系统设置、性能数据、打印机、进程、注册表设置、安全性、服务、共享、用户、组等等。在 WMI 之前,能够以编程方式访问 Windows 资源的惟一方法就是通过 Win32 API,现在我们除了使用WMI 脚本管理任何通过 WMI 公开的 Windows 资源外,还可以通过.Net框架对于WMI封装的System.Management 命名空间来轻松实现。
我们首先使用WMI查询来获取特定类名的SelectQuery实例,可以有两种方法创建该实例,一是可以传递一个已知的类名,譬如本文需要传递的类名为:Win32_LogicalDisk,代码如下:
SelectQuery selectQuery = new SelectQuery("win32_logicaldisk");
或者使用wql查询来创建查询类的实例,代码如下:
SelectQuery selectQuery = new SelectQuery("select * from win32_logicaldisk");
或者只获取类的部分属性,代码如下:
SelectQuery selectQuery = new SelectQuery("select Name,DriveType from win32_logicaldisk");
WQL查询语言是 SQL 的一个子集,查询通过包含以下内容限制返回的数据量1、SELECT 子句,指定只返回某些属性的数据;2、WHERE 子句,指定要返回的实例。Win32_LogicalDisk类在默认的本地MSDN里是无法找到的,只有在联机的MSDN里,Win32 and COM Development下的WMI下才能找到,同样可以使用的类还有很多很多,包含登录用户信息的Win32_Account类、包含本地和共享打印机信息的Win32_PrinterShare类等等。Win32_LogicalDisk里所包含的驱动器属性相当丰富,如下图:
然后使用该指定的SelectQuery查询创建ManagementObjectSearcher实例,此类是用于检索管理信息的较为常用的入口点之一,实例创建结束,我们需要调用Get方法执行查询以便检索管理对象的集合,当调用该方法时,ManagementObjectSearcher 在指定的范围内执行给定的查询,并返回与 ManagementObjectCollection 中的查询匹配的管理对象的集合,这是就可以在一个循环中遍历集合中的所有对象,并获取我们所感兴趣的对象的属性,代码如下:
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)SelectQuery selectQuery = new SelectQuery("select * from win32_logicaldisk");ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery); int i=0;foreach (ManagementObject disk in searcher.Get()) { //获取驱动器盘符 listView1.Items.Add(disk["Name"].ToString());}
三、 程序实现
我们使用Visual Studio 2005来创建该示例程序,首先创建C#的Windows应用程序空白项目,为解决方案和项目取名为 GetLogicDrives,在默认的Form1窗体上我们各放置一个ListView和一个Button控件,保留控件的默认名称不变,将ListView1的View属性设为Details,双击ListView1的Columns属性,为详细信息视图添加5个列,分别为:盘符、卷标、类型、容量和可用空间,设置Button1的Text属性为Refresh,为该Button1添加单击事件,代码如下:
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)private void button1_Click(object sender, EventArgs e){ listView1.Items.Clear(); SelectQuery selectQuery = new SelectQuery("select * from win32_logicaldisk"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery); int i=0; foreach (ManagementObject disk in searcher.Get()) { //盘符 listView1.Items.Add(disk["Name"].ToString()); //卷标 try { listView1.Items[i].SubItems.Add(disk["VolumeName"].ToString()); } catch { listView1.Items[i].SubItems.Add("设备未准备好"); } //驱动器类型 string DriveType; try { DriveType = disk["DriveType"].ToString(); switch (DriveType) { case "0": listView1.Items[i].SubItems.Add("未知设备"); break; case "1": listView1.Items[i].SubItems.Add("未分区"); break; case "2": listView1.Items[i].SubItems.Add("可移动磁盘"); break; case "3": listView1.Items[i].SubItems.Add("硬盘"); break; case "4": listView1.Items[i].SubItems.Add("网络驱动器"); break; case "5": listView1.Items[i].SubItems.Add("光驱"); break; case "6": listView1.Items[i].SubItems.Add("内存磁盘"); break; } } catch { listView1.Items[i].SubItems.Add("未知类型"); } //容量 try { listView1.Items[i].SubItems.Add(GetSizeUseUnit(disk["Size"].ToString())); } catch { listView1.Items[i].SubItems.Add("设备未准备好"); } //剩余空间 try { listView1.Items[i].SubItems.Add(GetSizeUseUnit(disk["FreeSpace"].ToString())); } catch { listView1.Items[i].SubItems.Add("设备未准备好"); } i++;}}
我们使用了格式化显示磁盘空间容量的自定义函数GetSizeUseUnit,当不使用该函数时磁盘容量和可用空间的显示如下:
private string GetSizeUseUnit(string size){ double dSpace = Convert.ToDouble(size); string sSpace = dSpace.ToString("N"); string[] tmp; string rtnSize = "0"; tmp = sSpace.Split(','); switch (tmp.GetUpperBound(0)) { case 0: rtnSize = tmp[0] + " 字节"; break; case 1: rtnSize = tmp[0] + "." + tmp[1].Substring(0,2) + " K"; break; case 2: rtnSize = tmp[0] + "." + tmp[1].Substring(0, 2) + " M"; break; case 3: rtnSize = tmp[0] + "." + tmp[1].Substring(0, 2) + " G"; break; case 4: rtnSize = tmp[0] + "." + tmp[1].Substring(0, 2) + " T"; break; } return rtnSize;}
使用了上述自定义格式化显示的函数后,磁盘容量和可用空间的显示就显得非常简洁和直观。
最后,为了确保在窗体启动时自动获取驱动器信息,需要在窗体的Load事件中模拟对Button1的单击操作,代码如下:
private void Form1_Load(object sender, EventArgs e){ button1_Click(sender, e);}
四、 总结
我们利用.Net框架System.Management 命名空间所提供的WMI封装非常简单的实现了获取逻辑驱动器的详细信息,除了上述信息我们还可以轻松的获取Windows资源大部分信息,比起使用Win32API要更加简单和有效。该示例程序在Windows XP SP2 + Visual Studio 2005 下编译和调试通过。