Search code examples
vb.netusbdetection

how to detect first plug usb flash memory on Vb.net


I'm trying to make a screen locker software, that unlocks only when the correct flash drive plugged in and locks when it's unplugged. So that I have searched and found some codes that detects flash drive. It works properly when there is only one flash drive but if there are more than one flash drive and I unplugged the one without pass, my software still locks the screen. Can anyone help with it?

here is my codes

Imports System.Runtime.InteropServices
Imports System.IO

Public Class Form1

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
    e.Cancel = True
End Sub

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Me.WindowState = FormWindowState.Maximized
    Me.TopMost = True
End Sub


Private Const WM_DEVICECHANGE As Integer = &H219
Private Const DBT_DEVICEARRIVAL As Integer = &H8000
Private Const DBT_DEVTYP_VOLUME As Integer = &H2
Private Const DBT_DEVICEREMOVECOMPLETE As Integer = &H8004


Public Structure DEV_BROADCAST_HDR
    Public dbch_size As Int32
    Public dbch_devicetype As Int32
    Public dbch_reserved As Int32
End Structure

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

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
End Function


Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

    If m.Msg = WM_DEVICECHANGE Then
        If m.WParam.ToInt32 = DBT_DEVICEARRIVAL Then
            If CInt(m.WParam) = DBT_DEVICEARRIVAL Then
                Dim DeviceInfo As DEV_BROADCAST_HDR
                DeviceInfo = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_HDR)), DEV_BROADCAST_HDR)
                If DeviceInfo.dbch_devicetype = DBT_DEVTYP_VOLUME Then
                    Dim Volume As DEV_BROADCAST_VOLUME
                    Volume = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
                    Dim DriveLetter As String = (GetDriveLetterFromMask(Volume.dbcv_unitmask) & ":\")
                    If IO.File.Exists(IO.Path.Combine(DriveLetter, "password.info")) Then


                        Dim fso As Scripting.FileSystemObject
                        Dim oDrive As Scripting.Drive

                        fso = CreateObject("Scripting.FileSystemObject")

                        oDrive = fso.GetDrive(DriveLetter)


                        Dim passline As String() = File.ReadAllLines(DriveLetter & "password.info")

                        If passline(3) = "1120" & oDrive.SerialNumber Then
                            MessageBox.Show("Welcome!")
                            Me.TopMost = False
                            Me.WindowState = FormWindowState.Minimized

                        Else
                            MsgBox("This is not your password.")
                        End If

                    Else

                        MessageBox.Show("Password couldn't be found!")
                    End If
                End If
            End If
        End If
        If m.WParam.ToInt32 = DBT_DEVICEREMOVECOMPLETE Then

            Me.WindowState = FormWindowState.Maximized
            Me.TopMost = True
            MsgBox("Device is removed!")


        End If
    Else

    End If


    MyBase.WndProc(m)
End Sub

End Class

Solution

  • Since you can't get the device ID when the drive is removed, you can not tell which device was removed, all you know is SOMETHING was removed.

    At that point you really need to scan and see if the expected drive is still connected.

    You need to store the DriveLetter of the right USB Drive in the class when it is detected, then check it still exists when a drive is removed..

    Something like

        Dim Key_Is_Gone = True
        For Each drv As DriveInfo In My.Computer.FileSystem.Drives
            If drv.Name = DriveLetter Then
                Key_Is_Gone = False
                Exit For 
            End If
        Next
    
        If Key_Is_Gone Then
             'Do what you have to do
        End If
    

    Though if the drive letter does exist, you may want to check some other property of the drive to verify it is really the same key. Otherwise, some bright spark may reassign the drive letters on you.

    Perhaps

    drv.RootDirectory.CreationTime
    

    Read and store that on detecting the Key, and use that stored value to test.

        Dim Key_Is_Gone = True
        For Each drv As DriveInfo In My.Computer.FileSystem.Drives
            If drv.Name = DriveLetter andalso drv.RootDirectory.CreationTime = DetectedKeyDate Then
                Key_Is_Gone = False
                Exit For 
            End If
        Next
    
        If Key_Is_Gone Then
             'Do what you have to do
        End If
    

    ALSO: Don't use FSO, use the native VB.NET

    My.Computer.FileSystem
    

    objects instead.