升级到 Windows 10 后 WMI 不工作
WMI not working after upgrading to Windows 10
我一直在 Windows 8 上 Visual Studio 的控制台应用程序中使用下面的代码来 return 连接的串行设备的描述和设备 ID。我在我正在创建的应用程序中使用了这个的修改版本来自动检测 Arduino 的 COM 端口。自从我用 Windows 10 完成了全新安装后,它不再是 return 任何东西。我有一个 USB 到串行 AVR 编程器,但它仍然显示使用此代码。我检查了注册表,Arduino 列在 SERIALCOMM 中,Arduino 在设备管理器的 'Ports (COM & LPT)' 下显示为 'USB Serial Port (COM6)',我可以使用 Arduino 软件对 Arduino 进行编程。我不知道为什么它不再工作了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.IO.Ports;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
ManagementScope connectionScope = new ManagementScope();
SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);
try
{
foreach (ManagementObject item in searcher.Get())
{
string desc = item["Description"].ToString();
string deviceId = item["DeviceID"].ToString();
Console.WriteLine(desc);
Console.WriteLine(deviceId);
}
}
catch (ManagementException e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
}
}
可能还相关的是,在尝试寻找解决方案时,我发现以下实现使用 MSSerial_PortName 查找端口名称,但出现拒绝访问错误。
using System;
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
try
{
ManagementObjectSearcher MOSearcher = new ManagementObjectSearcher("root\WMI", "SELECT * FROM MSSerial_PortName");
foreach (ManagementObject MOject in MOSearcher.Get())
{
Console.WriteLine(MOject["PortName"]);
}
}
catch (ManagementException me)
{
Console.WriteLine("An error occurred while querying for WMI data: " + me.Message);
}
Console.ReadKey();
}
}
}
您的 Windows 8 用户配置文件可能包含完整的管理员权限,而您的 Windows 10 用户配置文件是标准用户。因为你的Windows10用户配置文件是标准用户,你必须调整一些访问权限。
运行 Computer Management
实用程序。
转到Computer Management > Services and Applications > WMI Control
。
转到Actions > WMI Control > More Actions > Properties
打开WMI Control Properties
window。
在 Security
选项卡下,select Root
,然后按 Security
。
在Security for Root
对话框中,select您的用户名或您所属的组。 Select Allow for Permissions > Execute Methods
。单击 OK
关闭对话框。
对 CIMV2
重复上一步。
使用这些新权限再次尝试 运行。
好的,我想我现在看到了问题(我会添加一个新答案,但不会替换旧答案,以防有人发现信息有用)。
Win32_SerialPort
只检测硬件串口(如RS232)。
Win32_PnPEntity
标识即插即用设备,包括硬件和虚拟串行端口(例如 FTDI 驱动程序创建的 COM 端口)。
要使用 Win32_PnPEntity
识别驱动程序需要一些额外的工作。以下代码标识系统上的所有 COM 端口并生成所述端口的列表。从此列表中,您可以确定适当的 COM 端口号以创建您的 SerialPort 对象。
// Class to contain the port info.
public class PortInfo
{
public string Name;
public string Description;
}
// Method to prepare the WMI query connection options.
public static ConnectionOptions PrepareOptions ( )
{
ConnectionOptions options = new ConnectionOptions ( );
options . Impersonation = ImpersonationLevel . Impersonate;
options . Authentication = AuthenticationLevel . Default;
options . EnablePrivileges = true;
return options;
}
// Method to prepare WMI query management scope.
public static ManagementScope PrepareScope ( string machineName , ConnectionOptions options , string path )
{
ManagementScope scope = new ManagementScope ( );
scope . Path = new ManagementPath ( @"\" + machineName + path );
scope . Options = options;
scope . Connect ( );
return scope;
}
// Method to retrieve the list of all COM ports.
public static List<PortInfo> FindComPorts ( )
{
List<PortInfo> portList = new List<PortInfo> ( );
ConnectionOptions options = PrepareOptions ( );
ManagementScope scope = PrepareScope ( Environment . MachineName , options , @"\root\CIMV2" );
// Prepare the query and searcher objects.
ObjectQuery objectQuery = new ObjectQuery ( "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0" );
ManagementObjectSearcher portSearcher = new ManagementObjectSearcher ( scope , objectQuery );
using ( portSearcher )
{
string caption = null;
// Invoke the searcher and search through each management object for a COM port.
foreach ( ManagementObject currentObject in portSearcher . Get ( ) )
{
if ( currentObject != null )
{
object currentObjectCaption = currentObject [ "Caption" ];
if ( currentObjectCaption != null )
{
caption = currentObjectCaption . ToString ( );
if ( caption . Contains ( "(COM" ) )
{
PortInfo portInfo = new PortInfo ( );
portInfo . Name = caption . Substring ( caption . LastIndexOf ( "(COM" ) ) . Replace ( "(" , string . Empty ) . Replace ( ")" , string . Empty );
portInfo . Description = caption;
portList . Add ( portInfo );
}
}
}
}
}
return portList;
}
比 Juderb 小一点的解决方案
public static List<string> FindComPorts()
{
using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0"))
{
return searcher.Get().OfType<ManagementBaseObject>()
.Select(port => Regex.Match(port["Caption"].ToString(), @"\((COM\d*)\)"))
.Where(match => match.Groups.Count >= 2)
.Select(match => match.Groups[1].Value).ToList();
}
}
在 win7 + win10 上测试过。顺便说一句,您可以根据需要向正则表达式添加额外的搜索条件(或者只添加一个新的 Where 子句)
我一直在 Windows 8 上 Visual Studio 的控制台应用程序中使用下面的代码来 return 连接的串行设备的描述和设备 ID。我在我正在创建的应用程序中使用了这个的修改版本来自动检测 Arduino 的 COM 端口。自从我用 Windows 10 完成了全新安装后,它不再是 return 任何东西。我有一个 USB 到串行 AVR 编程器,但它仍然显示使用此代码。我检查了注册表,Arduino 列在 SERIALCOMM 中,Arduino 在设备管理器的 'Ports (COM & LPT)' 下显示为 'USB Serial Port (COM6)',我可以使用 Arduino 软件对 Arduino 进行编程。我不知道为什么它不再工作了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.IO.Ports;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
ManagementScope connectionScope = new ManagementScope();
SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);
try
{
foreach (ManagementObject item in searcher.Get())
{
string desc = item["Description"].ToString();
string deviceId = item["DeviceID"].ToString();
Console.WriteLine(desc);
Console.WriteLine(deviceId);
}
}
catch (ManagementException e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
}
}
可能还相关的是,在尝试寻找解决方案时,我发现以下实现使用 MSSerial_PortName 查找端口名称,但出现拒绝访问错误。
using System;
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
try
{
ManagementObjectSearcher MOSearcher = new ManagementObjectSearcher("root\WMI", "SELECT * FROM MSSerial_PortName");
foreach (ManagementObject MOject in MOSearcher.Get())
{
Console.WriteLine(MOject["PortName"]);
}
}
catch (ManagementException me)
{
Console.WriteLine("An error occurred while querying for WMI data: " + me.Message);
}
Console.ReadKey();
}
}
}
您的 Windows 8 用户配置文件可能包含完整的管理员权限,而您的 Windows 10 用户配置文件是标准用户。因为你的Windows10用户配置文件是标准用户,你必须调整一些访问权限。
运行
Computer Management
实用程序。转到
Computer Management > Services and Applications > WMI Control
。转到
Actions > WMI Control > More Actions > Properties
打开WMI Control Properties
window。在
Security
选项卡下,selectRoot
,然后按Security
。在
Security for Root
对话框中,select您的用户名或您所属的组。 SelectAllow for Permissions > Execute Methods
。单击OK
关闭对话框。对
CIMV2
重复上一步。使用这些新权限再次尝试 运行。
好的,我想我现在看到了问题(我会添加一个新答案,但不会替换旧答案,以防有人发现信息有用)。
Win32_SerialPort
只检测硬件串口(如RS232)。
Win32_PnPEntity
标识即插即用设备,包括硬件和虚拟串行端口(例如 FTDI 驱动程序创建的 COM 端口)。
要使用 Win32_PnPEntity
识别驱动程序需要一些额外的工作。以下代码标识系统上的所有 COM 端口并生成所述端口的列表。从此列表中,您可以确定适当的 COM 端口号以创建您的 SerialPort 对象。
// Class to contain the port info.
public class PortInfo
{
public string Name;
public string Description;
}
// Method to prepare the WMI query connection options.
public static ConnectionOptions PrepareOptions ( )
{
ConnectionOptions options = new ConnectionOptions ( );
options . Impersonation = ImpersonationLevel . Impersonate;
options . Authentication = AuthenticationLevel . Default;
options . EnablePrivileges = true;
return options;
}
// Method to prepare WMI query management scope.
public static ManagementScope PrepareScope ( string machineName , ConnectionOptions options , string path )
{
ManagementScope scope = new ManagementScope ( );
scope . Path = new ManagementPath ( @"\" + machineName + path );
scope . Options = options;
scope . Connect ( );
return scope;
}
// Method to retrieve the list of all COM ports.
public static List<PortInfo> FindComPorts ( )
{
List<PortInfo> portList = new List<PortInfo> ( );
ConnectionOptions options = PrepareOptions ( );
ManagementScope scope = PrepareScope ( Environment . MachineName , options , @"\root\CIMV2" );
// Prepare the query and searcher objects.
ObjectQuery objectQuery = new ObjectQuery ( "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0" );
ManagementObjectSearcher portSearcher = new ManagementObjectSearcher ( scope , objectQuery );
using ( portSearcher )
{
string caption = null;
// Invoke the searcher and search through each management object for a COM port.
foreach ( ManagementObject currentObject in portSearcher . Get ( ) )
{
if ( currentObject != null )
{
object currentObjectCaption = currentObject [ "Caption" ];
if ( currentObjectCaption != null )
{
caption = currentObjectCaption . ToString ( );
if ( caption . Contains ( "(COM" ) )
{
PortInfo portInfo = new PortInfo ( );
portInfo . Name = caption . Substring ( caption . LastIndexOf ( "(COM" ) ) . Replace ( "(" , string . Empty ) . Replace ( ")" , string . Empty );
portInfo . Description = caption;
portList . Add ( portInfo );
}
}
}
}
}
return portList;
}
比 Juderb 小一点的解决方案
public static List<string> FindComPorts()
{
using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0"))
{
return searcher.Get().OfType<ManagementBaseObject>()
.Select(port => Regex.Match(port["Caption"].ToString(), @"\((COM\d*)\)"))
.Where(match => match.Groups.Count >= 2)
.Select(match => match.Groups[1].Value).ToList();
}
}
在 win7 + win10 上测试过。顺便说一句,您可以根据需要向正则表达式添加额外的搜索条件(或者只添加一个新的 Where 子句)