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...