Laden...

Event zu Mount und Unmount von Laufwerken?

Erstellt von Subtrivial vor 17 Jahren Letzter Beitrag vor 17 Jahren 9.102 Views
S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren
Event zu Mount und Unmount von Laufwerken?

Hallo,

im Windows Explorer werden Änderungen an den Verzeichnissen automatisch aktualisiert. Legt man beispielsweise eine neue CD ein, wird diese in der Ordnerliste hinzugefügt (inklusive dem Label des Mediums).

Die gleiche Funkionalität möchte ich nun in einem Control einbauen, damit nicht jedesmal die kompletten Laufwerksinformationen neu ausgelesen werden müssen. Ein unschöner Effekt dabei ist, dass das Floppy jedesmal "Musik" macht und das Control dadurch etwas hakt.

Die einfachste Lösung wäre wohl eine Klasse, die ein Event feuert, falls sich in der Laufwerkliste etwas ändert. Ich hatte schon mit der Klasse System.IO.FileSystemWatcher herum experimentiert, hatte aber bislang keinen Erfolg:


public static void Beispiel()
{
FileSystemWatcher fsWatcher = new FileSystemWatcher();
fsWatcher.Path = "A:\\";
fsWatcher.IncludeSubdirectories = false;
fsWatcher.EnableRaisingEvents = true;
fsWatcher.Changed +=new FileSystemEventHandler(fsWatcher_Changed);
}

static void fsWatcher_Changed(object sender, FileSystemEventArgs e)
{
// Code
}

Und die Win API macht mir aufgrund ihrer Größe ziemliche Angst. 😉

Hat da zufällig einer eine Idee?

2.921 Beiträge seit 2005
vor 17 Jahren

Du könntest z.B. mit WMI auslesen, ob sich an der Laufwerksliste was geändert hat. Wenn Du aber nicht weisst, wie man das vom Betriebssystem mitbekommt (weiss ich auch nicht), dann musst du z.B. mit einem Timer alle n Sekunden prüfen, ob sich was geändert hat.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren

Hallo dr4g0n76,

zuerst einmal zu der Idee mit dem Timer: Genau DAS möchte ich mit den Events vermeiden. Außerdem würden das "Pollen" nur unnötig Ressourcen verschwenden und mein Floppy würde dann auch nur noch rattern.

Mit WMI habe ich noch nie gearbeitet. Vielleicht finde ich hier die Lösung. Alles was ich im Grunde benötige ist ein Klassenname. Und wenn ich den Namen einer API-Funktion hätte, wäre mir auch schon geholfen. Naja, muss ich mal weiter suchen.

Auf jeden Fall vielen Dank für die schnelle Antwort 🙂 .

B
1.529 Beiträge seit 2006
vor 17 Jahren

Mit der API-Funktion RegisterDeviceNotification kann deine Anwendung den Empfang von WM_DEVICECHANGE-Nachrichten aktivieren.
Jedes Mal, wenn sich eines der festgeleten Geräte oder Medien ändert, wird diese Nachricht erzeugt. Du kannst sie in der WndProc abfangen.
Wenn die Anwendung fertig ist, muss sie den Empfang mit UnregisterDeviceNotification wieder abschalten.

Im Platform SDK ist dazu Beispielcode enthalten.

PS.: Falls sich ein Laufwerksbuchstabe ändern sollte, wird WM_DEVICECHANGE automatisch (auch ohne vorheriges RegisterDeviceNotification) an alle Top-Level Anwendungen geschickt.

S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren

Hallo Borg,

klasse Tip, danke 🙂 . Mit dem Code


protected override void WndProc(ref Message m)
{

if (m.Msg == WM_DEVICECHANGE) // == 0x219
{
Console.Beep(); // Test
}

base.WndProc(ref m);
}

im Applikationsfenster erhalte ich "Beeps", wenn ich den USB-Stick abziehe bzw. wieder anstecke. Diese Funktionalität steht mir leider nicht zur Verfügung, wenn ich in von Control abgeleiteten Klassen arbeite. Aber gerade dort möchte ich auf WM_DEVICECHANGE reagieren können. Und es wäre ausgesprochen unschön, wenn man immer erst noch Code in die WndProc-Funktion der Forms einfügen müsste, um meine Controls zu informieren.

Auch mit den von Dir erwähnten Funktionen RegisterDeviceNotification und _UnregisterDeviceNotification _komme ich da nicht weiter.

B
1.529 Beiträge seit 2006
vor 17 Jahren

Ich verstehe dein Problem nicht: für jedes deiner Forms wird doch eine eigene Klasse definiert. Und diejenigen Forms, die eine Benachrichtung wünschen, überschreiben halt WndProc. Das ist doch nicht so kompliziert. Alternativ kannst du auch eine eigene Klasse dafür schreiben, die dafür Events anbietet, und von dieser ableiten.

