我不得不重写这篇文章,因为stackoverflow检测到这篇文章已经在另一个线程中解决了,我不得不将其删除。但引用论坛的线程是针对C#的,无论如何,即使阅读它,我也找不到解决问题的方法。
大家好,伙计们:D
我确实在网上找到了一个代码,可以检测usb设备和相关文件,它可以工作,但不是很好,因为每次我插入或拔下usb设备时,我都会得到:
"系统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
系统。我得到的NullReferenceException是在这一点上:
Volume = DirectCast(Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
我确实读到,当值为null并且应该有一个相关联的值时,就会发生这个错误,我尝试了不同的方法,但都没有奏效,我希望你们中的某个人能给我一个解决方案和解释,让我更好地理解这一点。
非常感谢你们的帮助!
当在VS 2019中运行代码时,它在System.NullReferenceException
下面表示:系统。运行时。InteropServices。元帅PtrToStructure(…)返回Nothing,这是因为m.LParam
是0
。这可以通过将以下代码放在DirectCast语句之前来观察: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后,由于语句Return ""
,函数GetDriveLetterFromMask
中会出现以下编译器错误:BC30512: Option Strict On disallows implicit conversions from 'String' to 'Char'
。要解决此问题,请尝试以下操作之一:
选项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
资源:
- 元帅。PtrToStructure方法
- DirectCast运算符(Visual Basic)
- C类型函数(Visual Basic)