VB.NET中获取设备管理器last arrival date属性(Win32_PnPEntity无此属性)
获取设备管理器中"Last Arrival Date"属性的VB.NET方案
你说得对,Win32_PnPEntity确实没有暴露"Last Arrival Date"这个属性——这个值要么存在设备的注册表项里,要么得通过Windows的SetupAPI来读取。针对你需要判断NI PXI Express Chassis预热时长的需求,我整理了两种可行的实现方法:
方法一:直接读取设备注册表(快速上手)
设备的"Last Arrival Date"以REG_BINARY格式存储在注册表的HKLM\SYSTEM\CurrentControlSet\Enum\<PNPDeviceID>\<实例ID>路径下,键名就是LastArrivalDate。咱们可以先用你现有的WMI代码拿到设备的PNPDeviceID,再读取这个二进制值并转换成DateTime:
Imports Microsoft.Win32 Imports System.Management Module Module1 Sub Main() Dim scope As New ManagementScope("root\CIMV2") Dim query As New ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE Name LIKE 'NI PXI Express Chassis Control Device'") Dim searcher As New ManagementObjectSearcher(scope, query) Dim queryCollection As ManagementObjectCollection = searcher.Get() For Each m As ManagementObject In queryCollection Dim pnpDeviceId As String = m("PNPDeviceID").ToString() Console.WriteLine("Device Name: {0}", m("Name")) Console.WriteLine("PNPDeviceID: {0}", pnpDeviceId) ' 构造设备注册表路径 Dim regPath As String = $"SYSTEM\CurrentControlSet\Enum\{pnpDeviceId}" Using key As RegistryKey = Registry.LocalMachine.OpenSubKey(regPath) If key IsNot Nothing Then ' 遍历设备的实例子项(通常只有一个) For Each subKeyName As String In key.GetSubKeyNames() Using subKey As RegistryKey = key.OpenSubKey(subKeyName) If subKey IsNot Nothing Then Dim lastArrivalBytes As Byte() = subKey.GetValue("LastArrivalDate") If lastArrivalBytes IsNot Nothing AndAlso lastArrivalBytes.Length = 8 Then ' 把Windows FILETIME格式的二进制转换成DateTime Dim fileTime As Long = BitConverter.ToInt64(lastArrivalBytes, 0) Dim lastArrivalDate As DateTime = DateTime.FromFileTime(fileTime) Console.WriteLine("Last Arrival Date: {0:G}", lastArrivalDate) ' 计算机箱开机时长 Dim uptime As TimeSpan = DateTime.Now - lastArrivalDate Console.WriteLine("Chassis Uptime: {0} hours {1} minutes", uptime.Hours, uptime.Minutes) ' 判断是否满足30分钟预热要求 If uptime.TotalMinutes >= 30 Then Console.WriteLine("✅ Preheating completed, ready for measurement!") Else Console.WriteLine("⚠️ Preheating not done yet, remaining time: {0:N1} minutes", 30 - uptime.TotalMinutes) End If End If End If Next End If End If End Using Next Console.ReadLine() End Sub End Module
方法二:使用SetupAPI(更稳定可靠)
如果遇到注册表权限问题,或者想要更通用的设备属性读取方式,Windows的SetupAPI是更好的选择——它是专门为设备管理设计的原生API,能直接获取SPDRP_LAST_ARRIVAL_DATE属性。不过需要用P/Invoke调用这些原生函数,代码会稍微复杂一点,但兼容性和稳定性更强:
Imports System.Management Imports System.Runtime.InteropServices Module Module1 ' SetupAPI相关的P/Invoke声明 Private Const DIGCF_PRESENT As Integer = &H2 Private Const SPDRP_LAST_ARRIVAL_DATE As Integer = &H1B <DllImport("setupapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Function SetupDiGetClassDevs(ByRef ClassGuid As Guid, ByVal Enumerator As String, ByVal hwndParent As IntPtr, ByVal Flags As Integer) As IntPtr End Function <DllImport("setupapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Function SetupDiEnumDeviceInfo(ByVal DeviceInfoSet As IntPtr, ByVal MemberIndex As Integer, ByRef DeviceInfoData As SP_DEVINFO_DATA) As Boolean End Function <DllImport("setupapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)> Private Function SetupDiGetDeviceRegistryProperty(ByVal DeviceInfoSet As IntPtr, ByRef DeviceInfoData As SP_DEVINFO_DATA, ByVal Property As Integer, ByRef PropertyRegDataType As Integer, ByVal PropertyBuffer As Byte(), ByVal PropertyBufferSize As Integer, ByRef RequiredSize As Integer) As Boolean End Function <DllImport("setupapi.dll", SetLastError:=True)> Private Function SetupDiDestroyDeviceInfoList(ByVal DeviceInfoSet As IntPtr) As Boolean End Function <StructLayout(LayoutKind.Sequential)> Private Structure SP_DEVINFO_DATA Public cbSize As Integer Public ClassGuid As Guid Public DevInst As Integer Public Reserved As IntPtr End Structure Sub Main() Dim scope As New ManagementScope("root\CIMV2") Dim query As New ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE Name LIKE 'NI PXI Express Chassis Control Device'") Dim searcher As New ManagementObjectSearcher(scope, query) Dim queryCollection As ManagementObjectCollection = searcher.Get() For Each m As ManagementObject In queryCollection Dim classGuid As Guid = New Guid(m("ClassGuid").ToString()) ' 获取当前存在的设备信息集合 Dim deviceInfoSet As IntPtr = SetupDiGetClassDevs(classGuid, Nothing, IntPtr.Zero, DIGCF_PRESENT) If deviceInfoSet = IntPtr.Zero Then Console.WriteLine("Failed to retrieve device info set.") Continue For End If Try Dim deviceInfoData As New SP_DEVINFO_DATA() deviceInfoData.cbSize = Marshal.SizeOf(deviceInfoData) Dim index As Integer = 0 ' 枚举设备集合中的设备 While SetupDiEnumDeviceInfo(deviceInfoSet, index, deviceInfoData) ' 读取Last Arrival Date属性 Dim bufferSize As Integer = 8 Dim buffer As Byte() = New Byte(bufferSize - 1) {} Dim regDataType As Integer = 0 Dim requiredSize As Integer = 0 If SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_LAST_ARRIVAL_DATE, regDataType, buffer, bufferSize, requiredSize) Then Dim fileTime As Long = BitConverter.ToInt64(buffer, 0) Dim lastArrivalDate As DateTime = DateTime.FromFileTime(fileTime) Console.WriteLine("Last Arrival Date: {0:G}", lastArrivalDate) ' 计算开机时长 Dim uptime As TimeSpan = DateTime.Now - lastArrivalDate Console.WriteLine("Chassis Uptime: {0}h {1}m", uptime.Hours, uptime.Minutes) ' 预热状态判断 If uptime.TotalMinutes >= 30 Then Console.WriteLine("✅ Ready to start measurements!") Else Console.WriteLine("⚠️ Still preheating, need {0:N1} more minutes.", 30 - uptime.TotalMinutes) End If End If index += 1 End While Finally ' 释放设备信息集合资源 SetupDiDestroyDeviceInfoList(deviceInfoSet) End Try Next Console.ReadLine() End Sub End Module
额外提示
- 运行这些代码需要管理员权限,因为读取设备注册表和调用SetupAPI都需要较高的系统权限。
- 考虑到你用的是NI设备,也可以试试NI官方的.NET API(比如NI System Configuration API或NI-DAQmx),这些API可能直接提供设备的上电时间或预热状态,比通用方法更贴合NI设备的特性。
内容的提问来源于stack exchange,提问作者Duryon
相关产品推荐
相关产品推荐