S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren

Also:

Von Form angeleitete Klassen erhalten in der WndProc die WM_DEVICECHANGE-Nachricht, nicht aber Controls wie die ComboBox. So zeigte sich mir das Verhalten. Ich möchte sie aber in einer ComboBox abfangen, da dieses Control in einer DLL zur Verfügung gestellt werden soll. Solbald diese DLL verwendet wird wäre es äußerst unschön, wenn der Benutzer zur Nutzung des Controls jedesmal die WndProc des Forms überschreiben müsste. Es liegt nahe, dass das das Control selber leisten soll.

Ich habe auch eine mögliche Lösung gefunden. Dazu binde ich eine geschachtelte Klasse in das Control ein, die von NativeWindow erbt. Sie überschreibt die WndProc und feuert beim Eintreffen der WM_DEVICECHANGE-Nachricht ein Event:


private class WindowMessageListener : NativeWindow
{
public delegate void Informer();
public event Informer informer = null;


public WindowMessageListener()
{
if (Form.ActiveForm != null)
{
IntPtr fHandle = Form.ActiveForm.Handle;
this.AssignHandle(fHandle);
}
}


protected override void WndProc(ref Message m)
{
if (m.Msg == WM_DEVICECHANGE)
{
if (this.informer != null)
{
this.informer();
}
}

base.WndProc(ref m);
}
}

Nun kann ein Event Handler angehängt werden, der dann die gewünschte Aktion ausführt:


this.windowMessageListener.informer += new WindowMessageListener.Informer(this.test);

...


private void test()
{
Console.Beep();
}

Bei genauerer Betrachtung ist dieser Ansatz sogar recht elegant. Selbstverständlich bin ich auch für alternative Lösungen offen. Vielleicht geht es ja noch einfacher 🙂

B
1.529 Beiträge seit 2006
vor 17 Jahren

Nun gut, die Lösung ist sehr funktional. Elegant würde ich noch nicht sagen, da du ja nur zum Empfang einer einzigen Nachricht ein ganzes Fenster geöffnet hältst. (Auch wenn es nicht angezeigt wird.)

Eventuell solltest du dich doch noch mit RegisterDeviceNotification auseinander setzen. Ist vielleicht am Anfang etwas schwierig, aber dafür kannst du dann jede beliebige WndProc die Nachrichten empfangen lassen.

Mit Sicherheit solltest du aber Event und Delegate noch aussagekräftige Namen verpassen. Wie wäre es mit DeviceChangedHandler und DeviceChanged? Desweiteren würde ich dem Handler als Parameter entweder die Änderung mitteilen (empfängst du ja mit WM_DEVICECHANGE) oder die neue Laufwerksliste. Dazu könntest du ja eine Methode OnDeviceChanged benutzen. Dann ist diese Funktionalität auch "ästhetisch" in die schon bestehende Klasse eingebunden.

S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren

Wenn das mit RegisterDeviceNotification funktionieren sollte, wäre das natürlich klasse. Was die Benennung betrifft, so war ich nur "zu faul" 😄.

Zwischen den Jahren werde ich mir das dann noch einmal näher zu Gemüte führen. Ich danke Dir auf jeden Fall. Bis dahin wünsche ich dir ein frohes Fest.

S
Subtrivial Themenstarter:in
6 Beiträge seit 2006
vor 17 Jahren

Zuerst einmal: Frohe Weihnachten!

Ich bin noch einmal dem Vorschlag von dr4g0n76 nachgegangen, da mir die API-Geschichte nicht so gut gefallen. Ein weiteres Problem ist nämlich, dass die Nachrichten teilweise mehrfach in die WndProc reinkommen.

Mit der ManagementEventWatcher-Klasse konnte ich nun auf verschiedene Events recht einfach reagieren. Eine Sache wäre da allerdings noch. ManagementEventWatcher verfügt u.a. über zwei Methoden: Start() und Stop(), die die Überwachung starten oder eben stoppen. Solange dass Programm ordnungsgemäß beendet wird, ist alles bestens. Sollte die Applikation aber abstürzen, läuft auch die Überwachung weiter, da Stop() nicht aufgerufen wurde. Das Betriebssystem prüft nach wie vor den Status der Laufwerke. Erst nach dem Windows-Neustart läuft wieder alles wie gehabt.

Nun meine Frage:
Gibt es eine Möglichkeit die Überwachung dennoch zu beenden? Kann man da etwas mit AppDomain ausrichten?

Und hier drei Websites, die mir weitergeholfen habe:*http://www.thescripts.com/forum/thread264280.html *MSDN (Win32_DiskDrive): http://msdn2.microsoft.com/en-us/library/aa394132.asp *MSDN (Win32_LogicalDisk): http://msdn2.microsoft.com/en-us/library/aa394173.aspx