用C#和WMI获取逻辑驱动器详细信息(转)
用C#和WMI获取逻辑驱动器详细信息
在编写某些Windows管理应用程序时,能够从自定义的驱动器选择列表框中进行选择无疑是非常专业的,使用Delphi或者C++的早期版本时我们都必须使用Win32所提供的许多关于获取磁盘信息的API函数来分别获取像卷标、序列号以及剩余空间等信息,现在我们将使用.Net框架和WMI(Windows Management Instrumentation - Windows 管理规范 )来实现上述功能。
一、 简介
若仅简单获取逻辑驱动器的名称列表我们使用.Net框架的Environment.GetLogicalDrives即可,但是若想获得更多关于磁盘驱动器的信息我们可以使用.Net框架下的System.Management 命名空间所提供的类和委托等对大量管理信息和管理事件的集合进行访问,这些信息和事件都与 WMI有关,该命名空间下的类实际上也是对WMI的一种封装,应用程序和服务可以使用从 ManagementObjectSearcher 和 ManagementQuery 派生的类,查询感兴趣的管理信息,例如在磁盘上还剩多少可用空间、当前 CPU 利用率是多少、某一应用程序正连接到哪一数据库等等,现在我们就以 C# 语言编写获取详细的逻辑驱动器信息的示例来展示.Net框架System.Management 命名空间的相关类和WMI编程,如下图:
二、技术要点
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 中的查询匹配的管理对象的集合,这是就可以在一个循环中遍历集合中的所有对象,并获取我们所感兴趣的对象的属性,代码如下:
…… SelectQuery selectQuery = new SelectQuery("select * from win32_logicaldisk"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery); int i=0; |
三、 程序实现
我们使用Visual Studio 2005来创建该示例程序,首先创建C#的Windows应用程序空白项目,为解决方案和项目取名为 GetLogicDrives,在默认的Form1窗体上我们各放置一个ListView和一个Button控件,保留控件的默认名称不变,将ListView1的View属性设为Details,双击ListView1的Columns属性,为详细信息视图添加5个列,分别为:盘符、卷标、类型、容量和可用空间,设置Button1的Text属性为Refresh,为该Button1添加单击事件,代码如下:
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; } } |
我们使用了格式化显示磁盘空间容量的自定义函数GetSizeUseUnit,当不使用该函数时磁盘容量和可用空间的显示如下:
private string GetSizeUseUnit(string size) { double dSpace = Convert.ToDouble(size); string sSpace = dSpace.ToString("N"); string[] tmp; string rtnSize = "0"; tmp = sSpace.Split(','); |
使用了上述自定义格式化显示的函数后,磁盘容量和可用空间的显示就显得非常简洁和直观。
最后,为了确保在窗体启动时自动获取驱动器信息,需要在窗体的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 下编译和调试通过