提问人:Giovanni De Miccoli 提问时间:7/9/2022 更新时间:7/12/2022 访问量:157
Visual Studio Vb.net |USB检测代码部分工作
Visual studio Vb.net | Usb detection code partially working
问:
我不得不重写帖子,因为 stackoverflow 检测到该帖子已经在另一个线程中解决,我不得不删除它。但是引用论坛的线程是针对 C# 的,无论如何,即使阅读它,我也无法找到解决我的问题的方法。
所以,大家好,:D
我确实在网上的某个地方找到了一个代码,可以让我检测 USB 设备和相关文件, 它有效但不是很好,因为每次我插入或拔出 USB 设备时,我都会得到:
“System.NullReferenceException”,我不会写其余的错误以避免stackoverflow关闭线程,无论如何你应该已经理解我的问题。
代码如下:
Imports System.IO
Public Class Form1
#Region "USB EVENT"
Private WM_DEVICECHANGE As Integer = &H219
Public Enum WM_DEVICECHANGE_WPPARAMS As Integer
DBT_CONFIGCHANGECANCELED = &H19
DBT_CONFIGCHANGED = &H18
DBT_CUSTOMEVENT = &H8006
DBT_DEVICEARRIVAL = &H8000
DBT_DEVICEQUERYREMOVE = &H8001
DBT_DEVICEQUERYREMOVEFAILED = &H8002
DBT_DEVICEREMOVECOMPLETE = &H8004
DBT_DEVICEREMOVEPENDING = &H8003
DBT_DEVICETYPESPECIFIC = &H8005
DBT_DEVNODES_CHANGED = &H7
DBT_QUERYCHANGECONFIG = &H17
DBT_USERDEFINED = &HFFFF
End Enum
Private Structure DEV_BROADCAST_VOLUME
Public dbcv_size As Int32
Public dbcv_devicetype As Int32
Public dbcv_reserved As Int32
Public dbcv_unitmask As Int32
Public dbcv_flags As Int16
End Structure
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Try
If m.Msg = WM_DEVICECHANGE Then
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
If Not GetDriveLetterFromMask(Volume.dbcv_unitmask).ToString.Trim = String.Empty Then
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
Select Case m.WParam
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEARRIVAL
LblUSB.Text = DriveLetter
GetFiles()
MsgBox("Usb connected")
' Code When add USB
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEREMOVECOMPLETE
LblUSB.Text = ""
CheckedListBox1.Items.Clear()
MsgBox("Usb disconnected")
' Code When Remove USB
End Select
End If
End If
Catch ex As Exception
End Try
MyBase.WndProc(m)
End Sub
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return ""
End Function
#End Region
Sub GetFiles()
Try
Dim Path = LblUSB.Text
Dim LstFiles = My.Computer.FileSystem.GetFiles(Path, FileIO.SearchOption.SearchTopLevelOnly)
For Each File In LstFiles
Dim F As New IO.FileInfo(File)
CheckedListBox1.Items.Add(F.Name)
Next
Catch ex As Exception
End Try
End Sub
End Class
我得到的System.NullReferenceException是在这一点上:
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
我确实读到过,当值为 null 并且应该有一个关联的值时,会发生此错误, 我尝试了不同的方法,但没有一个奏效,我希望你们中的某个人能给我一个解决方案和解释,以更好地理解这一点。
非常感谢你们的帮助!
答:
当在 VS 2019 中运行代码时,在它下面指出:System.Runtime.InteropServices.Marshal.PtrToStructure(...) 返回 Nothing ,因为 是 .通过将以下代码放在 DirectCast 语句之前,可以观察到这一点:.System.NullReferenceException
m.LParam
0
Debug.WriteLine($"m.LParam: '{m.LParam.ToString()}'")
在检测到已插入 USB 设备之前,无需尝试获取驱动器号。如果重构代码,如下所示,则不会发生此问题:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_DEVICECHANGE Then
Debug.WriteLine($"m.LParam: '{m.LParam.ToString()}'")
Select Case CInt(m.WParam)
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEARRIVAL
Debug.WriteLine($" DBT_DEVICEARRIVAL")
Dim Volume As DEV_BROADCAST_VOLUME
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
If Not GetDriveLetterFromMask(Volume.dbcv_unitmask).ToString.Trim = String.Empty Then
Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
LblUSB.Text = DriveLetter
GetFiles()
MsgBox("Usb connected")
' Code When add USB
End If
Case WM_DEVICECHANGE_WPPARAMS.DBT_DEVICEREMOVECOMPLETE
LblUSB.Text = ""
CheckedListBox1.Items.Clear()
MsgBox("Usb disconnected")
' Code When Remove USB
End Select
End If
MyBase.WndProc(m)
End Sub
旁注:建议为您的项目启用 Option Strict。
更新:
启用 Option Strict 后,由于以下语句,会收到以下编译器错误:in function: 。要解决此问题,请尝试以下操作之一:BC30512: Option Strict On disallows implicit conversions from 'String' to 'Char'
GetDriveLetterFromMask
Return ""
选项 1:
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As String
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return ""
End Function
选项 2:
Private Function GetDriveLetterFromMask(ByRef Unit As Int32) As Char
For i As Integer = 0 To 25
If Unit = (2 ^ i) Then
Return Chr(Asc("A") + i)
End If
Next
Return Chr(0)
End Function
资源:
评论