Thema: Delphi Festplatte ausschalten

Einzelnen Beitrag anzeigen

Daniel G
(Gast)

n/a Beiträge
 
#13

Re: Festplatte ausschalten

  Alt 13. Jul 2006, 20:59
So, um meinen Monolog jetzt zu komplettieren ()

Die Lösung

Man definiere folgende Typen (Dank' an Alex Konshin für seine Unit, die diese Definitionen schon beinhaltet)

Delphi-Quellcode:
Type
TIDERegs = packed record
    bFeaturesReg : Byte; // Used for specifying SMART "commands".
    bSectorCountReg : Byte; // IDE sector count register
    bSectorNumberReg : Byte; // IDE sector number register
    bCylLowReg : Byte; // IDE low order cylinder value
    bCylHighReg : Byte; // IDE high order cylinder value
    bDriveHeadReg : Byte; // IDE drive/head register
    bCommandReg : Byte; // Actual IDE command.
    bReserved : Byte; // reserved for future use. Must be zero.
  end;
  IDEREGS = TIDERegs;
  PIDERegs = ^TIDERegs;

 TIdSector = packed record
    wGenConfig : Word; //00
    wNumCyls : Word;
    wReserved : Word;
    wNumHeads : Word;
    wBytesPerTrack : Word;
    wBytesPerSector : Word;
    wSectorsPerTrack : Word;
    wVendorUnique : Array[0..2] of Word;
    sSerialNumber : Array[0..19] of Char; //10-19
    wBufferType : Word;
    wBufferSize : Word;
    wECCSize : Word;
    sFirmwareRev : Array[0..7] of Char; //23-26
    sModelNumber : Array[0..39] of Char; //27-46
    wMoreVendorUnique : Word;
    wDoubleWordIO : Word;
    wCapabilities : Word;
    wReserved1 : Word;
    wPIOTiming : Word;
    wDMATiming : Word;
    wBS : Word;
    wNumCurrentCyls : Word;
    wNumCurrentHeads : Word;
    wNumCurrentSectorsPerTrack : Word;
    ulCurrentSectorCapacity : ULONG; //57-58
    wMultSectorStuff : Word;
    ulTotalAddressableSectors : ULONG; //60-61
    wSingleWordDMA : Word;
    wMultiWordDMA : Word; //63
    wFlowControlPIOSupported : Word; //64
    wMinimumMultiWordDMA : Word; //65
    wRecommendedMultiWordDMA : Word; //66
    wMinimumPIOCycleWOFlow : Word; //67
    wMinimumPIOCycleIORDYFlow : Word; //68
    bReserved1 : Array[0..21] of Byte; //69-79
    wMajorVersionNumber : Word; //80
    wMinorVersionNumber : Word; //81
    wCommandSetSupported : Word; //82
    wCommandSetSupported2 : Word; //83
    wCommandSetExtension : Word; //84
    wCommandSetFeatureEnabled1 : Word; //85
    wCommandSetFeatureEnabled2 : Word; //86
    wCommandSetFeatureEnabled3 : Word; //87
    wUltraDMAMode : Word; //88
    wTimeRequiredErase : Word; //89
    wTimeRequiredEnhancedErase : Word; //90
    wAbleMode : Word; //91
    bReserved2 : Array[0..71] of Byte; //92-127
    wSecurityModeFeature : Word; //128
    wCurrentFeatureOption : Word; //129
    wReserved2 : Word; //130
    wInitialPowerMode : Word; //131
    bReserved3 : Array[0..247] of Byte; //132-255
  end;
  PIdSector = ^TIdSector;
Man übernehme diese Konstanten:

Delphi-Quellcode:
const
  BufferSize = SizeOf(TIDERegs)+4;
  IOCTL_IDE_PASS_THROUGH = $0004d028;
Und dann diese beiden Funktionen:
Delphi-Quellcode:
Function IdeRegPassThrough(Device: String; var ideregs: TIDERegs ): Boolean;
var
  ret:BOOL;
  hDevice : THandle;
  cbBytesReturned : DWORD;
  pInData : PIDERegs;
  pOutData : Pointer;
  Buffer : Array[0..BufferSize-1] of Byte;
begin
  Result := False;
  FillChar(Buffer,BufferSize,#0);

  hDevice := CreateFile( PChar(Device), GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
  if hDevice=INVALID_HANDLE_VALUE then Exit;
  try
    pInData := @Buffer;
     pOutData := pInData;
    pInData^ := ideregs;
    ret := DeviceIoControl( hDevice, IOCTL_IDE_PASS_THROUGH, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil );
    if not ret then begin
      Exit;
    end;
    ideregs := PIDERegs(pOutData)^;
  finally
    CloseHandle(hDevice);
  end;
  Result := True;
end;

function SendToSleep(Device: String): Boolean;
var
  ideregs : TIDERegs;
begin
  Result := False;
  with ideregs do
  begin
    bFeaturesReg := 0;
    bSectorCountReg := 0;
    bSectorNumberReg := 0;
    bCylLowReg := 0;
    bCylHighReg := 0;
    bDriveHeadReg := $A0;
    bCommandReg := $E6;
    bReserved := 0;
  end;
  if not IdeRegPassThrough(Device, ideregs ) then Exit else Result := True;
end;
Voilà.

Jetzt die
Erklärung:
Die Funktion IdeRegPassThrough stammt aus einem japanischen Projekt, in dem es darum ging, das APM von Festplatten unter W2k zu kontrollieren. Um dies zu tun, werden ATA - Kommandos an die Festplatte geschickt. Dies kann man unter Windows 2000 aufwärts mit dem Befehl IOCTL_IDE_PASS_THROUGH bewerkstelligen.
Jetzt brauch man eigentlich nur den Befehl zum Ausschalten an die Platte senden. Dies geschieht mit meiner Funktion SendToSleep, die als Parameter \\.\PhysicalDriveX erwartet, wobei X hier für eine Zahl steht. Dabei repräsentiert die 0 euer erstes IDE - Laufwerk, die 1 euer zweites usw... Der eigentliche Befehl findet sich in dieser Zeile:
bCommandReg := $E6; $E6 ist laut ATA - Definition der Sleep-Befehl. Dieser ist ab ATA4 Pflicht. Er erwartet keine weiteren Parameter und gibt auch keine Werte zurück.

Beispielaufruf:
Aufgerufen werden könnte die Funktion zum Beispiel so:
Delphi-Quellcode:
if SendToSleep('\\.\PhysicalDrive'+ SleepEdit.Text) then
 Showmessage('Laufwerk erfolgreich schlafen gelegt')
 else
 Showmessage('Laufwerk nicht schlafen legen können');
end;
Mal sehen, vllt. baue ich so eine Funktion noch in mein SMART - Programm ein. Über den Sinn und Zweck schweige ich mich aus. Es gibt Solche, die meinen, soetwas sei für die Lebensdauer der Hardware nicht förderlich, wieder andere meinen, ab einer gewissen Zeit würde das sogar Sinn ergeben.

Ich hoffe, ich konnte euch etwas helfen...
  Mit Zitat antworten Zitat