如何在 VB.NET 中检测到 USB 设备时使 WinForm 控件 Visible = True
How do I make a WinForm control Visible = True upon detection of USB device in VB.NET
使用 VB.net 中的现有代码。工作正常,直到我在代码中添加额外的功能来完成其他任务。例如,下面的代码在检测到插入的 USB 拇指驱动器时尝试使按钮可见时在立即 window 中抛出异常。我猜这是因为按钮还没有完全创建?无论如何,寻找如何解决这个问题的方向。我想要做的就是让按钮在插入 USB 驱动器时可见,而在拔出 USB 驱动器时不可见。提前致谢!
代码:
Imports System.Management ' Also had to add System.Management as a reference
Imports System
Imports System.ComponentModel
Public Class Form1
Private WithEvents m_MediaConnectWatcher As ManagementEventWatcher
Public USBDriveName As String
Public USBDriveLetter As String
Public Sub StartDetection()
' __InstanceOperationEvent will trap both Creation and Deletion of class instances
Dim query2 As New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 " _
& "WHERE TargetInstance ISA 'Win32_DiskDrive'")
m_MediaConnectWatcher = New ManagementEventWatcher With {
.Query = query2
}
m_MediaConnectWatcher.Start()
End Sub
Private Sub Arrived(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs) Handles m_MediaConnectWatcher.EventArrived
Dim mbo, obj As ManagementBaseObject
' the first thing we have to do is figure out if this is a creation or deletion event
mbo = CType(e.NewEvent, ManagementBaseObject)
' next we need a copy of the instance that was either created or deleted
obj = CType(mbo("TargetInstance"), ManagementBaseObject)
Select Case mbo.ClassPath.ClassName
Case "__InstanceCreationEvent"
If obj("InterfaceType") = "USB" Then
MsgBox("Technician maintenance key has been plugged in")
Button1.Visible = True
Else
MsgBox(obj("InterfaceType"))
End If
Case "__InstanceDeletionEvent"
If obj("InterfaceType") = "USB" Then
MsgBox("Technician maintenance key has been unplugged.")
Button1.Visible = False
If obj("Caption") = USBDriveName Then
USBDriveLetter = ""
USBDriveName = ""
End If
Else
MsgBox(obj("InterfaceType"))
End If
Case Else
MsgBox("nope: " & obj("Caption"))
End Select
End Sub
Private Function GetDriveLetterFromDisk(ByVal Name As String) As String
Dim oq_part, oq_disk As ObjectQuery
Dim mos_part, mos_disk As ManagementObjectSearcher
Dim obj_part, obj_disk As ManagementObject
Dim ans As String = ""
' WMI queries use the "\" as an escape charcter
Name = Replace(Name, "\", "\")
' First we map the Win32_DiskDrive instance with the association called
' Win32_DiskDriveToDiskPartition. Then we map the Win23_DiskPartion
' instance with the assocation called Win32_LogicalDiskToPartition
oq_part = New ObjectQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & Name & """} WHERE AssocClass = Win32_DiskDriveToDiskPartition")
mos_part = New ManagementObjectSearcher(oq_part)
For Each obj_part In mos_part.Get()
oq_disk = New ObjectQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & obj_part("DeviceID") & """} WHERE AssocClass = Win32_LogicalDiskToPartition")
mos_disk = New ManagementObjectSearcher(oq_disk)
For Each obj_disk In mos_disk.Get()
ans &= obj_disk("Name") & ","
Next
Next
Return ans.Trim(","c)
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
StartDetection()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
m_MediaConnectWatcher.Stop()
Application.Exit()
End Sub
Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
m_MediaConnectWatcher.Stop()
Application.Exit()
End Sub
End Class
当创建控件(在您的情况下为 Button1)的线程以外的线程尝试调用该控件时(Button1.Visible = True 或 Button1.Visible = False),调试器引发 InvalidOperationException 消息,Control control name accessed from a thread 而不是创建它的线程。 这可能就是您看到的消息。从不同线程访问控件的一种方法是使用 Invoke():
Private Sub ShowButton()
'InvokeRequired compares the thread ID of the
'calling thread to the thread ID of the creating thread.
'If these threads are different, it returns true.
'If the calling thread is different from the thread that
'created the Button1 control, this method calls itself asynchronously using the
'Invoke method
If Me.InvokeRequired Then
Me.Invoke(Sub() ShowButton())
Return
End If
Button1.Visible = True
End Sub
Private Sub HideButton()
If Me.InvokeRequired Then
Me.Invoke(Sub() HideButton())
Return
End If
Button1.Visible = False
End Sub
并在您的代码中替换
Button1.Visible = True
和
ShowButton()
和
Button1.Visible = False
和
HideButton()
使用 VB.net 中的现有代码。工作正常,直到我在代码中添加额外的功能来完成其他任务。例如,下面的代码在检测到插入的 USB 拇指驱动器时尝试使按钮可见时在立即 window 中抛出异常。我猜这是因为按钮还没有完全创建?无论如何,寻找如何解决这个问题的方向。我想要做的就是让按钮在插入 USB 驱动器时可见,而在拔出 USB 驱动器时不可见。提前致谢!
代码:
Imports System.Management ' Also had to add System.Management as a reference
Imports System
Imports System.ComponentModel
Public Class Form1
Private WithEvents m_MediaConnectWatcher As ManagementEventWatcher
Public USBDriveName As String
Public USBDriveLetter As String
Public Sub StartDetection()
' __InstanceOperationEvent will trap both Creation and Deletion of class instances
Dim query2 As New WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 1 " _
& "WHERE TargetInstance ISA 'Win32_DiskDrive'")
m_MediaConnectWatcher = New ManagementEventWatcher With {
.Query = query2
}
m_MediaConnectWatcher.Start()
End Sub
Private Sub Arrived(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs) Handles m_MediaConnectWatcher.EventArrived
Dim mbo, obj As ManagementBaseObject
' the first thing we have to do is figure out if this is a creation or deletion event
mbo = CType(e.NewEvent, ManagementBaseObject)
' next we need a copy of the instance that was either created or deleted
obj = CType(mbo("TargetInstance"), ManagementBaseObject)
Select Case mbo.ClassPath.ClassName
Case "__InstanceCreationEvent"
If obj("InterfaceType") = "USB" Then
MsgBox("Technician maintenance key has been plugged in")
Button1.Visible = True
Else
MsgBox(obj("InterfaceType"))
End If
Case "__InstanceDeletionEvent"
If obj("InterfaceType") = "USB" Then
MsgBox("Technician maintenance key has been unplugged.")
Button1.Visible = False
If obj("Caption") = USBDriveName Then
USBDriveLetter = ""
USBDriveName = ""
End If
Else
MsgBox(obj("InterfaceType"))
End If
Case Else
MsgBox("nope: " & obj("Caption"))
End Select
End Sub
Private Function GetDriveLetterFromDisk(ByVal Name As String) As String
Dim oq_part, oq_disk As ObjectQuery
Dim mos_part, mos_disk As ManagementObjectSearcher
Dim obj_part, obj_disk As ManagementObject
Dim ans As String = ""
' WMI queries use the "\" as an escape charcter
Name = Replace(Name, "\", "\")
' First we map the Win32_DiskDrive instance with the association called
' Win32_DiskDriveToDiskPartition. Then we map the Win23_DiskPartion
' instance with the assocation called Win32_LogicalDiskToPartition
oq_part = New ObjectQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & Name & """} WHERE AssocClass = Win32_DiskDriveToDiskPartition")
mos_part = New ManagementObjectSearcher(oq_part)
For Each obj_part In mos_part.Get()
oq_disk = New ObjectQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & obj_part("DeviceID") & """} WHERE AssocClass = Win32_LogicalDiskToPartition")
mos_disk = New ManagementObjectSearcher(oq_disk)
For Each obj_disk In mos_disk.Get()
ans &= obj_disk("Name") & ","
Next
Next
Return ans.Trim(","c)
End Function
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
StartDetection()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
m_MediaConnectWatcher.Stop()
Application.Exit()
End Sub
Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
m_MediaConnectWatcher.Stop()
Application.Exit()
End Sub
End Class
当创建控件(在您的情况下为 Button1)的线程以外的线程尝试调用该控件时(Button1.Visible = True 或 Button1.Visible = False),调试器引发 InvalidOperationException 消息,Control control name accessed from a thread 而不是创建它的线程。 这可能就是您看到的消息。从不同线程访问控件的一种方法是使用 Invoke():
Private Sub ShowButton()
'InvokeRequired compares the thread ID of the
'calling thread to the thread ID of the creating thread.
'If these threads are different, it returns true.
'If the calling thread is different from the thread that
'created the Button1 control, this method calls itself asynchronously using the
'Invoke method
If Me.InvokeRequired Then
Me.Invoke(Sub() ShowButton())
Return
End If
Button1.Visible = True
End Sub
Private Sub HideButton()
If Me.InvokeRequired Then
Me.Invoke(Sub() HideButton())
Return
End If
Button1.Visible = False
End Sub
并在您的代码中替换
Button1.Visible = True
和
ShowButton()
和
Button1.Visible = False
和
HideButton()