Usb-Anschlüsse überwachen

    • VB.NET

      Usb-Anschlüsse überwachen

      Hier gehts um wie man WindowMessages auswerten kann, um Änderungen an Usb-Anschlüssen wahrzunehmen.
      Eine Windowmessage ist eine Struktur mit vier Elementen:
      1. msg (Integer): der MessageCode
        Im Windows-Betriebsystem sind ca. 200 verschiedene Messages hinterlegt, als namentlich bekannte Integer-Konstanten, die Benennung beginnt per Konvention mit WM_
      2. hwnd (IntPtr): Handle des Ziel-Fensters
      3. wparam (IntPtr): eine Zusatz-Information
      4. lparam (IntPtr): noch eine Zusatz-Information
      5. result (IntPtr): ein Message-Member, über den man dem Betriebssystem Informationen und Daten auch zurückgeben kann.
      wparam, lparam kann alles mögliche bedeuten, Boolean, Integer, Handles, oder es können auch Pointer auf unmanaged Strukturen sein, die weitreichendere Informationen bereithalten.

      Wie dem auch sei, zunächstmal muss man nur wissen, dass Windows die WM_DEVICECHANGE-Message verschickt, wenn man was an einen Usb-Buchse anschließt oder rauszieht.
      Windows hält so ein Ereignis für so wichtig, dass es die Message ungefragt an jede Fensterhandle verschickt, die herumfährt.
      Das ist bequem, denn für viele andere WMs muss man erst noch eine unmanaged Register-Funktion aufrufen, und ein FensterHandle angeben, an das Windows die Message senden soll (gugge zB Globaler Hotkey )

      Wie empfängt man nu eine WM?
      Das kann jedes Control, sogar jede Komponente, und auch die kleine Klasse NativeWindow kanns. Es muss halt die WndProc() - Sub vorhanden und überschreibbar sein.
      Hier überschreibe ich mal einfach die WndProc meines MainForms, filtere die msg auf WM_DEVICECHANGE, und logge die Treffer ins Outputfenster:

      VB.NET-Quellcode

      1. Public Class Form2
      2. Private Const WM_DEVICECHANGE As Integer = &H219
      3. Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
      4. MyBase.WndProc(msg)
      5. If msg.Msg <> WM_DEVICECHANGE Then Return
      6. Debug.WriteLine(msg.ToString)
      7. End Sub
      Mehr erstmal nicht - das ist der wichtigste Einstieg in den Umgang mit WMs: Erstmal filtern und dann loggen, was kommt. Filtert man nicht, so wird man schier erschlagen von einer unglaublichen Menge an Messages, die auflaufen.
      Beachte auch, dass als erste Amts-Handlung MyBase.WndProc() aufgerufen wird, meine Überschreibung will die Message ja nicht abfangen, sondern nur mithören - deshalb reicht sie die Message schön weiter (und deshalb wird auch nicht am result-Member rumgefummelt.)

      Hier mal der Log, der entsteht, als ich einen Usb-Stick reingesteckt habe:

      OutputWindow schrieb:

      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x8000 lparam=0x582e460 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      msg=0x219 (WM_DEVICECHANGE) hwnd=0x830b9a wparam=0x7 lparam=0x0 result=0x1
      Beachte, dass msg.ToString() die msg sogar selbst übersetzt, zu (WM_DEVICECHANGE). Dies zeigt, dass diese Konstanten im Betriebssystem wirklich festverdrahtet vorliegen.
      Ja, leider wird WM_DEVICECHANGE offsichtlich viel zu oft gesendet.
      Aber trotzdem liegt bereits hiermit schon ein Mechanismus vor, der aufs Anschließen an Usb-Anschlüsse reagiert.

      msg und hwnd sind natürlich immer dieselben - mein Filter lässt ja keine andere msg passieren, und hwnd ist ja die FensterHandle meines Forms.
      Aber in zeile#5 des Logs - da treten abweichend besondere wparam und lparam auf.

      Wie gesagt - je nach WM können diese Params alles mögliche bedeuten, hier bedeutet der wparam eine der beiden Konstanten

      VB.NET-Quellcode

      1. Private Shared DBT_DEVICEARRIVAL As New IntPtr(&H8000)
      2. Private Shared DBT_DEVICEREMOVECOMPLETE As New IntPtr(&H8004)
      (Nomen est Omen) zu deutsch: Device angekommen bzw entfernt.

      Und lparam bedeutet hier noch viel mehr, das ist in diesem Fall nämlich ein Pointer auf eine unmanaged Structure. Deren .Net-Pendant sieht so aus:

      VB.NET-Quellcode

      1. ' Struct for parameters of the WM_DEVICECHANGE message
      2. <StructLayout(LayoutKind.Sequential)> _
      3. Public Structure DEV_BROADCAST_VOLUME
      4. Public dbcv_size As Integer
      5. Public dbcv_devicetype As Integer
      6. Public dbcv_reserved As Integer
      7. Public dbcv_unitmask As Integer
      Also 4 Integer.
      Wir kümmern uns nur um dbcv_unitmask, denn das kann man als Bitmuster dekodieren, um den Laufwerksbuchstaben zu erhalten:

      VB.NET-Quellcode

      1. Public Function GetDriveChar() As Char
      2. 'die Position des in dbcv_unitmask gesetzten Bits entspricht dem Laufwerks-Buchstaben
      3. For i = 0 To 31
      4. If (1 << i And dbcv_unitmask) <> 0 Then Return Convert.ToChar(65 + i)
      5. Next
      6. Return "?"c
      7. End Function
      (Ich hoffe, die Bit-Operationen << und And sind bekannt, ansonsten fragen, wie Zeile#4 funktioniert.)

      Also hier nochmal die ganze Geschichte, ein Logger, der WM_DEVICECHANGE-Messages loggt, und bei UsbSticks auch den Laufwerksbuchstaben herausfindet:

      VB.NET-Quellcode

      1. Imports System.Runtime.InteropServices
      2. Public Class Form2
      3. Private Const WM_DEVICECHANGE As Integer = &H219
      4. Private Shared DBT_DEVICEARRIVAL As New IntPtr(&H8000)
      5. Private Shared DBT_DEVICEREMOVECOMPLETE As New IntPtr(&H8004)
      6. Private _Counter As Integer = 0
      7. Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
      8. MyBase.WndProc(msg)
      9. If msg.Msg <> WM_DEVICECHANGE Then Return
      10. Dim remark = ""
      11. Select Case msg.WParam
      12. Case DBT_DEVICEARRIVAL
      13. remark = "add drive: " & DEV_BROADCAST_VOLUME.FromPointer(msg.LParam).GetDriveChar
      14. Case DBT_DEVICEREMOVECOMPLETE
      15. remark = "remove drive: " & DEV_BROADCAST_VOLUME.FromPointer(msg.LParam).GetDriveChar
      16. End Select
      17. Debug.WriteLine(msg.ToString)
      18. WriteLog(msg.ToString, remark)
      19. End Sub
      20. ''' <summary> fügt msg und remark als numerierte neue Zeile einer Richtextbox an (die maximal 30 Zeilen anzeigt) </summary>
      21. Private Sub WriteLog(msg As String, remark As String)
      22. 'zb: msg=0x219 (WM_DEVICECHANGE) hwnd=0x950d8e wparam=0x7 lparam=0x0 result=0x1
      23. If remark <> "" Then remark = String.Concat(" remark=""", remark, """")
      24. Dim newLine = String.Concat(_Counter.ToString("000"), ": ", msg.ToString, remark)
      25. Dim lines = RichTextBox1.Lines.Concat({newLine})
      26. RichTextBox1.Lines = lines.Skip(lines.Count - 30).ToArray
      27. _Counter += 1
      28. End Sub
      29. End Class
      30. ' Struct for parameters of the WM_DEVICECHANGE message
      31. <StructLayout(LayoutKind.Sequential)> _
      32. Public Structure DEV_BROADCAST_VOLUME
      33. Public dbcv_size As Integer
      34. Public dbcv_devicetype As Integer
      35. Public dbcv_reserved As Integer
      36. Public dbcv_unitmask As Integer
      37. Public Function GetDriveChar() As Char
      38. 'die Position des in dbcv_unitmask gesetzten Bits entspricht dem Laufwerks-Buchstaben
      39. For i = 0 To 31
      40. If (1 << i And dbcv_unitmask) <> 0 Then Return Convert.ToChar(65 + i)
      41. Next
      42. Return "?"c
      43. End Function
      44. Public Shared Function FromPointer(ptr As IntPtr) As DEV_BROADCAST_VOLUME
      45. Return DirectCast(Marshal.PtrToStructure(ptr, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
      46. End Function
      47. End Structure
      Ach - fast vergessen: Marshal.PtrToStructure(IntPtr, structType) (zeile#54) - das ist die Methode, die die Daten vom unmanaged Pointer ausliest in eine geeignete .Net-Structure.

      Übrigens habich dem Download auch noch ein Enum mit allen WM-Konstanten beigelegt - ach kann ich ja auch zeigen:
      alle WM-Konstanten

      VB.NET-Quellcode

      1. Public Enum WM_CONST As Integer
      2. WM_ACTIVATE = 6
      3. WM_ACTIVATEAPP = 28
      4. WM_AFXFIRST = 864
      5. WM_AFXLAST = 895
      6. WM_APP = 32768
      7. WM_ASKCBFORMATNAME = 780
      8. WM_CANCELJOURNAL = 75
      9. WM_CANCELMODE = 31
      10. WM_CAPTURECHANGED = 533
      11. WM_CHANGECBCHAIN = 781
      12. WM_CHAR = 258
      13. WM_CHARTOITEM = 47
      14. WM_CHILDACTIVATE = 34
      15. WM_CLEAR = 771
      16. WM_CLOSE = 16
      17. WM_COMMAND = 273
      18. WM_COMMNOTIFY = 68
      19. WM_COMPACTING = 65
      20. WM_COMPAREITEM = 57
      21. WM_CONTEXTMENU = 123
      22. WM_COPY = 769
      23. WM_COPYDATA = 74
      24. WM_CREATE = 1
      25. WM_CTLCOLOR = 25
      26. WM_CTLCOLORBTN = 309
      27. WM_CTLCOLORDLG = 310
      28. WM_CTLCOLOREDIT = 307
      29. WM_CTLCOLORLISTBOX = 308
      30. WM_CTLCOLORMSGBOX = 306
      31. WM_CTLCOLORSCROLLBAR = 311
      32. WM_CTLCOLORSTATIC = 312
      33. WM_CUT = 768
      34. WM_DEADCHAR = 259
      35. WM_DELETEITEM = 45
      36. WM_DESTROY = 2
      37. WM_DESTROYCLIPBOARD = 775
      38. WM_DEVICECHANGE = 537
      39. WM_DEVMODECHANGE = 27
      40. WM_DISPLAYCHANGE = 126
      41. WM_DRAWCLIPBOARD = 776
      42. WM_DRAWITEM = 43
      43. WM_DROPFILES = 563
      44. WM_ENABLE = 10
      45. WM_ENDSESSION = 22
      46. WM_ENTERIDLE = 289
      47. WM_ENTERMENULOOP = 529
      48. WM_ENTERSIZEMOVE = 561
      49. WM_ERASEBKGND = 20
      50. WM_EXITSIZEMOVE = 562
      51. WM_FONTCHANGE = 29
      52. WM_GETDLGCODE = 135
      53. WM_GETFONT = 49
      54. WM_GETHOTKEY = 51
      55. WM_GETICON = 127
      56. WM_GETMINMAXINFO = 36
      57. WM_GETOBJECT = 61
      58. WM_GETTEXT = 13
      59. WM_GETTEXTLENGTH = 14
      60. WM_HANDHELDFIRST = 856
      61. WM_HANDHELDLAST = 863
      62. WM_HELP = 83
      63. WM_HOTKEY = 786
      64. WM_HSCROLL = 276
      65. WM_HSCROLLCLIPBOARD = 782
      66. WM_ICONERASEBKGND = 39
      67. WM_IME_CHAR = 646
      68. WM_IME_COMPOSITION = 271
      69. WM_IME_COMPOSITIONFULL = 644
      70. WM_IME_CONTROL = 643
      71. WM_IME_ENDCOMPOSITION = 270
      72. WM_IME_KEYDOWN = 656
      73. WM_IME_KEYUP = 657
      74. WM_IME_NOTIFY = 642
      75. WM_IME_SELECT = 645
      76. WM_IME_SETCONTEXT = 641
      77. WM_IME_STARTCOMPOSITION = 269
      78. WM_INITDIALOG = 272
      79. WM_INITMENU = 278
      80. WM_INITMENUPOPUP = 279
      81. WM_INPUTLANGCHANGE = 81
      82. WM_INPUTLANGCHANGEREQUEST = 80
      83. WM_KEYDOWN = 256
      84. WM_KEYLAST = 264
      85. WM_KEYUP = 257
      86. WM_KILLFOCUS = 8
      87. WM_LBUTTONDBLCLK = 515
      88. WM_LBUTTONDOWN = 513
      89. WM_LBUTTONUP = 514
      90. WM_MBUTTONDBLCLK = 521
      91. WM_MBUTTONDOWN = 519
      92. WM_MBUTTONUP = 520
      93. WM_MDIACTIVATE = 546
      94. WM_MDICASCADE = 551
      95. WM_MDICREATE = 544
      96. WM_MDIDESTROY = 545
      97. WM_MDIGETACTIVE = 553
      98. WM_MDIICONARRANGE = 552
      99. WM_MDIMAXIMIZE = 549
      100. WM_MDINEXT = 548
      101. WM_MDIREFRESHMENU = 564
      102. WM_MDIRESTORE = 547
      103. WM_MDISETMENU = 560
      104. WM_MDITILE = 550
      105. WM_MEASUREITEM = 44
      106. WM_MENUCHAR = 288
      107. WM_MENULOOP = 530
      108. WM_MENUSELECT = 287
      109. WM_MOUSEACTIVATE = 33
      110. WM_MOUSEHOVER = 673
      111. WM_MOUSELEAVE = 675
      112. WM_MOUSEMOVE = 512
      113. WM_MOUSEWHEEL = 522
      114. WM_MOVE = 3
      115. WM_MOVING = 534
      116. WM_NCACTIVATE = 134
      117. WM_NCCALCSIZE = 131
      118. WM_NCCREATE = 129
      119. WM_NCDESTROY = 130
      120. WM_NCHITTEST = 132
      121. WM_NCLBUTTONDBLCLK = 163
      122. WM_NCLBUTTONDOWN = 161
      123. WM_NCLBUTTONUP = 162
      124. WM_NCMBUTTONDBLCLK = 169
      125. WM_NCMBUTTONDOWN = 167
      126. WM_NCMBUTTONUP = 168
      127. WM_NCMOUSEMOVE = 160
      128. WM_NCPAINT = 133
      129. WM_NCRBUTTONDBLCLK = 166
      130. WM_NCRBUTTONDOWN = 164
      131. WM_NCRBUTTONUP = 165
      132. WM_NEXTDLGCTL = 40
      133. WM_NEXTMENU = 531
      134. WM_NOTIFY = 78
      135. WM_NOTIFYFORMAT = 85
      136. WM_NULL = 0
      137. WM_PAINT = 15
      138. WM_PAINTCLIPBOARD = 777
      139. WM_PAINTICON = 38
      140. WM_PALETTECHANGED = 785
      141. WM_PALETTEISCHANGING = 784
      142. WM_PARENTNOTIFY = 528
      143. WM_PASTE = 770
      144. WM_PENWINFIRST = 896
      145. WM_PENWINLAST = 911
      146. WM_POWER = 72
      147. WM_POWERBROADCAST = 536
      148. WM_PRINT = 791
      149. WM_PRINTCLIENT = 792
      150. WM_QUERYDRAGICON = 55
      151. WM_QUERYENDSESSION = 17
      152. WM_QUERYNEWPALETTE = 783
      153. WM_QUERYOPEN = 19
      154. WM_QUEUESYNC = 35
      155. WM_QUIT = 18
      156. WM_RBUTTONDBLCLK = 518
      157. WM_RBUTTONDOWN = 516
      158. WM_RBUTTONUP = 517
      159. WM_RENDERALLFORMATS = 774
      160. WM_RENDERFORMAT = 773
      161. WM_SETCURSOR = 32
      162. WM_SETFOCUS = 7
      163. WM_SETFONT = 48
      164. WM_SETHOTKEY = 50
      165. WM_SETICON = 128
      166. WM_SETREDRAW = 11
      167. WM_SETTEXT = 12
      168. WM_SHOWWINDOW = 24
      169. WM_SIZE = 5
      170. WM_SIZECLIPBOARD = 779
      171. WM_SIZEMOVE = 562
      172. WM_SIZING = 532
      173. WM_SPOOLERSTATUS = 42
      174. WM_STYLECHANGED = 125
      175. WM_STYLECHANGING = 124
      176. WM_SYSCHAR = 262
      177. WM_SYSCOLORCHANGE = 21
      178. WM_SYSCOMMAND = 274
      179. WM_SYSDEADCHAR = 263
      180. WM_SYSKEYDOWN = 260
      181. WM_SYSKEYUP = 261
      182. WM_TCARD = 82
      183. WM_TIMECHANGE = 30
      184. WM_TIMER = 275
      185. WM_UNDO = 772
      186. WM_USER = 1024
      187. WM_USERCHANGED = 84
      188. WM_VKEYTOITEM = 46
      189. WM_VSCROLL = 277
      190. WM_VSCROLLCLIPBOARD = 778
      191. WM_WINDOWPOSCHANGED = 71
      192. WM_WINDOWPOSCHANGING = 70
      193. WM_WININICHANGE = 26
      194. WM_UnKnown_FOCUSMOVED = 4110
      195. WM_Reflect = 8192
      196. End Enum 'WM_CONST
      Also das wird hier jetzt nicht genutzt, aber vlt sucht man ja mal den einen oder anderen Wert davon
      Dateien
      • UsbDetector.zip

        (13,73 kB, 252 mal heruntergeladen, zuletzt: )
      • UsbDetectorCs.zip

        (12,71 kB, 192 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()