c#错误捕获wmi

时间:2012-09-24 16:05:32

标签: c# c#-4.0 wmi

我有以下代码通过物理磁盘并显示WMI设置。

我注意到如果WMI参数不存在,它不会显示任何内容(这很好),但这会干扰服务器上存在的后续WMI参数,现在它们不显示任何内容......即使它们是应该......以下示例。

所以,我的意思是代码经历了这一部分:

 lblcapability_desc.Text = "Capability Description: " + moDisk["CapabilityDescription"].ToString();
                    lblAvailability.Text = "Availability: " + moDisk["Availability"].ToString();
                    lblbytepersector.Text = "Bytes per Sector: " + moDisk["BytesPerSector"].ToString();
                    lbl_deviceid.Text = "Device ID: " + moDisk["systemname"].ToString();

首先获取SystemName, 然后它获得Type等等。

现在,如果在计算机上的“可用性”的WMI参数不存在,那么它将不会显示。那样就好。但是,在“可用性”之后立即出现“每个扇区的字节数”参数和其他参数。这些参数也没有显示任何内容(尽管我知道它们应该显示一些东西,因为它们确实存在于服务器上 - 通过powershell测试)。

就好像“可用性”中缺少信息会干扰后面的参数而不显示任何内容。

我可以想到解决这个问题的唯一方法(这样即使可用性只显示后续参数显示他们需要的数据)也可能在每个WMI参数中添加一个IF THEN - 不是很好的编码但是可以'想一想解决这个问题的方法。

因此,例如IF [Availbility]然后消息“Avialbility = what”ELSE“WMI参数未找到”。这样每个WMI参数都有自己的错误检查。我想象的不是很好的编码..

如果WMI参数不存在,则已捕获错误,然后向最终用户显示注释。

