|
Antwort |
Registriert seit: 15. Nov 2003 Ort: Berlin 947 Beiträge Delphi 10.2 Tokyo Professional |
#1
Hallo,
hier ein kleines Beispiel für die Verwendung von IOCTL_STORAGE_GET_DEVICE_NUMBER, IOCTL_DISK_GET_DRIVE_GEOMETRY und IOCTL_DISK_GET_DRIVE_LAYOUT. Damit es läuft braucht man die jwaWinIOCTL bzw. die entsprechenden Deklaration(en). Kernstück ist die Unit uDevice:
Delphi-Quellcode:
Und das Formular:
unit uDevice;
interface uses Classes, Windows, jwaWindows; type TDeviceRec = record DeviceNr : DWORD; DeviceStr : String; DriveStr : String; PartitionStr : String; PartitionNr : DWORD; DeviceTyp : DEVICE_TYPE; DiskGeometry : DISK_GEOMETRY; PartitionData : PARTITION_INFORMATION; end; TDynDeviceRec = record DeviceNr : DWORD; DeviceStr : String; DiskGeometry : DISK_GEOMETRY; PartitionData : Array of PARTITION_INFORMATION; MediaTypeStr : String; end; TDeviceRecList = Array of TDeviceRec; TDynDeviceRecList = Array of TDynDeviceRec; function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean; function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean; implementation uses SysUtils; function MediaTypeToStr(aMediaType : MEDIA_TYPE) : String; begin case aMediatype of Unknown : Result := 'UNKNOWN'; F5_1Pt2_512 : Result := '5.25" floppy, with 1.2MB and 512 bytes/sector'; F3_1Pt44_512 : Result := '3.5" floppy, with 1.44MB and 512 bytes/sector'; F3_2Pt88_512 : Result := '3.5" floppy, with 2.88MB and 512 bytes/sector'; F3_20Pt8_512 : Result := '3.5" floppy, with 20MB and 512 bytes/sector'; F3_720_512 : Result := '3.5" floppy, with 720KB and 512 bytes/sector'; F5_360_512 : Result := '5.25" floppy, with 360KB and 512 bytes/sector'; F5_320_512 : Result := '5.25" floppy, with 320KB and 512 bytes/sector'; F5_320_1024 : Result := '5.25" floppy, with 360KB and 1024 bytes/sector'; F5_180_512 : Result := '5.25" floppy, with 180KB and 512 bytes/sector'; F5_160_512 : Result := '5.25" floppy, with 160KB and 512 bytes/sector'; RemovableMedia : Result := 'Removable media other than floppy'; FixedMedia : Result := 'Fixed hard disk media'; F3_120M_512 : Result := '3.5" floppy, with 120MB and 512 bytes/sector'; F3_640_512 : Result := '3.5" floppy, with 640MB and 512 bytes/sector'; F5_640_512 : Result := '5.25" floppy, with 640KB and 512 bytes/sector'; F5_720_512 : Result := '5.25" floppy, with 720KB and 512 bytes/sector'; F3_1Pt2_512 : Result := '3.5" floppy, with 1.2MB and 512 bytes/sector'; F3_1Pt23_1024 : Result := '3.5" floppy, with 1.23MB and 1024 bytes/sector'; F5_1Pt23_1024 : Result := '5.25" floppy, with 1.23KB and 1024 bytes/sector'; F3_128Mb_512 : Result := '3.5" floppy, with 128MB and 512 bytes/sector'; F3_230Mb_512 : Result := '3.5" floppy, with 230MB and 512 bytes/sector'; F8_256_128 : Result := '8" floppy, with 256KB and 128 bytes/sector'; F3_200Mb_512 : Result := '3.5" floppy, with 200MB and 512 bytes/sector. (HiFD)'; F3_240M_512 : Result := '3.5" floppy, with 240MB and 512 bytes/sector. (HiFD)'; F3_32M_512 : Result := '3.5" floppy, with 32MB and 512 bytes/sector'; end; end; function DeviceTypeToStr(aDeviceType : DEVICE_TYPE):String; begin case aDeviceType of FILE_DEVICE_BEEP : Result :='BEEP'; FILE_DEVICE_CD_ROM : Result :='CD-ROM'; FILE_DEVICE_CD_ROM_FILE_SYSTEM : Result :='CD-ROM FILE-SYSTEM'; FILE_DEVICE_CONTROLLER : Result :='CONTROLLER'; FILE_DEVICE_DATALINK : Result :='DATALINK'; FILE_DEVICE_DFS : Result :='DFS'; FILE_DEVICE_DISK : Result :='DISK'; FILE_DEVICE_DISK_FILE_SYSTEM : Result :='DISK FILE-SYSTEM'; FILE_DEVICE_FILE_SYSTEM : Result :='FILE-SYSTEM'; FILE_DEVICE_INPORT_PORT : Result :='INPORT-PORT'; FILE_DEVICE_KEYBOARD : Result :='KEYBOARD'; FILE_DEVICE_MAILSLOT : Result :='MAILSLOT'; FILE_DEVICE_MIDI_IN : Result :='MIDI_IN'; FILE_DEVICE_MIDI_OUT : Result :='MIDI_OUT'; FILE_DEVICE_MOUSE : Result :='MOUSE'; FILE_DEVICE_MULTI_UNC_PROVIDER : Result :='MULTI UNC-PROVIDER'; FILE_DEVICE_NAMED_PIPE : Result :='NAMED-PIPE'; FILE_DEVICE_NETWORK : Result :='NETWORK'; FILE_DEVICE_NETWORK_BROWSER : Result :='NETWORK-BROWSER'; FILE_DEVICE_NETWORK_FILE_SYSTEM : Result :='NETWORK FILE-SYSTEM'; FILE_DEVICE_NULL : Result :='NULL'; FILE_DEVICE_PARALLEL_PORT : Result :='PARALLEL-PORT'; FILE_DEVICE_PHYSICAL_NETCARD : Result :='PHYSICAL-NETCARD'; FILE_DEVICE_PRINTER : Result :='PRINTER'; FILE_DEVICE_SCANNER : Result :='SCANNER'; FILE_DEVICE_SERIAL_MOUSE_PORT : Result :='SERIAL MOUSE-PORT'; FILE_DEVICE_SERIAL_PORT : Result :='SERIAL-PORT'; FILE_DEVICE_SCREEN : Result :='SCREEN'; FILE_DEVICE_SOUND : Result :='SOUND'; FILE_DEVICE_STREAMS : Result :='STREAMS'; FILE_DEVICE_TAPE : Result :='TAPE'; FILE_DEVICE_TAPE_FILE_SYSTEM : Result :='TAPE FILE-SYSTEM'; FILE_DEVICE_TRANSPORT : Result :='TRANSPORT'; FILE_DEVICE_UNKNOWN : Result :='UNKNOWN'; FILE_DEVICE_VIDEO : Result :='VIDEO'; FILE_DEVICE_VIRTUAL_DISK : Result :='VIRTUAL-DISK'; FILE_DEVICE_WAVE_IN : Result :='WAVE_IN'; FILE_DEVICE_WAVE_OUT : Result :='WAVE_OUT'; FILE_DEVICE_8042_PORT : Result :='8042-PORT'; FILE_DEVICE_NETWORK_REDIRECTOR : Result :='NETWORK-REDIRECTOR'; FILE_DEVICE_BATTERY : Result :='BATTERY'; FILE_DEVICE_BUS_EXTENDER : Result :='BZS EXTENDER'; FILE_DEVICE_MODEM : Result :='MODEM'; FILE_DEVICE_VDM : Result :='VDM'; FILE_DEVICE_MASS_STORAGE : Result :='MASS-STORAGE'; FILE_DEVICE_SMB : Result :='SMB'; FILE_DEVICE_KS : Result :='KS'; FILE_DEVICE_CHANGER : Result :='CHANGER'; FILE_DEVICE_SMARTCARD : Result :='SMARTCARD'; FILE_DEVICE_ACPI : Result :='ACPI'; FILE_DEVICE_DVD : Result :='DVD'; FILE_DEVICE_FULLSCREEN_VIDEO : Result :='FULLSCREEN VIDEO'; FILE_DEVICE_DFS_FILE_SYSTEM : Result :='DFS FILE-SYSTEM'; FILE_DEVICE_DFS_VOLUME : Result :='DFS-VOLUME'; FILE_DEVICE_SERENUM : Result :='SERENUM'; FILE_DEVICE_TERMSRV : Result :='TERMINAL-SERVER'; FILE_DEVICE_KSEC : Result :='KSEC'; FILE_DEVICE_FIPS : Result :='FIPS'; FILE_DEVICE_INFINIBAND : Result :='INFINIBAND'; else Result := IntToStr(aDeviceType); end; end; function DeviceExists(aDeviceNumber : DWORD) : Boolean; var hVolume : THandle; begin hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); CloseHandle(hVolume); Result := hVolume <> INVALID_HANDLE_VALUE; end; function GetDeviceNumber(const aDriveLetter : PChar; var aDeviceRec : TDeviceRec) : Boolean; overload; var pVolume : PChar; dwSize : DWORD; hVolume : THandle; SDN : STORAGE_DEVICE_NUMBER; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; Ret, dliSize : Integer; begin Ret := -1; dwSize := 6; pVolume := StrAlloc(dwSize); try StrPCopy(pVolume, Format('\\.\%s:', [Copy(aDriveLetter, 1, 1)])); hVolume := CreateFile(pVolume, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hVolume <> INVALID_HANDLE_VALUE then begin if DeviceIOControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @SDN, SizeOf(SDN), @lpBytesReturned, nil) then begin Ret := SDN.DeviceNumber; with aDeviceRec do begin DeviceNr := Ret; PartitionNr := SDN.PartitionNumber; DeviceTyp := SDN.DeviceType; DriveStr := Format('%s:\', [aDriveLetter]); case SDN.DeviceType of FILE_DEVICE_DISK : DeviceStr := Format('\\.\PHYSICALDRIVE%d', [DeviceNr]); else DeviceStr := Format('DEVICE: %s ', [DeviceTypeToStr(DeviceTyp)]); end; PartitionStr := Format('Partition%d', [PartitionNr]); end; end; if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @DG, SizeOf(DG), @lpBytesReturned, nil) then aDeviceRec.DiskGeometry := DG; // Für den folgenden Aufruf müssen wir ausreichend Speicher reserviren // Falls ich ein Fragt warum 16 Partitionen, sollte sich gesondert informieren;-) dliSize := SizeOf(DRIVE_LAYOUT_INFORMATION) + (15 * SizeOf(PARTITION_INFORMATION)); // Wir nutzen GetMem da DRIVE_LAYOUT_INFORMATION.PartitionCount ein // statisches Array ist GetMem(pDLI, dliSize); if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_LAYOUT, nil, 0, pDLI, dliSize, @lpBytesReturned, nil) then begin // Hier verkürzen wir das ganze, da wir ja wissen welche Partition // wir auslesen wollen aDeviceRec.PartitionData := pDLI^.PartitionEntry[aDeviceRec.PartitionNr-1]; // Und geben den Speicher wieder frei FreeMem(pDLI, dliSize); end; CloseHandle(hVolume); end; finally StrDispose(pVolume); end; Result := Ret > -1; end; function GetDeviceNumber(const aPhysicalDrive : Byte; var aDynDeviceRec : TDynDeviceRec) : Boolean; overload; var pVolume : PChar; dwSize : DWORD; hVolume : THandle; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; I, piCount, dliSize : Integer; begin Result := false; dwSize := Length(Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])) + 1; pVolume := StrAlloc(dwSize); try StrPCopy(pVolume, Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])); hVolume := CreateFile(pVolume, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hVolume <> INVALID_HANDLE_VALUE then begin aDynDeviceRec.DeviceNr := aPhysicalDrive; aDynDeviceRec.DeviceStr:= pVolume; if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @DG, SizeOf(DG), @lpBytesReturned, nil) then begin aDynDeviceRec.DiskGeometry := DG; aDynDeviceRec.MediaTypeStr := MediaTypeToStr(DG.MediaType); end; // Für den folgenden Aufruf müssen wir ausreichend Speicher reserviren // Falls sich ein Fragt warum 16 Partitionen, sollte er sich // gesondert informieren;-) dliSize := SizeOf(DRIVE_LAYOUT_INFORMATION) + (15 * SizeOf(PARTITION_INFORMATION)); // Wir nutzen GetMem da DRIVE_LAYOUT_INFORMATION.PartitionCount ein // statisches Array ist GetMem(pDLI, dliSize); if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_LAYOUT, nil, 0, pDLI, dliSize, @lpBytesReturned, nil) then begin // IOCTL_DISK_GET_DRIVE_LAYOUT bringt in // DRIVE_LAYOUT_INFORMATION.PartitionCount immer 4 zurück // egal ob 1, 2 oder mehr Primärepartitionen vorhanden sind. piCount := 0; for I := 0 to pDLI^.PartitionCount - 1 do begin if pDLI^.PartitionEntry[I].StartingOffset.LowPart = 0 then Break; Inc(piCount); end; SetLength(aDynDeviceRec.PartitionData, piCount); for I := 0 to piCount-1 do aDynDeviceRec.PartitionData[I] := pDLI^.PartitionEntry[I]; // Speicher wieder freigeben FreeMem(pDLI, dliSize); end; CloseHandle(hVolume); Result := true; end; finally StrDispose(pVolume); end; end; function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean; var drives : DWORD; letter : Char; SL : TStringList; begin SL := TStringList.Create; try for letter := 'C' to 'Z' do case GetDriveType(PChar(letter + ':\')) of DRIVE_REMOVABLE : SL.Add(letter); DRIVE_FIXED : SL.Add(Letter); end; Result := SL.Count > 0; if Result then begin SetLength(aDeviceRecList, SL.Count); for drives := 0 to SL.Count - 1 do GetDeviceNumber(PChar(SL.Strings[drives]), aDeviceRecList[drives]); end; finally SL.Free; end; end; function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean; var I : Byte; J : Byte; C : Byte; DR : TDynDeviceRec; begin C := 0; SetLength(aDynDeviceRecList, HIGH(Byte)); for I := 0 to HIGH(BYTE) do begin if DeviceExists(I) then begin if GetDeviceNumber(I, DR) then begin try with aDynDeviceRecList[C] do begin DeviceNr := DR.DeviceNr; DeviceStr := DR.DeviceStr; DiskGeometry := DR.DiskGeometry; MediaTypeStr := DR.MediaTypeStr; SetLength(PartitionData, Length(DR.PartitionData)); for J := 0 to Length(DR.PartitionData) - 1 do PartitionData[J] := DR.PartitionData[J]; end; Inc(C); except end; end; end; end; SetLength(aDynDeviceRecList, C); Result := Length(aDynDeviceRecList) > 0; end; end.
Delphi-Quellcode:
Siehe auch Anhang. Ich gebe ja zu ein wenig Optimierung könnte das ganze vertragen
unit frmMain;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ActnList, Menus, ComCtrls, uDevice; type TMainForm = class(TForm) ActionList1: TActionList; MainMenu1: TMainMenu; mnuFile: TMenuItem; mnuDevice: TMenuItem; _aDummy: TAction; aFileExit: TAction; aDeviceLogical: TAction; aDevicePhysical: TAction; mnuFileExit: TMenuItem; mnuDeviceLogical: TMenuItem; N1: TMenuItem; mnuDevicePhysical: TMenuItem; tvDevices: TTreeView; procedure aFileExitExecute(Sender: TObject); procedure aDeviceLogicalExecute(Sender: TObject); procedure aDevicePhysicalExecute(Sender: TObject); private { Private-Deklarationen } DRL : TDeviceRecList; DDRL: TDynDeviceRecList; function FindRootNode(aName : String; aTreeView : TTreeView) : TTreeNode; procedure ClearList; public { Public-Deklarationen } end; var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm.aDeviceLogicalExecute(Sender: TObject); var I : Integer; R : TTreeNode; begin tvDevices.Items.BeginUpdate; tvDevices.Items.Clear; ClearList; if GetAllLogicalDevices(DRL) then begin for I := 0 to Length(DRL) -1 do begin R := FindRootNode(DRL[I].DeviceStr, tvDevices); if R <> nil then tvDevices.Items.AddChild(R, Format('%s (%s)', [DRL[I].PartitionStr, DRL[I].DriveStr])) else begin R := tvDevices.Items.AddChild(nil, DRL[I].DeviceStr); tvDevices.Items.AddChild(R, Format('%s (%s)', [DRL[I].PartitionStr, DRL[I].DriveStr])); end; end; tvDevices.Items.AlphaSort(); end; tvDevices.Items.EndUpdate; end; procedure TMainForm.aDevicePhysicalExecute(Sender: TObject); var I, J : Integer; N, R : TTreeNode; begin tvDevices.Items.BeginUpdate; tvDevices.Items.Clear; ClearList; if GetAllPhysicalDevices(DDRL) then begin for I := 0 to Length(DDRL) -1 do begin R := FindRootNode(DDRL[I].DeviceStr, tvDevices); if R <> nil then tvDevices.Items.AddChild(R, Format('%s ', [DDRL[I].MediaTypeStr])) else begin R := tvDevices.Items.AddChild(nil, DDRL[I].DeviceStr); N := tvDevices.Items.AddChild(R, Format('%s ', [DDRL[I].MediaTypeStr])); for J := 0 to Length(DDRL[I].PartitionData) -1 do tvDevices.Items.AddChild(N, Format('Partition%d', [J])); end; end; tvDevices.Items.AlphaSort(); end; tvDevices.Items.EndUpdate; end; procedure TMainForm.aFileExitExecute(Sender: TObject); begin ClearList; Close; end; function TMainForm.FindRootNode(aName : String; aTreeView : TTreeView) : TTreeNode; var I : Integer; begin Result := nil; aTreeView.Items.BeginUpdate; for I := 0 to aTreeView.Items.Count - 1 do if aTreeView.Items[I].Text = aName then begin Result := aTreeView.Items[I]; Break; end; aTreeView.Items.EndUpdate; end; procedure TMainForm.ClearList; var I : Integer; begin if Length(DDRL) > 0 then begin for I := Length(DDRL) -1 downto 0 do if Length(DDRL[I].PartitionData) > 0 then SetLength(DDRL[I].PartitionData, 0); SetLength(DDRL, 0); end; if Length(DRL) > 0 then SetLength(DRL, 0); end; end. Falls es Fragen gibt, fragen. Viele Grüße Geändert von Alter Mann ( 8. Sep 2010 um 11:20 Uhr) |
Zitat |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.184 Beiträge Delphi 12 Athens |
#2
Delphi-Quellcode:
Wozu setzt du den Namen/PChar doppelt?
var
pVolume : PWideChar; hVolume : THandle; begin Result := false; hVolume := INVALID_HANDLE_VALUE; pVolume := StrAlloc(Length('\\.\PHYSICALDRIVE' + IntToStr(aDeviceNumber))); try StrPCopy(pVolume, Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])); try hVolume := CreateFile(pVolume, ...); ... finally if Result then CloseHandle(hVolume); end; finally StrDispose(pVolume); end; Einmal über StrAlloc und dann nochmal über StrPCopy. Warum einmal über Format und dann über IntToStr? (ein bissl Einheitlichkeit kann nie schaden) Meckert Delphi denn nicht beim ersten Result? (ungenutzer Wert) Sicher daß dieser PChar-PWideChar-Mix in Delphi 7 funktioniert? (ich glaub eher nicht, abgesehn davon daß Delphi 7 da meckern sollte, da PAnsiChar nicht kompatiebel PWideChar) z.B.: (über solche Unicode-Fehler quassel ich mir schon seit Jahren den Mund fusselig und wegen sowas mecken dann viele, weil bei ihnen Codes nicht under Pre-D2009 und D2009+ kompatibel sind, bzw. warum sie dann "urplötzlich" nicht in dem Anderem funktionieren) CreateFileA + PAnsiChar CreateFileW + PWideChar CreateFile + PChar > du nimmst aber CreateFile + PWideChar Succeeded und das Result von CreateFile passen nicht zusammen. > Succeeded = HRESULT und CreateFile = HANDLE > INVALID_HANDLE_VALUE = $FFFFFFFF (alle Bits) und Succeeded-Error = $8xxxxxxx (nur das höchste Bit) Anstatt alle Laufwerksbuchstaben durchzuprobieren wäre es schöner, wenn man einfach mal anfragt, was es gibt > GetLogicalDriveStrings oder GetLogicalDrives. den oberen Code würde ich wie Folgt abändern:
Delphi-Quellcode:
DeviceExists kann man über GetLogicalDrives einfacher/besser erkennen.
var
hVolume : THandle; begin hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])), ...); if hVolume <> INVALID_HANDLE_VALUE then try ... finally CloseHandle(hVolume); end; Dein DeviceExists ist eher ein DeviceAccessAllowed. Da es nur True liefert, wenn das Laufwerk existiert und man darauf zugreifen darf. PS: Was du vergessen hast zu sagen, daß CreateFile nur mit Adminrechten Zugriff auf Festplatten bekommt, bzw. genauer gesagt, benötigt man mindestens Backup-Rechte. (Das ist schon seit WinNT so, auch wenn "leider" bis WinXP meistens alle rogramme automatisch admin-Rechte besaßen.) Mit ein bissl Kenntnis über das Fehler-/Excaption-Management dieser WinAPIs kann man die erste Funktion auf dieses kürzen, nachdem die Fehler (voallem das Succeeded) behoben wurden.
Delphi-Quellcode:
function {DeviceExists}DeviceAccessAllowed(aDeviceNumber: DWORD): Boolean;
var hVolume : THandle; begin hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); CloseHandle(hVolume); Result := hVolume <> INVALID_HANDLE_VALUE; end;
$2B or not $2B
Geändert von himitsu ( 7. Sep 2010 um 14:24 Uhr) |
Zitat |
Registriert seit: 15. Nov 2003 Ort: Berlin 947 Beiträge Delphi 10.2 Tokyo Professional |
#3
@himitsu
Danke für die Kommentare, kann nie schaden. Das keine Unterscheidung zwischen ANSI und PWideChar gemacht wird liegt wohl daran, dass entsprechend der Delphi-Version der Compiler die 'richtige' Funktion aufruft. Im diesem Fall ist Delphi 2009. Das ich mir bei PWideChar ein StrAlloc sparen kann, wenn ich StrPCopy aufrufe war mir neu, ist aber jetzt gemerkt. Genauso die Sache mit dem INVALID_HANDLE_VALUE.
Zitat:
Meckert Delphi denn nicht beim ersten Result?
Danke PS Werde noch ein paar kleine Korrekturen einarbeiten, sobald der Virenscanner fertig ist. Geändert von Alter Mann ( 7. Sep 2010 um 16:39 Uhr) |
Zitat |
Registriert seit: 2. Mär 2004 5.508 Beiträge Delphi 5 Professional |
#4
Da ja die Sache mit dem PhysicalDriveName mehr als einmal auftaucht, bietet es sich an,
ein kleine, lokale Funktion zu verwenden:
Delphi-Quellcode:
Als Profis wollen wir doch das Don't Repeat Yourself - Prinzip beachten.
function GetPhysicalDriveName(aDeviceNumber:integer):string;
begin result := Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber]); end;
Andreas
|
Zitat |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.184 Beiträge Delphi 12 Athens |
#5
Das keine Unterscheidung zwischen ANSI und PWideChar gemacht wird liegt
wohl daran, dass entsprechend der Delphi-Version der Compiler die 'richtige' Funktion aufruft. Im diesem Fall ist Delphi 2009. Dennoch nutze bitte die jeweiligen APIs, welche zu den P...Chars passen. Vorallem wenn du hier Codes für andere veröffentlichst, könnten bestimmt viele mit einem älteren Ansi-Delphi diesen Code nutzen und dann knallt's. Das ich mir bei PWideChar ein StrAlloc sparen kann, wenn ich StrPCopy aufrufe war mir neu, ist aber jetzt gemerkt.
StrAlloc reserviert Speicher und kopiert den übergebenen Text in diesen Speicher. StrPCopy kopiert Text in den angegebenen Speicher/PChar. Entweder man reserviert anders Speicher und kopiert dann via StrPCopy oder man nutzt nur StrAlloc (das StrPCopy wäre hier doppelt kopiert). Genauso die Sache mit dem INVALID_HANDLE_VALUE.
Zitat:
Meckert Delphi denn nicht beim ersten Result?
Danke PS Werde noch ein paar kleine Korrekturen einarbeiten, sobald der Virenscanner fertig ist.[/QUOTE]
$2B or not $2B
|
Zitat |
Registriert seit: 15. Nov 2003 Ort: Berlin 947 Beiträge Delphi 10.2 Tokyo Professional |
#6
Hi,
ich habe es nun soweit angepasst das unter D7 genauso wie unter D2009 läuft. Interessant für mich dabei war, die Sache mit dem PChar. Was ich allerdings noch nicht so richtig verstanden habe ist die Geschichte mit StrAlloc und StrPCopy. Ich gebe es ja zu meine Assembler-Kenntnisse sind gleich 0. So kann jedoch nicht erkennen wo Move den Speicher für Dest alloziert, aber das kann bestimmt mir einer Erklären, gern auch als PN. Die Änderungen sind im ersten Posting eingearbeitet. |
Zitat |
Registriert seit: 7. Sep 2006 Ort: Berlin 441 Beiträge Delphi 12 Athens |
#7
Mit Delphi 2007 erhalte ich 14 Fehler, die allesamt so lauten:
uDevice.pas (244): E2010 Inkompatible Typen: WideChar und Char Es variieren natürlich die Zeilennummern.
Devid
Devid Espenschied Pre-sales Consultant Embarcadero Germany GmbH germany.info@embarcadero.com Kein Support per PN |
Zitat |
DevidEspenschied |
Öffentliches Profil ansehen |
Mehr Beiträge von DevidEspenschied finden |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.184 Beiträge Delphi 12 Athens |
#8
Mit Delphi 2007 erhalte ich 14 Fehler, die allesamt so lauten:...
siehe Dennoch nutze bitte die jeweiligen APIs, welche zu den P...Chars passen.
Vorallem wenn du hier Codes für andere veröffentlichst, könnten bestimmt viele mit einem älteren Ansi-Delphi diesen Code nutzen und dann knallt's. Sicher daß dieser PChar-PWideChar-Mix in Delphi 7 funktioniert?
(ich glaub eher nicht, abgesehn davon daß Delphi 7 da meckern sollte, da PAnsiChar nicht kompatiebel PWideChar) z.B.: (über solche Unicode-Fehler quassel ich mir schon seit Jahren den Mund fusselig und wegen sowas mecken dann viele, weil bei ihnen Codes nicht under Pre-D2009 und D2009+ kompatibel sind, bzw. warum sie dann "urplötzlich" nicht in dem Anderem funktionieren) CreateFileA + PAnsiChar CreateFileW + PWideChar CreateFile + PChar > du nimmst aber CreateFile + PWideChar Wegen dem StrAlloc muß ich mich mal entschuldigen. StrAlloc reserviert nur den Speicher, StrPCopy kopiert dann den Text dort in den Speicher. Hatte irgendwie die Declaration von NewStr im Kopf. Nja, dann gibt es dennoch ein logistisches Problem. Du hattest mit einer Deklaration mit IntToStr den PChar-Speicher reserviert und hast dann eine "andere" Text-Deklaration mit Format dort reinkopiert. Also StrAlloc+StrPCopy könnte man mit NewStr zusammenfassen, aber man könnte auch alles lassen und castet den String einfach über PChar und überigbt dieses direkt an die Funktion. Hab hier nochmal schnell die Speicher und Fehlerbehandlung verändert: Sowas wie das leere Try-Except macht man einfach nicht, wobei es hier eh nicht nötig sein dürfte, es sei denn deine Array-Indize stimmen nicht und solche Fehler sollte man nie verschweigen.
Delphi-Quellcode:
PS: Diese festen dwSize waren nicht optimal, denn so würde man nur von 0 bis 9 zählen können, da die Länge wohl dafür ausgelegt war und was passiert dann, wenn man z.B. eine 10 für aPhysicalDrive übergibt? (ein Bufferoverrun)
unit uDevice;
interface uses Classes, Windows, jwaWindows; type TDeviceRec = record DeviceNr : DWORD; DeviceStr : String; DriveStr : String; PartitionStr : String; PartitionNr : DWORD; DeviceTyp : DEVICE_TYPE; DiskGeometry : DISK_GEOMETRY; PartitionData : PARTITION_INFORMATION; end; TDynDeviceRec = record DeviceNr : DWORD; DeviceStr : String; DiskGeometry : DISK_GEOMETRY; PartitionData : Array of PARTITION_INFORMATION; MediaTypeStr : String; end; TDeviceRecList = Array of TDeviceRec; TDynDeviceRecList = Array of TDynDeviceRec; function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean; function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean; implementation uses SysUtils; function MediaTypeToStr(aMediaType : MEDIA_TYPE) : String; begin case aMediatype of F5_1Pt2_512 : Result := '5.25" floppy, with 1.2MB and 512 bytes/sector'; F3_1Pt44_512 : Result := '3.5" floppy, with 1.44MB and 512 bytes/sector'; F3_2Pt88_512 : Result := '3.5" floppy, with 2.88MB and 512 bytes/sector'; F3_20Pt8_512 : Result := '3.5" floppy, with 20MB and 512 bytes/sector'; F3_720_512 : Result := '3.5" floppy, with 720KB and 512 bytes/sector'; F5_360_512 : Result := '5.25" floppy, with 360KB and 512 bytes/sector'; F5_320_512 : Result := '5.25" floppy, with 320KB and 512 bytes/sector'; F5_320_1024 : Result := '5.25" floppy, with 360KB and 1024 bytes/sector'; F5_180_512 : Result := '5.25" floppy, with 180KB and 512 bytes/sector'; F5_160_512 : Result := '5.25" floppy, with 160KB and 512 bytes/sector'; RemovableMedia : Result := 'Removable media other than floppy'; FixedMedia : Result := 'Fixed hard disk media'; F3_120M_512 : Result := '3.5" floppy, with 120MB and 512 bytes/sector'; F3_640_512 : Result := '3.5" floppy, with 640MB and 512 bytes/sector'; F5_640_512 : Result := '5.25" floppy, with 640KB and 512 bytes/sector'; F5_720_512 : Result := '5.25" floppy, with 720KB and 512 bytes/sector'; F3_1Pt2_512 : Result := '3.5" floppy, with 1.2MB and 512 bytes/sector'; F3_1Pt23_1024 : Result := '3.5" floppy, with 1.23MB and 1024 bytes/sector'; F5_1Pt23_1024 : Result := '5.25" floppy, with 1.23KB and 1024 bytes/sector'; F3_128Mb_512 : Result := '3.5" floppy, with 128MB and 512 bytes/sector'; F3_230Mb_512 : Result := '3.5" floppy, with 230MB and 512 bytes/sector'; F8_256_128 : Result := '8" floppy, with 256KB and 128 bytes/sector'; F3_200Mb_512 : Result := '3.5" floppy, with 200MB and 512 bytes/sector. (HiFD)'; F3_240M_512 : Result := '3.5" floppy, with 240MB and 512 bytes/sector. (HiFD)'; F3_32M_512 : Result := '3.5" floppy, with 32MB and 512 bytes/sector'; else Result := 'UNKNOWN'; // besser hier, falls mal was Unbekantes/Fehlerhaftes reinkommt end; end; function DeviceTypeToStr(aDeviceType : DEVICE_TYPE):String; begin case aDeviceType of FILE_DEVICE_BEEP : Result :='BEEP'; FILE_DEVICE_CD_ROM : Result :='CD-ROM'; FILE_DEVICE_CD_ROM_FILE_SYSTEM : Result :='CD-ROM FILE-SYSTEM'; FILE_DEVICE_CONTROLLER : Result :='CONTROLLER'; FILE_DEVICE_DATALINK : Result :='DATALINK'; FILE_DEVICE_DFS : Result :='DFS'; FILE_DEVICE_DISK : Result :='DISK'; FILE_DEVICE_DISK_FILE_SYSTEM : Result :='DISK FILE-SYSTEM'; FILE_DEVICE_FILE_SYSTEM : Result :='FILE-SYSTEM'; FILE_DEVICE_INPORT_PORT : Result :='INPORT-PORT'; FILE_DEVICE_KEYBOARD : Result :='KEYBOARD'; FILE_DEVICE_MAILSLOT : Result :='MAILSLOT'; FILE_DEVICE_MIDI_IN : Result :='MIDI_IN'; FILE_DEVICE_MIDI_OUT : Result :='MIDI_OUT'; FILE_DEVICE_MOUSE : Result :='MOUSE'; FILE_DEVICE_MULTI_UNC_PROVIDER : Result :='MULTI UNC-PROVIDER'; FILE_DEVICE_NAMED_PIPE : Result :='NAMED-PIPE'; FILE_DEVICE_NETWORK : Result :='NETWORK'; FILE_DEVICE_NETWORK_BROWSER : Result :='NETWORK-BROWSER'; FILE_DEVICE_NETWORK_FILE_SYSTEM : Result :='NETWORK FILE-SYSTEM'; FILE_DEVICE_NULL : Result :='NULL'; FILE_DEVICE_PARALLEL_PORT : Result :='PARALLEL-PORT'; FILE_DEVICE_PHYSICAL_NETCARD : Result :='PHYSICAL-NETCARD'; FILE_DEVICE_PRINTER : Result :='PRINTER'; FILE_DEVICE_SCANNER : Result :='SCANNER'; FILE_DEVICE_SERIAL_MOUSE_PORT : Result :='SERIAL MOUSE-PORT'; FILE_DEVICE_SERIAL_PORT : Result :='SERIAL-PORT'; FILE_DEVICE_SCREEN : Result :='SCREEN'; FILE_DEVICE_SOUND : Result :='SOUND'; FILE_DEVICE_STREAMS : Result :='STREAMS'; FILE_DEVICE_TAPE : Result :='TAPE'; FILE_DEVICE_TAPE_FILE_SYSTEM : Result :='TAPE FILE-SYSTEM'; FILE_DEVICE_TRANSPORT : Result :='TRANSPORT'; FILE_DEVICE_UNKNOWN : Result :='UNKNOWN'; FILE_DEVICE_VIDEO : Result :='VIDEO'; FILE_DEVICE_VIRTUAL_DISK : Result :='VIRTUAL-DISK'; FILE_DEVICE_WAVE_IN : Result :='WAVE_IN'; FILE_DEVICE_WAVE_OUT : Result :='WAVE_OUT'; FILE_DEVICE_8042_PORT : Result :='8042-PORT'; FILE_DEVICE_NETWORK_REDIRECTOR : Result :='NETWORK-REDIRECTOR'; FILE_DEVICE_BATTERY : Result :='BATTERY'; FILE_DEVICE_BUS_EXTENDER : Result :='BZS EXTENDER'; FILE_DEVICE_MODEM : Result :='MODEM'; FILE_DEVICE_VDM : Result :='VDM'; FILE_DEVICE_MASS_STORAGE : Result :='MASS-STORAGE'; FILE_DEVICE_SMB : Result :='SMB'; FILE_DEVICE_KS : Result :='KS'; FILE_DEVICE_CHANGER : Result :='CHANGER'; FILE_DEVICE_SMARTCARD : Result :='SMARTCARD'; FILE_DEVICE_ACPI : Result :='ACPI'; FILE_DEVICE_DVD : Result :='DVD'; FILE_DEVICE_FULLSCREEN_VIDEO : Result :='FULLSCREEN VIDEO'; FILE_DEVICE_DFS_FILE_SYSTEM : Result :='DFS FILE-SYSTEM'; FILE_DEVICE_DFS_VOLUME : Result :='DFS-VOLUME'; FILE_DEVICE_SERENUM : Result :='SERENUM'; FILE_DEVICE_TERMSRV : Result :='TERMINAL-SERVER'; FILE_DEVICE_KSEC : Result :='KSEC'; FILE_DEVICE_FIPS : Result :='FIPS'; FILE_DEVICE_INFINIBAND : Result :='INFINIBAND'; else Result := IntToStr(aDeviceType); end; end; function DeviceExists(aDeviceNumber : DWORD) : Boolean; var hVolume : THandle; begin hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); CloseHandle(hVolume); Result := hVolume <> INVALID_HANDLE_VALUE; end; function GetDeviceNumber(aDriveLetter : PChar; var aDeviceRec : TDeviceRec) : Boolean; overload; var hVolume : THandle; SDN : STORAGE_DEVICE_NUMBER; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; begin hVolume := CreateFile(PChar(Format('\\.\%s:', [aDriveLetter])), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); Result := hVolume <> INVALID_HANDLE_VALUE; if Result then try if DeviceIOControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @SDN, SizeOf(SDN), @lpBytesReturned, nil) then with aDeviceRec do begin DeviceNr := SDN.DeviceNumber; PartitionNr := SDN.PartitionNumber; DeviceTyp := SDN.DeviceType; DriveStr := Format('%s:\', [aDriveLetter]); case SDN.DeviceType of FILE_DEVICE_DISK : DeviceStr := Format('\\.\PHYSICALDRIVE%d', [DeviceNr]); else DeviceStr := Format('DEVICE: %s ', [DeviceTypeToStr(DeviceTyp)]); end; PartitionStr := Format('Partition%d', [PartitionNr]); // Wenn schon WITH, warum dann nicht auch DiskGeometry und PartitionData darüber setzen? :D // Wobei ich hier eigentlich lieber ganz auf WITH verzichten würde. if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @DG, SizeOf(DG), @lpBytesReturned, nil) then DiskGeometry := DG; GetMem(pDLI, SizeOf(DRIVE_LAYOUT_INFORMATION) + 15 * SizeOf(PARTITION_INFORMATION)); try if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_LAYOUT, nil, 0, pDLI, dliSize, @lpBytesReturned, nil) then PartitionData := pDLI^.PartitionEntry[aDeviceRec.PartitionNr-1]; finally FreeMem(pDLI); end; end; finally CloseHandle(hVolume); end; end; function GetDeviceNumber(aPhysicalDrive : Byte; var aDynDeviceRec : TDynDeviceRec) : Boolean; overload; var hVolume : THandle; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; I, piCount, begin Result := false; hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hVolume <> INVALID_HANDLE_VALUE then try aDynDeviceRec.DeviceNr := aPhysicalDrive; aDynDeviceRec.DeviceStr:= pVolume; if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, nil, 0, @DG, SizeOf(DG), @lpBytesReturned, nil) then begin aDynDeviceRec.DiskGeometry := DG; aDynDeviceRec.MediaTypeStr := MediaTypeToStr(DG.MediaType); end; GetMem(pDLI, SizeOf(DRIVE_LAYOUT_INFORMATION) + 15 * SizeOf(PARTITION_INFORMATION)); try if DeviceIOControl(hVolume, IOCTL_DISK_GET_DRIVE_LAYOUT, nil, 0, pDLI, dliSize, @lpBytesReturned, nil) then begin piCount := 0; for I := 0 to pDLI^.PartitionCount - 1 do begin if pDLI^.PartitionEntry[I].StartingOffset.LowPart = 0 then Break; Inc(piCount); end; SetLength(aDynDeviceRec.PartitionData, piCount); for I := 0 to piCount-1 do aDynDeviceRec.PartitionData[I] := pDLI^.PartitionEntry[I]; Result := true; end; finally FreeMem(pDLI, dliSize); end; finally CloseHandle(hVolume); end; end; function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean; var drives : DWORD; letter : Char; SL : TStringList; begin Result := false; SL := TStringList.Create; try for letter := 'C' to 'Z' do case GetDriveType(PChar(letter + ':\')) of DRIVE_REMOVABLE : SL.Add(letter); DRIVE_FIXED : SL.Add(Letter); end; Result := SL.Count > 0; if Result then begin SetLength(aDeviceRecList, SL.Count-1); for drives := 0 to SL.Count - 1 do GetDeviceNumber(PChar(SL.Strings[drives]), aDeviceRecList[drives]); end; finally SL.Free; end; end; function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean; var I, J, C : Byte; DR : TDynDeviceRec; begin C := 0; SetLength(aDynDeviceRecList, HIGH(Byte)); for I := 0 to HIGH(BYTE) do if DeviceExists(I) then begin if GetDeviceNumber(I, DR) then begin with aDynDeviceRecList[C] do // hier sollte wohl C hin und nicht I begin DeviceNr := DR.DeviceNr; DeviceStr := DR.DeviceStr; DiskGeometry := DR.DiskGeometry; MediaTypeStr := DR.MediaTypeStr; SetLength(PartitionData, Length(DR.PartitionData)); for J := 0 to Length(DR.PartitionData) - 1 do PartitionData[J] := DR.PartitionData[J]; end; Inc(C); end; end; // else Break; // nein, sobald was fehlt, heißt es nicht, daß nichts mehr kommt. // schließe mal zwei USB-Sicks o.Ä. an und entferne dann den zuerst angesteckten wieder. // die Drive-Numbers werden nicht neu vergeben und demnach würdest du dann den 2. Stick übersehn SetLength(aDynDeviceRecList, C); Result := Length(aDynDeviceRecList) > 0; end; end.
$2B or not $2B
Geändert von himitsu ( 7. Sep 2010 um 21:58 Uhr) |
Zitat |
Registriert seit: 15. Nov 2003 Ort: Berlin 947 Beiträge Delphi 10.2 Tokyo Professional |
#9
Okay,
ich werde es noch einmal überarbeiten, morgen dazu mehr. Erst einmal die zusätzlichen Fehler finden Bis dann |
Zitat |
Registriert seit: 15. Nov 2003 Ort: Berlin 947 Beiträge Delphi 10.2 Tokyo Professional |
#10
Moin, Moin
so die letzten Änderungen sind eingeflossen und im ersten Beitrag hinterlegt. Den geneigten Leser sei ans Herz gelegt nicht alles was hier bisher geschrieben wurde ist mit Substanz hinterlegt. So wurden Änderungen vorgeschlagen ohne sie selbst vorher zu prüfen (sprich durch den Compiler zu jagen) bzw. und das ist meine Schuld, der Code im Anhang benutzt zu haben ohne auf die Änderungen im abgebildeten Code einzugehen. Ein Vergleich der entsprechenden Fehler-Stellen hätte gereicht. Einige Sachen wurden mit Absicht nicht übernommen, so ist zum Beispiel:
Delphi-Quellcode:
drin geblieben, auch wenn himitsu anderer Meinung ist. Eine Verkürzung auf:
…
function GetDeviceNumber(const aPhysicalDrive : Byte; var aDynDeviceRec : TDynDeviceRec) : Boolean; overload; var pVolume : PChar; dwSize : DWORD; hVolume : THandle; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; I, piCount, dliSize : Integer; begin Result := false; dwSize := Length(Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])) + 1; pVolume := StrAlloc(dwSize); try StrPCopy(pVolume, Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])); hVolume := CreateFile(pVolume, …
Delphi-Quellcode:
brachte irgendwelche Pseudobezeichnungen und falsche Rückgabewerte.
…
function GetDeviceNumber(const aPhysicalDrive : Byte; var aDynDeviceRec : TDynDeviceRec) : Boolean; overload; var hVolume : THandle; DG : DISK_GEOMETRY; pDLI : PDRIVE_LAYOUT_INFORMATION; lpBytesReturned : DWORD; I, piCount, dliSize : Integer; begin Result := false; try hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive]), … Meinen Dank an allen die geholfen haben, dass das Beispiel unter D7 genauso läuft wie unter D2009. Alter Mann |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |