Autor |
Beitrag |
Nils:D
      
Beiträge: 131
Debian, Win XP
Delphi 7 Arch.
|
Verfasst: Mi 25.06.08 14:16
Hi,
ich möchte alle Datenträger in einer Liste ausgeben. Das auslesen der Laufwerkbuchstaben ist eine kurze Kleinigkeit, das Auslesen der Datenträgernamen ein viel zu langwieriger Akt. Folgenden Code benutze ich, das Bestimmen der Datenträgerkapazität und des freien Speicherplatzes fehlt noch --> wird später noch langsamer. Habt ihr eine Idee, wie man so etwas gut lösen könnte ? Im schlimmsten Falle würde ich die Datenträger bei Programmstart auslesen, in ein Array packen und immer wieder wenn nötig auslesen, drückt der Benutzer auf F5 bzw. auf Aktualisieren, wird alles neu eingelesen.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71:
| procedure ListLogicalDrives(var LV : TListView; ReadyOnly : Boolean = True); function DriveIsReady(const Drive : String) : Boolean; var wfd : TWin32FindData; hFindData : THandle; begin SetErrorMode(SEM_FAILCRITICALERRORS); hFindData := FindFirstFile(Pointer(Drive+'*.*'), wfd); if hFindData <> INVALID_HANDLE_VALUE then Result := True else Result := False; FindClose(hFindData); SetErrorMode(0); end;
function GetVolumeLabel(const Drive: string): string; var RootDrive : String; Buffer : Array[0..MAX_PATH+1] of Char; FileSysFlags, MaxCompLength : DWORD; begin Result := ''; FillChar(Buffer, SizeOf(Buffer), #0); if Length(Drive) = 1 then RootDrive := Drive + ':\' else RootDrive := Drive; if GetVolumeInformation(PChar(RootDrive), Buffer, SizeOf(Buffer), nil, MaxCompLength, FileSysFlags, nil, 0) then Result := String(Buffer); end; var FoundDrives, CurrentDrive : PChar; Len : DWord; begin LV.Clear;
GetMem(FoundDrives, 255); Len := GetLogicalDriveStrings(255, FoundDrives); if Len > 0 then begin try CurrentDrive := FoundDrives; while CurrentDrive[0] <> #0 do begin if ReadyOnly then begin with LV.Items.Add do begin Caption := GetVolumeLabel(CurrentDrive); SubItems.Add('Datenträger'); SubItems.Add(CurrentDrive); end; end else begin with LV.Items.Add do begin Caption := GetVolumeLabel(CurrentDrive); SubItems.Add('Datenträger'); SubItems.Add(CurrentDrive); end; end; CurrentDrive := PChar(@CurrentDrive[Succ(lstrlen(CurrentDrive))]); end; finally FreeMem(FoundDrives, Len); end; end; end; |
Wie kann man Datenträgerveränderungen (DVD in DVD-Laufwerk, externe Festplatte wird angemacht usw.) registrieren ? Ich fand bisher die Funktionen FindFirstChangeNotification/FindNextChangeNotification und ReadDirectoryChangesW. Da steht so schön dabei, sie würden das System extrem verlangsamen. Change Journals kann man vergessen, da die dazu gehörenden Funktionen alle nur bei NTFS funktionieren. Muss ich FindFirstChangeNotification und FindNextChangeNotification benutzen ? Ich weiß nicht, wie ich den Funktionen überhaupt den Mount-Ordner bzw. Arbeitsplatz übergeben soll. Bei Linux wäre das ganz einfach /mnt, aber bei Windows weiß ich es nicht.
|
|
baka0815
      
Beiträge: 489
Erhaltene Danke: 14
Win 10, Win 8, Debian GNU/Linux
Delphi 10.1 Berlin, Java, C#
|
Verfasst: Mi 25.06.08 14:31
Für das Erkennen, ob eine DVD eingelegt oder ein USB-Stick angeschlossen wurde, wirst du vermutlich einen Hook auf eine WinAPI Funktion benötigen.
|
|
Webo
      
Beiträge: 577
Erhaltene Danke: 14
Win 7, Debian
C# (Visual Studio 2013), PHP, C, C++ (Eclipse, KDevelop)
|
Verfasst: Mi 25.06.08 14:35
Hier poste ich dir nun die Lösung zum erkennen eines CD/DVD-Wechsels :
(nicht meine Arbeit, habe sie mal früher von einem Freund zugeschickt bekommen !)
Wenn eine CD ins Laufwerk einlegt oder eine CD herausgenommen wird, wird die Botschaft WM_DeviceChange an alle Anwendungen geschickt.
Über den Parameter WParam kann bestimmt werden welche Aktion durchgeführt wurde. Die Botschaft wird nur verschickt, wenn die 'Automatische Benachrichtigung bei Wechsel' aktiv ist.
In dem Botschaftsrecord sind weitere Informationen zum Datenträger-Wechsel enthalten. So lässt sich über die Variable "lpdbv.dbcv_unitmask" ermitteln, auf welches Laufwerk sich der Wechsel bezieht.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79:
| private procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
function GetFirstDrive(UnitMask: DWORD): Char; var I: Char; begin Result:=#0; for I:='A' to 'Z' do begin if (UnitMask and 1) = 1 then begin Result:=I; break; end; UnitMask:=UnitMask Shr 1; end; end;
procedure TForm1.WMDeviceChange(var Msg: TMessage); var lpdb: PDevBroadcastHdr; lpdbv: PDevBroadcastVolume; begin lpdb:=PDevBroadcastHdr(Msg.lParam); case Msg.wParam of DBT_DeviceArrival: if lpdb^.dbch_devicetype = DBT_DevTyp_Volume then begin lpdbv:=PDevBroadcastVolume(Msg.lParam); if lpdbv.dbcv_flags = DBTF_Media then Label1.Caption:=Format('Datenträger in Laufwerk %s eingelegt.', [GetFirstDrive(lpdbv.dbcv_unitmask)]); end; DBT_DeviceRemoveComplete: if lpdb^.dbch_devicetype = DBT_DevTyp_Volume then begin lpdbv:=PDevBroadcastVolume(Msg.lParam); if lpdbv.dbcv_flags = DBTF_Media then Label1.Caption:=Format('Datenträger aus Laufwerk %s entfernt.', [GetFirstDrive(lpdbv.dbcv_unitmask)]); end;
end; end;
const DBT_DEVICEARRIVAL = $8000; const DBT_DEVICEREMOVECOMPLETE = $8004; const DBTF_MEDIA = $0001; const DBT_DEVTYP_VOLUME = $0002;
type PDevBroadcastHdr = ^TDevBroadcastHdr; {$EXTERNALSYM DEV_BROADCAST_HDR} DEV_BROADCAST_HDR = packed record dbch_size: DWORD; dbch_devicetype: DWORD; dbch_reserved: DWORD; end; TDevBroadcastHdr = DEV_BROADCAST_HDR;
PDevBroadcastVolume = ^TDevBroadcastVolume; {$EXTERNALSYM DEV_BROADCAST_VOLUME} DEV_BROADCAST_VOLUME = packed record dbcv_size: DWORD; dbcv_devicetype: DWORD; dbcv_reserved: DWORD; dbcv_unitmask: DWORD; dbcv_flags: Word; end;
TDevBroadcastVolume = DEV_BROADCAST_VOLUME; |
Die Dokumentation der Botschaft findest du in der PSDK unter dem Stichwort "WM_DEVICECHANGE". Der oben stehende Quelltext basiert auf dem Beispiel, welches in der MSDN zu finden ist: msdn.microsoft.com/l...p?url=/library/en-us /devio/base/detecting_media_insertion_or_removal.asp
--- Moderiert von Narses: Beiträge zusammengefasst---
Wo ich grade schon dabei bin Quellcode zu posten (Wieder nicht von mir, aber dafür gut)
Hier eine leichte kleine Funktion, mit der man die Laufwerke (Festpaltten, optische Laufwerke usw.) auslesen kann. Die Funktion gibt die Buchstaben des Laufwerks + den Typ (Festplatte etc) aus.
Benutz ich sehr häufig.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure GetDrives(const AItems: TStrings); const DriveTypeTexts: array[DRIVE_UNKNOWN..DRIVE_RAMDISK] of String = ('Unbekannt', 'Kein Wurzelverzeichnis', 'Diskette', 'Festplatte', 'Netzlaufwerk', 'CDROM', 'RAMDisk'); var Drive: Char; DriveType: Integer; DriveMask: Integer; Flag: Integer; begin DriveMask:=GetLogicalDrives; flag:=1; for Drive := 'A' to 'Z' do begin if (flag and DriveMask)<>0 then begin DriveType := GetDriveType(PChar(Format('%S:\',[Drive]) ) ) ; AItems.Add(Format('%s: %s', [Drive, DriveTypeTexts[DriveType]])); end; flag:=flag shl 1; end; end; |
Die Funktion GetLogicalDrives gibt ein Bitmuster zurück, welches die verfügbaren Lauwerke angibt. Ist ein Bit auf 1 gesetzt, ist das Laufwerk vorhanden und kann erkannt werden.
Es wird zwischen Festplatten, Wechsellaufwerken, CD-ROM/DVD-Laufwerken, Netzlaufwerken und RamDisks unterschieden. Ein Beispielaufruf sieht so aus:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TForm1.Button2Click(Sender: TObject); begin GetDrives(Listbox1.Items) end; |
Hoffe ich konnte die hiermit helfen.
|
|
Nils:D 
      
Beiträge: 131
Debian, Win XP
Delphi 7 Arch.
|
Verfasst: Mi 25.06.08 19:07
Tut mir leid, dass ich mich erst jetzt wieder melde, aber ich habe eben fieberhaft den ganzen Tag am Projekt gearbeitet und da kam eben einiges noch regelrecht dazwischen. Habe aber vorhin schon geschaut und zu der Registrierung von ein- oder rausnehmen einer CD/DVD eine Frage: Das läuft nicht zwangsweise bei jedem Windows, da man die Einstellung wirklich erst aktivieren muss ? Das wäre natürlich nicht so gut, denn wenn mein Programm sich von der Registry vernhält, ist das wesentlich schöner. (Es gibt Registryschutzprogramme welche sofort Alarm melden, sobald nur irgendein Eintrag geändert werden soll. Ich programmiere selbstverständlich keinen Virus und ich kann davon ausgehen, dass der Benutzer die Änderung - solange ausführlich gesagt wird wozu diese dient - auch akzeptiert wird, aber schön ist so etas wirklich nicht, zumal man nicht überall so einfach an die Registry rankommt wegen fehlenden Benutzerrechten.) Gibt es da noch eine bessere Lösung ? Der zweite Beitrag war sehr hilfreich und ich habe ihn mit meinem alten Code so kombiniert, dass es noch ein Stück weit schneller wurde. Wie steht es eigentlich mit der Registration von "USB-Veränderungen" ? Wenn ich meine externe Platte - welche über USB läuft - anschalte, sollte mir das mein Programm melden.
|
|
Webo
      
Beiträge: 577
Erhaltene Danke: 14
Win 7, Debian
C# (Visual Studio 2013), PHP, C, C++ (Eclipse, KDevelop)
|
Verfasst: Do 26.06.08 11:07
Schön, dass dir der zweite Post geholfen hatt. Bin grad leider im Kofferpackstress und komme voraussichtlich frühestens heute Abend dazu, deine Fragen genau zu beantworten/dir weiter zu helfen.
Bis dann
Grüße
Webeo
|
|
|