我有以下代码通过物理磁盘并显示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());
}
}
}
}
答案 0 :(得分:2)
就好像“可用性”中缺少信息会干扰后面的参数而不显示任何内容。
部分情况如此:“可用性”不存在,并抛出NullReferenceException。在分配标签之前检查它是否为空(代码似乎是使用FirmwareRevision执行此操作)。
lblAvailability.Text = "Availability: " + moDisk["Availability"] != null ? moDisk["Availability"].ToString() : string.Empty;
问题的第二部分是你正在包装整个方法体,包括try-catch中的迭代语句。如果try
块中发生未处理的异常,则执行切换到catch
块。
我已经看到很多实例,其中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重复相同的事情!
如果能让您朝着正确的方向前进,请告诉我。