以下是代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Management;
using Microsoft.Win32;

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

        private void Form1_Load(object sender, EventArgs e)
        {
            //Get all the disk drives
            ManagementObjectSearcher mosDisk = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
            // Loop through each object (disk) retrieved by WMI
            foreach (ManagementObject moDisk in mosDisk.Get())
            {
                cmbHdd.Items.Add(moDisk["Model"].ToString());
            }
        }

        private void cmbHdd_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                ManagementObjectSearcher mosDisks = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive WHERE Model = '" + cmbHdd.SelectedItem + "'");
                foreach (ManagementObject moDisk in mosDisks.Get())
                {

                    lblSystemName.Text = "SystemName: " + moDisk["systemname"];
                    lblType.Text = "Type: " + moDisk["MediaType"].ToString();
                    lblModel.Text = "Model: " + moDisk["Model"].ToString();
                    lblCapacity.Text = "Capacity: " + moDisk["Size"].ToString() + " bytes (" + Math.Round(((((double)Convert.ToDouble(moDisk["Size"]) / 1024) / 1024) / 1024), 2) + " GB)";
                    lblPartitions.Text = "Partitions: " + moDisk["Partitions"].ToString();
                    lblSectors.Text = "Sectors: " + moDisk["SectorsPerTrack"].ToString();
                    lblSignature.Text = "Signature: " + moDisk["Signature"].ToString();
                    lblFirmware.Text = "Firmware: " +moDisk["FirmwareRevision"].ToString();
                    lblFirmware.Text = "Firmware: " + moDisk["FirmwareRevision"] == null ? "Not Available" : moDisk["FirmwareRevision"].ToString();
                    lblcapability_desc.Text = "Capability Description: " + moDisk["CapabilityDescription"].ToString();
                    lblAvailability.Text = "Availability: " + moDisk["Availability"].ToString();
                    lblbytepersector.Text = "Bytes per Sector: " + moDisk["BytesPerSector"].ToString();
                    lbl_deviceid.Text = "Device ID: " + moDisk["systemname"].ToString();
                }
            }
            catch (Exception exp)
            {
                lblError.Text = "Some properties were not shown due to WMI errors or member not available on this system";
            }

        }

        private void btn_clear_Click(object sender, EventArgs e)
        {
            //lblSystemName.Text = string.Empty;
            lblSystemName.Text = "SystemName: " + "";
            lblType.Text = "Type: " + "";
            lblModel.Text = "Model: " + "";
            lblCapacity.Text = "Capacity: " + "";
            lblPartitions.Text = "Partitions: " + "";
            lblSectors.Text = "Sectors: " + "";
            lblSignature.Text = "Signature: " + "";
            lblFirmware.Text = "Firmware: " + "";
            lblError.Text = String.Empty;
            cmbHdd.Items.Clear();
            cmbHdd.Text = "";
            ManagementObjectSearcher mosDisk = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
            foreach (ManagementObject moDisk in mosDisk.Get())
            {
                cmbHdd.Items.Add(moDisk["Model"].ToString());
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您遇到的问题

  

就好像“可用性”中缺少信息会干扰后面的参数而不显示任何内容。

部分情况如此:“可用性”不存在,并抛出NullReferenceException。在分配标签之前检查它是否为空(代码似乎是使用FirmwareRevision执行此操作)。

lblAvailability.Text = "Availability: " + moDisk["Availability"] != null ? moDisk["Availability"].ToString() : string.Empty;

问题的第二部分是你正在包装整个方法体,包括try-catch中的迭代语句。如果try块中发生未处理的异常,则执行切换到catch块。

额外信用:使用泛型和&amp ;;简化WMI报告反射

我已经看到很多实例,其中WMI信息直接从WMI查询对象显示在UI中,您在UI中看到类似这样的内容几次:

lblName.Text = mgmtObjQuery["Name"]

虽然这确实可以提供理想的效果,但有更有效的方法可以避免过早脱发。等到你的PM扩展要求,再包含来自root \ cimv2的20多个类。

我想出了一个解决方案,使用泛型,强类型类和反射来获取WMI信息来完成繁重的工作,现在我的代码看起来更像是这样:

lblName.Text = disk.Name;

首先,为WMI类创建一个模型。类名及其字段名应全部对应于相同的WMI类名和字段。课程&字段应该是公共的,数据类型也应该与C#数据类型匹配。

转到MSDN reference for Win32_DiskDrive,然后生成一个如下所示的类:

/// <summary>
/// A Win32_DiskDrive class based on 
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa394132(v=vs.85).aspx
/// </summary>
public class Win32_DiskDrive 
{
    public UInt16 Availability;
    public UInt32 BytesPerSector;
    public UInt16[] Capabilities ;
    public string[] CapabilityDescriptions ;
    public string Caption;
    public string CompressionMethod;
    public UInt32 ConfigManagerErrorCode;
    public bool ConfigManagerUserConfig;
    public string CreationClassName;
    public UInt64 DefaultBlockSize;
    public string Description;
    public string DeviceID;
    public bool ErrorCleared;
    public string ErrorDescription;
    public string ErrorMethodology;
    public string FirmwareRevision;
    public UInt32 Index;
    public DateTime InstallDate;
    public string InterfaceType;
    public UInt32 LastErrorCode;
    public string Manufacturer;
    public UInt64 MaxBlockSize;
    public UInt64 MaxMediaSize;
    public bool MediaLoaded;
    public string MediaType;
    public UInt64 MinBlockSize;
    public string Model;
    public string Name;
    public bool NeedsCleaning;
    public UInt32 NumberOfMediaSupported;
    public UInt32 Partitions;
    public string PNPDeviceID;
    public UInt16[] PowerManagementCapabilities ;
    public bool PowerManagementSupported;
    public UInt32 SCSIBus;
    public UInt16 SCSILogicalUnit;
    public UInt16 SCSIPort;
    public UInt16 SCSITargetId;
    public UInt32 SectorsPerTrack;
    public string SerialNumber;
    public UInt32 Signature;
    public UInt64 Size;
    public string Status;
    public UInt16 StatusInfo;
    public string SystemCreationClassName;
    public string SystemName;
    public UInt64 TotalCylinders;
    public UInt32 TotalHeads;
    public UInt64 TotalSectors;
    public UInt64 TotalTracks;
    public UInt32 TracksPerCylinder;

    public Win32_DiskDrive()
    {

    }
}

这种通用方法可以解决繁重问题。此方法使用反射将字段名称映射到WMI查询结果。空值检查和日期时间转换都在一个地方处理:

/// <summary>
/// Generic method that uses reflection for wiring up a local class to the corresponding win32_class and properties.
/// </summary>
/// <typeparam name="T">A class who's name and fields correspond to those of a WMI class.</typeparam>
/// <returns>A collection of WMI data.</returns>
public static IEnumerable<T> WmiSnapshot<T>()
{
    // The name of T must match that of the WMI class
    var searcher = new ManagementObjectSearcher(new SelectQuery(Activator.CreateInstance<T>().GetType().Name));

    foreach (ManagementObject managementObject in searcher.Get())
    {
        // Creates an instance of T
        var listItem = Activator.CreateInstance<T>();
        // an array of PUBLIC FIELDS of T
        var fields = listItem.GetType().GetFields();
        // matches a value from the WMI query to a field name
        foreach (FieldInfo field in fields)
        {
            if (managementObject[field.Name] != null)
            {
                field.SetValue(listItem,
                    field.FieldType == typeof(DateTime)
                        ? ManagementDateTimeConverter.ToDateTime(managementObject[field.Name].ToString())
                        : Convert.ChangeType(managementObject[field.Name], field.FieldType));
            }
        }
        yield return listItem;
    }
}

我在自己的类中保留我的WMI类和WMI帮助器方法以从UI调用。 UI代码更易于阅读,也更容易调试。

以下是一个快速示例,它将此快照的结果输出到控制台:

var disks = WmiHelper.WmiSnapshot<Win32_DiskDrive>().ToList(); 

StringBuilder sb = new StringBuilder(); 

foreach (Win32_DiskDrive disk in disks)
{
    sb.AppendFormat("SystemName: {0}\r\n", disk.SystemName);
    sb.AppendFormat("Type: {0}\r\n",  disk.MediaType);
    sb.AppendFormat("Model: {0}\r\n",  disk.Model);
    sb.AppendFormat("Capacity: {0}\r\n", disk.Size );
    sb.AppendFormat("Partitions: {0}\r\n", disk.Partitions);
    sb.AppendFormat("Sectors: {0}\r\n",  disk.SectorsPerTrack);
    sb.AppendFormat("Signature: {0}\r\n", disk.Signature);
    sb.AppendFormat("Firmware: {0}\r\n",  string.IsNullOrEmpty(disk.FirmwareRevision) ? "Not Available" : disk.FirmwareRevision);
    sb.AppendFormat("Capability Description: {0}\r\n", string.Join("\r\n", disk.CapabilityDescriptions));
    sb.AppendFormat("Availability: {0}\r\n", disk.Availability);
    sb.AppendFormat("Bytes per Sector: {0}\r\n", disk.BytesPerSector);
    sb.AppendFormat("Device ID: {0}\r\n", disk.DeviceID);
    sb.AppendLine();
}

Console.WriteLine(sb.ToString());

输出看起来像这样:

SystemName: UVVXWVXXWV
Type: Fixed hard disk media
Model: ST9500420AS
Capacity: 500105249280
Partitions: 4
Sectors: 63
Signature: 2210653369
Firmware: 0006
Capability Description: Random Access
Supports Writing
SMART Notification
Availability: 0
Bytes per Sector: 512
Device ID: \\.\PHYSICALDRIVE0

现在对Win32_ComputerSystem然后Win32_Product重复相同的事情!

如果能让您朝着正确的方向前进,请告诉我。