Darf auf ein Laufwerk zugegriffen werden? try/catch
-
ich hab ein Problem mit dem Zugriff auf Laufwerke. ich benutze die DriveComboBox, um zwischen den Laufwerken zu wechslen.
Durch das ändern der DCB wird ein DirectoryListBox-Feld verändert.
Wenn ich auf ein Laufwerk komme, in dem kein Datenträger ist, wird die DLB auch verändert, jedoch gibt das ja einen Fehler. Daher habe ich diesen Teil in ein try-Block gepackt. Bei einem solchen Fehler soll die DCB wieder auf das vorherige Laufwerk gestellt werden.Dazu habe ich bis jetzt folgenden Quelltext:
Bei ändern des Laufwerks in der DCB:
void __fastcall TForm1::DriveComboBox1Change(TObject *Sender) { try{ if(Rsave->Checked==true){ laufwerk_save = char (DriveComboBox1->Drive); String pfad = DriveComboBox1->Drive; if(strcmp(String(vorherigesLaufwerk_save).c_str(),pfad.c_str())!=0){ update_path(pfad + ":\\"); } update_dlb(); vorherigesLaufwerk_save = char (DriveComboBox1->Drive); } else{ laufwerk_share = char (DriveComboBox1->Drive); String pfad = DriveComboBox1->Drive; if(strcmp(String(vorherigesLaufwerk_share).c_str(),pfad.c_str())!=0){ update_path(pfad + ":\\"); } update_dlb(); vorherigesLaufwerk_share = char (DriveComboBox1->Drive); } } catch(...){ String aFehler = "Auf Laufwerk " + String (DriveComboBox1->Drive) + ": kann nicht zugegriffen werden!"; char *Fehler = aFehler.c_str(); Application->MessageBox(Fehler, "Achtung!", 16); if(Rsave->Checked==true){ DriveComboBox1->Drive = vorherigesLaufwerk_save; } else{ DriveComboBox1->Drive = vorherigesLaufwerk_share; } } }die verwendeten Funktionen:
void update_dlb(void){ if(Form1->Rsave->Checked==true){ Form1->DriveComboBox1->Drive = laufwerk_save; Form1->DirectoryListBox1->Directory = pfad_save; } else{ Form1->DriveComboBox1->Drive = laufwerk_share; Form1->DirectoryListBox1->Directory = pfad_share; } update_edit(); } void update_edit(void){ if(Form1->Rsave->Checked==true){ if(strcmp(neuer_ordner_save.c_str(),pfad_save.c_str())==0){ Form1->Edit1->Text = pfad_save; } else{ Form1->Edit1->Text = pfad_save + ordnername_save; } } else{ if(strcmp(neuer_ordner_share.c_str(),pfad_share.c_str())==0){ Form1->Edit1->Text = pfad_share; } else{ Form1->Edit1->Text = pfad_share + ordnername_share; } } }Das Problem besteht nun darin, dass dieses immer 2 mal eine Fehlermeldung ausgibt. Das erste mal die korrekte, z.B.:
Auf Laufwerk A: kann nicht zugegriffen werdenBeim zweiten mal gibt es aber die Ausgabe:
Auf Laufwerk C: kann nicht zugegriffen werdenJedoch ist das Laufwerk C: das Laufwerk, welches vorher angewählt war.
Daran, dass alles doppelt ist, braucht ihr euch nicht weiter zu stören, da ich zwei Pfade auswählbar sein sollen, je nach dem, welchen radiobutton ich angewählt habe.
Ich benutze den BCB 2 Standard.
-
Debugger?
-
Poste doch mal bitte die fehlende Funktion zum Aufruf von
update_path(pfad + ":\\");MfG
kpeter
-
sry, übersehen:
void update_path(String pfad){ if(Form1->Rsave->Checked==true){ pfad_save = pfad; } else{ pfad_share = pfad; } update_edit(); }
-
Das OnChange der DCB feuert immer zweimal.
Ich würde einfach die ApplicationEvents-Komponente benutzen, wenn es die in deinem BCB gibt (du hast 1 oder 3, Version 2 gab es nicht).char chDrive; void __fastcall TForm1::DriveComboBox1Change(TObject *Sender) { chDrive = DriveComboBox1->Drive; } //--------------------------------------------------------------------------- void __fastcall TForm1::ApplicationEvents1Exception(TObject *Sender, Exception *E) { if (dynamic_cast<EInOutError*>(E) && // ist eine IO-Exception, E->Message.Pos(" 21") == E->Message.Length() - 2) // und hat Fehlernr. 21 { ShowMessage("Auf Laufwerk " + UpperCase(DriveComboBox1->Drive) + ": kann nicht zugegriffen werden."); DriveComboBox1->Drive = chDrive; } } //---------------------------------------------------------------------------
-
(Vorweg: is da nicht n kleiner Tippfehler?:
anstatt ApplicationEvents1Exception muss es doch heissen ApplicationEventsException?)Das macht leider auch nicht viel anders:
Wenn ich jetzt auf ein Laufwerk komme, auf das nicht zugegriffen werden kann, gibt es immer noch diese typische windoof-Fehlermeldung, dass auf Laufwerk A: nicht zugegriffen werden kann mit den 3 Buttons: Abbrechen, Wiederholen und weiter.
Das Edit-Feld wird daraufhin aktualisiert. Dann steht da "A:", obwohl es eig wieder zurückgestellt werden soll.
Danach kommt die Meldung: "I/O-Fehler 21".
Dann läuft das Prog weiter. Wenn ich dann aber wieder auf ein anderes Laufwerk komme, gibt es erneut die Fehlermeldung, dass auf A: nicht zugegriffen werden kann und auch nochmal die Meldung "I/O-Fehler 21".
Jedoch wird das Laufwerk nicht zurückgestellt. Das liegt daran, dass im DriveComboBox1Change der Variable vorherigesLaufwerk_.... der Wert des Laufwerks, auf das eig nicht zugegriffen werden darf, zugewiesen wird. Ich weis jedoch nicht, wie ich das beheben kann (vllt im ApplicationEventsException einen zweig machen, wenn kein Fehler vorliegt? Da müsste dann auch das update_dlb() aus dem DCB-Change rein).//--------------------------------------------------------------------------- void __fastcall TForm1::DriveComboBox1Change(TObject *Sender) { if(Rsave->Checked==true){ laufwerk_save = char (DriveComboBox1->Drive); String pfad = DriveComboBox1->Drive; if(strcmp(String(vorherigesLaufwerk_save).c_str(),pfad.c_str())!=0){ update_path(pfad + ":\\"); } update_dlb(); vorherigesLaufwerk_save = char (DriveComboBox1->Drive); } else{ laufwerk_share = char (DriveComboBox1->Drive); String pfad = DriveComboBox1->Drive; if(strcmp(String(vorherigesLaufwerk_share).c_str(),pfad.c_str())!=0){ update_path(pfad + ":\\"); } update_dlb(); vorherigesLaufwerk_share = char (DriveComboBox1->Drive); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ApplicationEventsException(TObject *Sender, Exception *E) { if (dynamic_cast<EInOutError*>(E) && // ist eine IO-Exception, E->Message.Pos(" 21") == E->Message.Length() - 2) // und hat Fehlernr. 21 { ShowMessage("Auf Laufwerk " + UpperCase(DriveComboBox1->Drive) + ": kann nicht zugegriffen werden."); if(Rsave->Checked==true){ DriveComboBox1->Drive = vorherigesLaufwerk_save; } else{ DriveComboBox1->Drive = vorherigesLaufwerk_share; } update_dlb(); } } //---------------------------------------------------------------------------
-
Ich kann nicht wirklich nachvollziehen, was dein Programm eigentlich macht bzw. machen soll, deshalb fällt es mir schwer, dein Problem zu erkennen. Bist du sicher, dass du die ganzen update_xyz-Funktionen wirklich brauchst?
In meinem Beispiel (Zeile 15) wird der Pfad zurückgestellt, und bleibt dann auch so.
-
ich hab 3 felder:
- eine DCB
- eine DBL
- ein Edit-FeldIm DCB wähl ich das Laufwerk aus. Dann wir die DLB aktualisiert und dann das Edit-Feld. Dann gibt's noch nen Button, mit dem man nen neuen Ordner erstellen kann.
Standardmäßig wird im Edit-Feld ein extra Ordnername hinter den ausgewählten Ordner gehängt. Wenn ich aber nen neuen Ordner erstellt habe, soll der Standardordnername nicht mehr hinten dran gehängt werden. Wenn dann aber der Ordner wieder gewechselt wird, soll der Standardordnername wieder angehängt werden bzw. nicht mehr angehängt werden, wenn man wieder auf den selbst erstellten Ordner klickt.
Außerdem kann man zwischen 2 Radio-Buttons wechseln und man soll den Pfad für beie Radio-Buttons unterschiedlich wählen können.Die update-Funktionen sollen einfach nur die Variablenwerte in die DCB, die DLB bzw. das Edit-Feld reinschreiben und somit den korrekten Pfad anzeigen. Funktionen hab ich genommen, weil immer überprüfen werden muss, welcher Radio-Button ausgewählt ist.
Zu Zeile 15: Der aktuelle Pfad wird in die Variable geschrieben, weil ich nur so entscheiden kann, ob jetzt die Variable vorhehrigesLaufwerk_... verändert werden muss oder nicht (wegen den 2 Möglichkeiten durch die Radio-Buttons).
-
Hilft das folgende?
Boolean __fastcall DriveOk(char Drive) { char RootPathName[256]="*:\\"; // address of name of root directory char VolumeNameBuffer[256]; // address of name of the volume DWORD VolumeSerialNumber; // address of volume serial number DWORD MaximumComponentLength; // address of system's maximum filename length DWORD FileSystemFlags; // address of file system flags char FileSystemNameBuffer[256]; // address of name of file system Boolean Res; UINT OldErrMode; OldErrMode=SetErrorMode(SEM_FAILCRITICALERRORS); /* LPCTSTR lpRootPathName, // address of root directory of the file system LPTSTR lpVolumeNameBuffer, // address of name of the volume DWORD nVolumeNameSize, // length of lpVolumeNameBuffer LPDWORD lpVolumeSerialNumber, // address of volume serial number LPDWORD lpMaximumComponentLength, // address of system's maximum filename length LPDWORD lpFileSystemFlags, // address of file system flags LPTSTR lpFileSystemNameBuffer, // address of name of file system DWORD nFileSystemNameSize // length of lpFileSystemNameBuffer */ RootPathName[0]=Drive; Res=GetVolumeInformation(RootPathName,VolumeNameBuffer,255, &VolumeSerialNumber,&MaximumComponentLength, &FileSystemFlags,FileSystemNameBuffer,255 ); SetErrorMode(OldErrMode); return Res; }Damit teste ich immer VOR einem Zugriffsversuch, ob das LW verfügbar ist.
-
Beherzige Jansens Tipp/Code aus seinem ersten Posting!
Damit ist die Exception-Behandlung doch gelöst und den try-catch-block kannst du rausschmeissen.
Wenn du keine MessageBox haben willst, kannst du elegant ein TLabel visible machen und die
Nachricht ausgeben (mit Timer natürlich blink blink :D).
Die char-Deklaration chDrive gehört in der Header-Datei public gemacht,
dann kannst du auch dein Edit1 "zurückstellen".Um ehrlich zu sein, ich habe den Code mal in die Maschine gehaun und bin zu
dem Schluss gekommen, dass, wenn du schon Pfade etc. aufzeichnen willst, du
diese Daten in ein StringGrid schreiben solltest.
So kannst du deine vielen Variablen abspecken, hast Zugriff auf die im Grid abgelegten Pfade und
übersichtlicher ist es auch.Und wetten, dass es kein Schreibfehler war?
MfG
kpeter
-
Der Code funzt wirklich wunderbar!!
THXMit ApplicationEvents1Exception funzt das nicht.
Hab aber noch eine kleine Frage: Wie kann ich den Code ändern, dass auch überprüft wird, ob ich in den Pfad schreiben darf?
-
Wie meinst du denn das jetzt?
Wenn du Administratorrechte auf dem PC hast, kommst du in gewissen Sinne an jede
Windows-Datei heran.Suche mal in der IDE-Hilfe nach z.B. ExtractFilePath, dann bist du schon
beim richtigen Thema.MfG
kpeter
-
Dass man mit Administratorrechten überall ran kommt is logisch^^.
Aber mit ExtractFilePath kommt man, soweit ich das sehe, nur an den Pfad ran, in dem die exe liegt. Ich möchte aber wissen, ob ich auf irgendeinen Pfad (den ich vorher auswähle) Schreibrechte hab.
-
Wozu musst du das wissen? Pack deine Schreibversuche in eine ordentliche Fehlerbehandlung und gut ist.
-
Jo, so gehts natürlich auch.
THX