Canvas not supported
Canvas not supported
Suchen
Bookmark
Canvas not supported
Shine Effekt
Direkt zum Seiteninhalt

Hauptmenü:

PNP Hardware-Änderungen erkennen

 

Autor:

Oscar Kohler

Version:

0.11

Level:

Einfach

Sprache:

C/C++


 
Haftungsausschluss / Disclaimer
Kontakt / Contact
Drucken / Print


Eine der beeindruckensten Fähigkeiten von Windows, zumindest ab Windows XP, ist wohl die Plug and Play (PNP) Funktion.
Hinter diesem genialen Mechanismus steckt der PNP Manager. Dieser erkennt und enumeriert beim Systemboot die angeschlossene Hardware und sorgt im laufenden Betrieb dafür, dass Änderungen an
Geräten erkannt und entsprechend bearbeitet werden.

Oftmals wäre es vorteilhaft, wenn nicht nur Windows solche Änderungen entdeckt, sondern auch unser Programm
etwas davon mitbekommen würde.

Änderungen am System, die auch für laufende Programme interessant sein könnten, gibt Windows in der Regel mittels Nachrichten an die betreffenden Programme weiter.

Tutorial: Window Basics

Auch Änderungen an der PNP Hardware teilt Windows freundlicherweise den einzelnen Programmen, durch Sendung der Windows Message: WM_DEVICECHANGE an alle Top-Level Fenster, mit.

Device Änderung erkennen in der Praxis


  • Medien Player durchsucht frisch eingesteckte USB-Storage-Devices nach abspielbaren Mediendaten,
  • Eingesteckte Wechselmedien (CD/DVD, USB Sticks, ...) werden auf definierte, freie Laufwerksbuchstaben um-gemounted,

  • Bestimmte Wechselmedien werden aus Scherheitsgründen gesperrt,

  • ...


Windows teilt uns praktisch jede PNP Änderung mit ... sofern wir das auch wünschen ...
Standardmässig teilt uns Windows Änderungen an Ports (DBT_DEVTYP_PORT) und Logischen-Volumes (DBT_DEVTYP_VOLUME) immer mit.
Möchten wir auch über andere Geräte Klassen informiert werden, können wir dies mittels der Funktion:  RegisterDeviceNotification(...) angeben.

WM_DEVICECHANGE Nachrichten werden direkt, ohne den Umweg über die Thread-Message-Queue, an die Windows Prozedur: WndProc der einzelnen (GUI) Programme gesendet.

In einem GUI Programm können wir anhand der Message ID auf die Nachricht warten:

...
switch (
message ) {
  case
WM_DEVICECHANGE:
     ...
  break;
}
...

Durch den wParam der Nachricht können wir zwischen dem Ein / und Ausstecken des Gerätes unterscheiden:

...
  case
WM_DEVICECHANGE:
     
     // Device inserted

     if (
wParam == DBT_DEVICEARRIVAL ) {
        MessageBox( hWnd, _T( "Device inserted !" ), _T( "Device change ..." ), MB_OK );
     }

     
// Device removed

     else if (
wParam == DBT_DEVICEREMOVECOMPLETE ) {
        MessageBox( hWnd, _T( "Device removed !" ), _T( "Device change ..." ), MB_OK );
     }

     break;
...

Stecken wir nun einen USB-Stick ein und wieder aus, so erhalten wir jeweils die passende MessageBox !

Device Type erkennen


Der lParam Wert gibt uns die universelle PDEV_BROADCAST_HDR Struktur mit, aus der wir den Device-Typen und somit auch die "Reale" Device-Struktur ermitteln können:

...
  if (
wParam == DBT_DEVICEARRIVAL ) {
     PDEV_BROADCAST_HDR
lpDC = ( PDEV_BROADCAST_HDR )lParam;
     DWORD
dwDT = lpDC->dbch_devicetype;
  }
...


MSDN: DEV_BROADCAST_HDR


In unserem Falle ist das Device vom Typ: DBT_DEVTYP_VOLUME, also ein Volume-Device und daher können wir uns mittels der Struktur: PDEV_BROADCAST_VOLUME weiterhangeln.


MSDN: DEV_BROADCAST_VOLUME


Nocheinmal erwähnt: Je nach Device Type handelt es sich um eine eigene Struktur !

Nun können wir sehr einfach ermitteln, welche(n) "Laufwerks Buchstaben" es betraf und um welchen Volumen-Typen es sich handelt.

...
  
if ( wParam == DBT_DEVICEARRIVAL ) {
     PDEV_BROADCAST_HDR
lpDC = ( PDEV_BROADCAST_HDR )lParam;
     if (
lpDC->dbch_devicetype == DBT_DEVTYP_VOLUME ) {
        PDEV_BROADCAST_VOLUME lpBV = ( PDEV_BROADCAST_VOLUME )lpDC;
        DWORD
dwMask = lpBV->dbcv_unitmask;
        WORD
wType =  lpBV->dbcv_flags;
     }
  }
...

Geschafft (1) ...



Die dbcv_unitmask gibt an, welches logische Laufwerk sich geändert hat. Dies kann durchaus auch mehrere Laufwerke betreffen.
Wie für eine Bit-Maske üblich, bezeichnet Bit 0 das Laufwerk 0 - also A:, Bit 1 das Laufwerk 1 - also B:, Bit 2 das Laufwerk 2 - also C:, ...
Floppy Laufwerke A / B werden jedoch oftmals nicht angezeigt.
Bei mit steht in dwMask der dezimale Wert 512, das entspricht
%1000000000, also wurde das Laufwerk J: geändert !

Die dbcv_flags zeigen noch den Volume-Type an. In meinem Fall ein Physisches Laufwerk.

Device Änderungen mittels Service erkennen


In einer GUI Anwendung, die diese Nachrichten mittels WndProc verarbeiten kann, funktioniert es prinzipiell ganz gut.
Nicht immer ist eine GUI Anwendung aber die erste Wahl. Vorallem bei sicherheitsrelevanten Anwendungen wird meist eher ein Windows Service bevorzugt. Jedoch verfügen die wenigsten Windows Services über ein Top Level Window ...

Nicht verzagen ... auch bei Services funktioniert es recht ähnlich ...

Bei Registrierung der Device Notification wird einfach ein Service Statushandle angegeben:

...
hDevNotify =
RegisterDeviceNotification (
                                         hServiceStatusHandle,
                                         &devInterface,
                                         DEVICE_NOTIFY_SERVICE_HANDLE
                                       );
...

Im Service-Control-Handler wird dann der Device Event abgefangen:

...
  
switch( dwControl ) {
     
case SERVICE_CONTROL_DEVICEEVENT:
        if (
dwEventType == DBT_DEVICEARRIVAL ) {
           // Inserted ...
        }
        else if (
dwEventType == DBT_DEVICEREMOVECOMPLETE ) {
           // Removed ...
        }
        
break;
     ...
  }
...

Beim beenden des Services die Notification wieder sauber de-registrieren:

UnregisterDeviceNotification(hDevNotify);

Geschafft (2) ...



Das sollte es dann prinzipiell gewesen sein ...


 
Kein Kommentar
 
Letzte Änderung: 03.02.2015
button Canvas not supported button
Zurück zum Seiteninhalt | Zurück zum Hauptmenü