Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0055: Hinzufügen und Entfernen von USB-Wechselmedien erkennen

 von 

Beschreibung

Mit dieser Klasse ist es möglich festzustellen, ob bzw. wann ein USB-Wechselmedium (USB-Stick oder USB-Festplatte) hinzugekommen ist oder entfernt wurde.

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Framework-Version(en):

.NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [12,55 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2005
' Option Strict:    An
'
' Referenzen: 
'  - System
'  - System.Data
'  - System.Deployment
'  - System.Drawing
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - System
'  - System.Collections
'  - System.Collections.Generic
'  - System.Data
'  - System.Drawing
'  - System.Diagnostics
'  - System.Windows.Forms
'

' ##############################################################################
' ########################### DriveChangeWatcher.vb ############################
' ##############################################################################
' Mit dieser Klasse ist es möglich festzustellen, ob ein Laufwerk hinzugekommen 
' ist oder entfernt wurde. An dieser Stelle möchte ich mich für die tatkräftige 
' Unterstützung von Frank Schüler bedanken, von ihm wurde ich auf den 
' folgenden Link aufmerksam gemacht:
'   http://msdn2.microsoft.com/en-us/library/aa363239(VS.85).aspx
' Diesen möchte ich dem interessiertem Leser wärmstens empfehlen. Ebenso vielen 
' Dank an Eckard Ahlers für das Korrekturlesen und die kleinen Tipps am Rande.

Public Class DriveChangeWatcher
    Inherits System.Windows.Forms.NativeWindow

    ' Das sind die Ereignisse aus WParam.
    ' Uns interessiert nur, ob ein Laufwerk hinzugekommen ist oder 
    '  entfernt wurde.
    Public Event DriveArrived(ByVal sender As Object, _
        ByVal e As System.IO.DriveInfo)
    Public Event DriveRemoved(ByVal sender As Object, _
        ByVal e As System.IO.DriveInfo)

    ' Die Struktur für OEM.
    ' Wird über LParam gefüllt.
    ' USB-Sticks laufen alle hier auf.
    Private Structure DEV_BROADCAST_OEM
        Dim dbco_size As Integer
        Dim dbco_devicetype As Integer
        Dim dbco_reserved As Integer
        Dim dbco_identifier As Integer
        Dim dbco_suppfunc As Integer
    End Structure

    ' Die Struktur für Volumes.
    ' Wird über LParam gefüllt.
    Private Structure DEV_BROADCAST_VOLUME
        Dim dbch_size As Integer
        Dim dbch_devicetype As Integer
        Dim dbch_reserved As Integer
        Dim dbcv_unitmask As Integer
        Dim dbcv_flags As Short
    End Structure

    ' Die Struktur für den Header.
    ' Wird über LParam gefüllt.
    Private Structure DEV_BROADCAST_HDR
        Dim dbch_size As Integer
        Dim dbch_devicetype As Integer
        Dim dbch_reserved As Integer
    End Structure

    ' Das sind die Konstanten der Gerätetypen
    ' Vorsicht die Gerätetypen Variablen in den Strukturen sind vom Typ Integer.
    ' IntelliSense kann das nicht auflösen.
    Private Enum DeviceType
        OEM = 0
        DEVNODE = 1
        VOLUME = 2
        PORT = 3
        NET = 4
        DEVICEINTERFACE = 5
        HANDLE = 6
    End Enum

    ' Dies sind die Konstanten für die verschiedenen Geräte - Habe ich zur der 
    ' besseren Verwendbarkeit in eine Enum gepackt.(siehe oben)
    ' // type of device in DEV_BROADCAST_HDR
    ' // OEM- or IHV-defined:
    '   Public Const DBT_DEVTYP_OEM As Integer = &H0&                 
    ' Devnode number.
    '   Public Const DBT_DEVTYP_DEVNODE As Integer = &H1&               
    ' // Logical volume
    '   Public Const DBT_DEVTYP_VOLUME As Integer = &H2&                
    ' // Port (serial or parallel)
    '   Public Const DBT_DEVTYP_PORT As Integer = &H3&                  
    ' // Network resource
    '   Public Const DBT_DEVTYP_NET As Integer = &H4&                   
    ' // Device interface class
    '   Public Const DBT_DEVTYP_DEVICEINTERFACE As Integer = &H5&       
    ' // File system handle
    '   Public Const DBT_DEVTYP_HANDLE As Integer = &H6&                

    ' Windowmessage DeviceChange
    Private Const WM_DEVICECHANGE As Integer = &H219

    'Die beiden Ereignisse, die für uns von Bedeutung sind.
    Private Const DBT_DEVICEARRIVAL As Integer = &H8000
    Private Const DBT_DEVICEREMOVECOMPLETE As Integer = &H8004

    ' Dies ist der Dreh- und Angelpunkt der Klasse. - Hier bekommen wir die 
    '  Messages mit.
    ' In unserm Fall interessiert uns nur die WM_DeviceChange-Nachricht
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_DEVICECHANGE Then
            Me.HandleHeader(m)
        End If
        MyBase.WndProc(m)
    End Sub

    ' Hier schauen wir erst mal in den Header und verzweigen dementsprechend
    Private Sub HandleHeader(ByRef m As Message)
        Dim header As DEV_BROADCAST_HDR
        Dim objHeader As Object = m.GetLParam(header.GetType)
        If Not IsNothing(objHeader) Then
            'Dient nur zur Kennzeichnung, was nicht implementiert ist
            Dim notSupported As Boolean

            Select Case header.dbch_devicetype
                Case DeviceType.OEM
                    Me.HandleOEM(m)

                Case DeviceType.DEVNODE
                    notSupported = True

                Case DeviceType.VOLUME
                    Me.HandleVolume(m)

                Case DeviceType.PORT
                    notSupported = True

                Case DeviceType.NET
                    notSupported = True

                Case DeviceType.DEVICEINTERFACE
                    notSupported = True

                Case DeviceType.HANDLE
                    notSupported = True
            End Select
        End If
    End Sub

    ' Das Ereignis betrifft ein Volume
    Private Sub HandleVolume(ByRef m As Message)
        Dim volume As DEV_BROADCAST_VOLUME
        Dim objVolume As Object = m.GetLParam(volume.GetType)

        If Not IsNothing(objVolume) Then
            volume = DirectCast(objVolume, DEV_BROADCAST_VOLUME)
            Dim di As New IO.DriveInfo(Me.DriveFromMask(volume.dbcv_unitmask))

            ' USB-Stick
            If di.DriveType = IO.DriveType.Removable Then
                If CInt(m.WParam) = DBT_DEVICEARRIVAL Then
                    RaiseEvent DriveArrived(Me, di)
                End If
            End If

            ' USB-Festplatte
            If di.DriveType = IO.DriveType.Fixed Then
                If CInt(m.WParam) = DBT_DEVICEARRIVAL Then
                    RaiseEvent DriveArrived(Me, di)
                End If
            End If

            If CInt(m.WParam) = DBT_DEVICEREMOVECOMPLETE Then
                RaiseEvent DriveRemoved(Me, di)
            End If
        End If
    End Sub

    ' OEM, und was genau?
    ' Uns interesieren nur Volumes
    Private Sub HandleOEM(ByRef m As Message)
        Dim oem As DEV_BROADCAST_OEM
        Dim objOem As Object = m.GetLParam(oem.GetType)

        If Not IsNothing(objOem) Then
            oem = DirectCast(objOem, DEV_BROADCAST_OEM)
            If oem.dbco_devicetype = DeviceType.VOLUME Then
                Me.HandleVolume(m)
            End If
        End If
    End Sub

    ' Liefert uns den Laufwerksbuchstaben zurück
    Private Function DriveFromMask(ByVal unitmask As Integer) As Char
        For b As Integer = 0 To 25
            If (unitmask And CInt(2 ^ b)) <> 0 Then
                Return Chr(65 + b)
            End If
        Next b
    End Function

    '#################################################################
    ' Wir haben zwei Möglichkeiten der Instanzierung
    '#################################################################
    ' Erste Möglichkeit:
    ' Wir benötigen das Form in der die Klasse instanziert wird.
    ' Und müssen den Handle der Form auf unser NativeWindow setzen.
    Public Sub New(ByVal form As System.Windows.Forms.Form)
        Me.AssignHandle(form.Handle)
    End Sub
    Private Sub New()
    End Sub

    ' Das Handle wieder freigeben.
    Protected Overrides Sub Finalize()
        Me.ReleaseHandle()
        MyBase.Finalize()
    End Sub

    ''##################################################################
    '' Zweite Möglichkeit:(Auskommentiert)
    '' Wir machen uns unser eigenes Handle.
    '' In diesen Fall benötigen wir das Form nicht!
    'Public Sub New()
    '    Me.CreateHandle(New CreateParams)
    'End Sub

    '' Das selbst erstellte Handle zerstören.
    'Protected Overrides Sub Finalize()
    '    Me.DestroyHandle()
    '    MyBase.Finalize()
    'End Sub
End Class

' ##############################################################################
' ################################# Form1.vb ###################################
' ##############################################################################
Public Class Form1
    Private WithEvents myDriveWatcher As New DriveChangeWatcher(Me)

    Private Sub myDriveWatcher_DriveCoutChanged(ByVal sender As Object, _
        ByVal e As System.IO.DriveInfo) Handles myDriveWatcher.DriveArrived

        MsgBox("Arrived -> " & e.Name & " - " & e.DriveType.ToString)
    End Sub

    Private Sub myDriveWatcher_DriveRemoved(ByVal sender As Object, _
        ByVal e As System.IO.DriveInfo) Handles myDriveWatcher.DriveRemoved

        MsgBox("Removed -> " & e.Name & " - " & e.DriveType.ToString)
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 1 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von MAR am 24.06.2010 um 20:52

WOW, hat mir sehr, sehr, sehr geholfen bei meinem Projekt! Vielen Dank!!!

PS: Hab die Volumes noch um einen CD/DVD-Eintrag erweitert!