Hier gehts um wie man WindowMessages auswerten kann, um Änderungen an Usb-Anschlüssen wahrzunehmen.
Eine Windowmessage ist eine Struktur mit vier Elementen:
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
Hier überschreibe ich mal einfach die WndProc meines MainForms, filtere die msg auf WM_DEVICECHANGE, und logge die Treffer ins Outputfenster:
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
Hier mal der Log, der entsteht, als ich einen Usb-Stick reingesteckt habe:
Ja, leider wird
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
(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:
Also 4 Integer.
Wir kümmern uns nur um
(Ich hoffe, die Bit-Operationen
Also hier nochmal die ganze Geschichte, ein Logger, der
Ach - fast vergessen:
Übrigens habich dem Download auch noch ein Enum mit allen WM-Konstanten beigelegt - ach kann ich ja auch zeigen:
alle WM-Konstanten
Also das wird hier jetzt nicht genutzt, aber vlt sucht man ja mal den einen oder anderen Wert davon
Eine Windowmessage ist eine Struktur mit vier Elementen:
- msg (
Integer
): der MessageCode
Im Windows-Betriebsystem sind ca. 200 verschiedene Messages hinterlegt, als namentlich bekannte Integer-Konstanten, die Benennung beginnt per Konvention mitWM_
- hwnd (
IntPtr
): Handle des Ziel-Fensters - wparam (
IntPtr
): eine Zusatz-Information - lparam (
IntPtr
): noch eine Zusatz-Information - result (
IntPtr
): ein Message-Member, über den man dem Betriebssystem Informationen und Daten auch zurückgeben kann.
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:
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:
Beachte, dassOutputWindow 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
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
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:
Wir kümmern uns nur um
dbcv_unitmask
, denn das kann man als Bitmuster dekodieren, um den Laufwerksbuchstaben zu erhalten:<<
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
- Imports System.Runtime.InteropServices
- Public Class Form2
- Private Const WM_DEVICECHANGE As Integer = &H219
- Private Shared DBT_DEVICEARRIVAL As New IntPtr(&H8000)
- Private Shared DBT_DEVICEREMOVECOMPLETE As New IntPtr(&H8004)
- Private _Counter As Integer = 0
- Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
- MyBase.WndProc(msg)
- If msg.Msg <> WM_DEVICECHANGE Then Return
- Dim remark = ""
- Select Case msg.WParam
- Case DBT_DEVICEARRIVAL
- remark = "add drive: " & DEV_BROADCAST_VOLUME.FromPointer(msg.LParam).GetDriveChar
- Case DBT_DEVICEREMOVECOMPLETE
- remark = "remove drive: " & DEV_BROADCAST_VOLUME.FromPointer(msg.LParam).GetDriveChar
- End Select
- Debug.WriteLine(msg.ToString)
- WriteLog(msg.ToString, remark)
- End Sub
- ''' <summary> fügt msg und remark als numerierte neue Zeile einer Richtextbox an (die maximal 30 Zeilen anzeigt) </summary>
- Private Sub WriteLog(msg As String, remark As String)
- 'zb: msg=0x219 (WM_DEVICECHANGE) hwnd=0x950d8e wparam=0x7 lparam=0x0 result=0x1
- If remark <> "" Then remark = String.Concat(" remark=""", remark, """")
- Dim newLine = String.Concat(_Counter.ToString("000"), ": ", msg.ToString, remark)
- Dim lines = RichTextBox1.Lines.Concat({newLine})
- RichTextBox1.Lines = lines.Skip(lines.Count - 30).ToArray
- _Counter += 1
- End Sub
- End Class
- ' Struct for parameters of the WM_DEVICECHANGE message
- <StructLayout(LayoutKind.Sequential)> _
- Public Structure DEV_BROADCAST_VOLUME
- Public dbcv_size As Integer
- Public dbcv_devicetype As Integer
- Public dbcv_reserved As Integer
- Public dbcv_unitmask As Integer
- Public Function GetDriveChar() As Char
- 'die Position des in dbcv_unitmask gesetzten Bits entspricht dem Laufwerks-Buchstaben
- For i = 0 To 31
- If (1 << i And dbcv_unitmask) <> 0 Then Return Convert.ToChar(65 + i)
- Next
- Return "?"c
- End Function
- Public Shared Function FromPointer(ptr As IntPtr) As DEV_BROADCAST_VOLUME
- Return DirectCast(Marshal.PtrToStructure(ptr, GetType(DEV_BROADCAST_VOLUME)), DEV_BROADCAST_VOLUME)
- End Function
- End Structure
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:
VB.NET-Quellcode
- Public Enum WM_CONST As Integer
- WM_ACTIVATE = 6
- WM_ACTIVATEAPP = 28
- WM_AFXFIRST = 864
- WM_AFXLAST = 895
- WM_APP = 32768
- WM_ASKCBFORMATNAME = 780
- WM_CANCELJOURNAL = 75
- WM_CANCELMODE = 31
- WM_CAPTURECHANGED = 533
- WM_CHANGECBCHAIN = 781
- WM_CHAR = 258
- WM_CHARTOITEM = 47
- WM_CHILDACTIVATE = 34
- WM_CLEAR = 771
- WM_CLOSE = 16
- WM_COMMAND = 273
- WM_COMMNOTIFY = 68
- WM_COMPACTING = 65
- WM_COMPAREITEM = 57
- WM_CONTEXTMENU = 123
- WM_COPY = 769
- WM_COPYDATA = 74
- WM_CREATE = 1
- WM_CTLCOLOR = 25
- WM_CTLCOLORBTN = 309
- WM_CTLCOLORDLG = 310
- WM_CTLCOLOREDIT = 307
- WM_CTLCOLORLISTBOX = 308
- WM_CTLCOLORMSGBOX = 306
- WM_CTLCOLORSCROLLBAR = 311
- WM_CTLCOLORSTATIC = 312
- WM_CUT = 768
- WM_DEADCHAR = 259
- WM_DELETEITEM = 45
- WM_DESTROY = 2
- WM_DESTROYCLIPBOARD = 775
- WM_DEVICECHANGE = 537
- WM_DEVMODECHANGE = 27
- WM_DISPLAYCHANGE = 126
- WM_DRAWCLIPBOARD = 776
- WM_DRAWITEM = 43
- WM_DROPFILES = 563
- WM_ENABLE = 10
- WM_ENDSESSION = 22
- WM_ENTERIDLE = 289
- WM_ENTERMENULOOP = 529
- WM_ENTERSIZEMOVE = 561
- WM_ERASEBKGND = 20
- WM_EXITSIZEMOVE = 562
- WM_FONTCHANGE = 29
- WM_GETDLGCODE = 135
- WM_GETFONT = 49
- WM_GETHOTKEY = 51
- WM_GETICON = 127
- WM_GETMINMAXINFO = 36
- WM_GETOBJECT = 61
- WM_GETTEXT = 13
- WM_GETTEXTLENGTH = 14
- WM_HANDHELDFIRST = 856
- WM_HANDHELDLAST = 863
- WM_HELP = 83
- WM_HOTKEY = 786
- WM_HSCROLL = 276
- WM_HSCROLLCLIPBOARD = 782
- WM_ICONERASEBKGND = 39
- WM_IME_CHAR = 646
- WM_IME_COMPOSITION = 271
- WM_IME_COMPOSITIONFULL = 644
- WM_IME_CONTROL = 643
- WM_IME_ENDCOMPOSITION = 270
- WM_IME_KEYDOWN = 656
- WM_IME_KEYUP = 657
- WM_IME_NOTIFY = 642
- WM_IME_SELECT = 645
- WM_IME_SETCONTEXT = 641
- WM_IME_STARTCOMPOSITION = 269
- WM_INITDIALOG = 272
- WM_INITMENU = 278
- WM_INITMENUPOPUP = 279
- WM_INPUTLANGCHANGE = 81
- WM_INPUTLANGCHANGEREQUEST = 80
- WM_KEYDOWN = 256
- WM_KEYLAST = 264
- WM_KEYUP = 257
- WM_KILLFOCUS = 8
- WM_LBUTTONDBLCLK = 515
- WM_LBUTTONDOWN = 513
- WM_LBUTTONUP = 514
- WM_MBUTTONDBLCLK = 521
- WM_MBUTTONDOWN = 519
- WM_MBUTTONUP = 520
- WM_MDIACTIVATE = 546
- WM_MDICASCADE = 551
- WM_MDICREATE = 544
- WM_MDIDESTROY = 545
- WM_MDIGETACTIVE = 553
- WM_MDIICONARRANGE = 552
- WM_MDIMAXIMIZE = 549
- WM_MDINEXT = 548
- WM_MDIREFRESHMENU = 564
- WM_MDIRESTORE = 547
- WM_MDISETMENU = 560
- WM_MDITILE = 550
- WM_MEASUREITEM = 44
- WM_MENUCHAR = 288
- WM_MENULOOP = 530
- WM_MENUSELECT = 287
- WM_MOUSEACTIVATE = 33
- WM_MOUSEHOVER = 673
- WM_MOUSELEAVE = 675
- WM_MOUSEMOVE = 512
- WM_MOUSEWHEEL = 522
- WM_MOVE = 3
- WM_MOVING = 534
- WM_NCACTIVATE = 134
- WM_NCCALCSIZE = 131
- WM_NCCREATE = 129
- WM_NCDESTROY = 130
- WM_NCHITTEST = 132
- WM_NCLBUTTONDBLCLK = 163
- WM_NCLBUTTONDOWN = 161
- WM_NCLBUTTONUP = 162
- WM_NCMBUTTONDBLCLK = 169
- WM_NCMBUTTONDOWN = 167
- WM_NCMBUTTONUP = 168
- WM_NCMOUSEMOVE = 160
- WM_NCPAINT = 133
- WM_NCRBUTTONDBLCLK = 166
- WM_NCRBUTTONDOWN = 164
- WM_NCRBUTTONUP = 165
- WM_NEXTDLGCTL = 40
- WM_NEXTMENU = 531
- WM_NOTIFY = 78
- WM_NOTIFYFORMAT = 85
- WM_NULL = 0
- WM_PAINT = 15
- WM_PAINTCLIPBOARD = 777
- WM_PAINTICON = 38
- WM_PALETTECHANGED = 785
- WM_PALETTEISCHANGING = 784
- WM_PARENTNOTIFY = 528
- WM_PASTE = 770
- WM_PENWINFIRST = 896
- WM_PENWINLAST = 911
- WM_POWER = 72
- WM_POWERBROADCAST = 536
- WM_PRINT = 791
- WM_PRINTCLIENT = 792
- WM_QUERYDRAGICON = 55
- WM_QUERYENDSESSION = 17
- WM_QUERYNEWPALETTE = 783
- WM_QUERYOPEN = 19
- WM_QUEUESYNC = 35
- WM_QUIT = 18
- WM_RBUTTONDBLCLK = 518
- WM_RBUTTONDOWN = 516
- WM_RBUTTONUP = 517
- WM_RENDERALLFORMATS = 774
- WM_RENDERFORMAT = 773
- WM_SETCURSOR = 32
- WM_SETFOCUS = 7
- WM_SETFONT = 48
- WM_SETHOTKEY = 50
- WM_SETICON = 128
- WM_SETREDRAW = 11
- WM_SETTEXT = 12
- WM_SHOWWINDOW = 24
- WM_SIZE = 5
- WM_SIZECLIPBOARD = 779
- WM_SIZEMOVE = 562
- WM_SIZING = 532
- WM_SPOOLERSTATUS = 42
- WM_STYLECHANGED = 125
- WM_STYLECHANGING = 124
- WM_SYSCHAR = 262
- WM_SYSCOLORCHANGE = 21
- WM_SYSCOMMAND = 274
- WM_SYSDEADCHAR = 263
- WM_SYSKEYDOWN = 260
- WM_SYSKEYUP = 261
- WM_TCARD = 82
- WM_TIMECHANGE = 30
- WM_TIMER = 275
- WM_UNDO = 772
- WM_USER = 1024
- WM_USERCHANGED = 84
- WM_VKEYTOITEM = 46
- WM_VSCROLL = 277
- WM_VSCROLLCLIPBOARD = 778
- WM_WINDOWPOSCHANGED = 71
- WM_WINDOWPOSCHANGING = 70
- WM_WININICHANGE = 26
- WM_UnKnown_FOCUSMOVED = 4110
- WM_Reflect = 8192
- End Enum 'WM_CONST
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()