まずはDeviceIOControlで使用する構造体、定数などを定義します。
type
{ ATA_PASS_THROUGH_EX }
_ATA_PASS_THROUGH_EX = packed record
Length: Word;
AtaFlags: Word;
PathId: UCHAR;
TargetId: UCHAR;
Lun: UCHAR;
ReservedAsUchar: UCHAR;
DataTransferLength: ULONG;
TimeOutValue: ULONG;
ReservedAsUlong: ULONG;
DataBufferOffset: ULONG_PTR;
PreviousTaskFile: array [0..7] of UCHAR;
CurrentTaskFile: array [0..7] of UCHAR;
end;
{$EXTERNALSYM _ATA_PASS_THROUGH_EX}
ATA_PASS_THROUGH_EX = _ATA_PASS_THROUGH_EX;
{$EXTERNALSYM ATA_PASS_THROUGH_EX}
TAtaPassThroughEx = _ATA_PASS_THROUGH_EX;
PAtaPassThroughEx = ^TAtaPassThroughEx;
{ ATAIdentifyDeviceQuery }
TATAIdentifyDeviceQuery = packed record
header: ATA_PASS_THROUGH_EX;
data: array [0..255] of Word;
end;
const
{$IF RTLVersion < 22.0}
FILE_DEVICE_CONTROLLER = $00000004;
{$EXTERNALSYM FILE_DEVICE_CONTROLLER}
FILE_READ_ACCESS = $0001;
{$EXTERNALSYM FILE_READ_ACCESS}
FILE_WRITE_ACCESS = $0002;
{$EXTERNALSYM FILE_WRITE_ACCESS}
{$IFEND}
ATA_FLAGS_DRDY_REQUIRED = $01;
ATA_FLAGS_DATA_IN = $02;
ATA_FLAGS_DATA_OUT = $04;
ATA_FLAGS_48BIT_COMMAND = $08;
ATA_FLAGS_USE_DMA = $10;
ATA_FLAGS_NO_MULTIPLE = $20;
IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER;
IOCTL_ATA_PASS_THROUGH = (IOCTL_SCSI_BASE shl 16) or
((FILE_READ_ACCESS or FILE_WRITE_ACCESS) shl 14) or
($040B shl 2) or
(METHOD_BUFFERED);
FILE_DEVICE_CONTROLLER、FILE_READ_ACCESS、FILE_WRITE_ACCESSはDelphi XE以降では定義済ですので、Delphi 2009およびそれ以前のバージョン用に定義しています。これらを使用して物理ドライブ名"\\.\PhysicalDrive#"で指定したドライブが"nominal media rotation rate"かどうかを調べる関数です。
function HasNominalMediaRotationRate(const PhysicalDrivePath: String): Boolean;
var
h: THandle;
ATAIdentifyDeviceQuery: TATAIdentifyDeviceQuery;
RSize: DWORD;
begin
h := CreateFile(PChar(PhysicalDrivePath),GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,nil,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if h = INVALID_HANDLE_VALUE then
begin
RaiseLastOSError;
end;
try
FillChar(ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),0);
with ATAIdentifyDeviceQuery do
begin
header.Length := SizeOf(header);
header.AtaFlags := ATA_FLAGS_DATA_IN;
header.DataTransferLength := SizeOf(data);
header.TimeOutValue := 3; // sec
header.DataBufferOffset := SizeOf(header);
header.CurrentTaskFile[6] := $EC; // ATA IDENTIFY DEVICE command
end;
RSize := 0;
if DeviceIoControl(h,IOCTL_ATA_PASS_THROUGH,
@ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
@ATAIdentifyDeviceQuery,SizeOf(ATAIdentifyDeviceQuery),
RSize,nil) = False then
begin
RaiseLastOSError;
end;
Result := (ATAIdentifyDeviceQuery.data[217] = 1);
finally
CloseHandle(h);
end;
end;
Trueが返ってくればそのドライブはnominal media rotation rateである、つまりSSDと判断できる、ということになります。こちらの方法はデバイスがATA8-ACSに対応していればWindows 2000およびそれ以降のすべてのOSで使用できますが、Windows Vista以降では管理者権限が必要になります。Delphiで作ったアプリケーションが管理者権限を要求するようにする方法についてはWindows Vista上で管理者権限を要求するアプリケーションを作成するを参照してください。なおWindows Vista以降の環境で管理者権限を要求するアプリケーションをデバッグするときはDelphiのIDEそのものも管理者権限で実行する必要があるようですので注意してください。ファイル名/パス名から物理ドライブ番号("\\.\PhysicalDrive#"の#)を取得する方法は前回のものを使用できますので、こちらもファイル/パスがSSD上に書き込まれるかどうかを調べてみます。
var
Index: Integer;
Filename: String;
PhysicalDrives: TIntegerDynArray;
PhysicalDrivePath: String;
IsSSD: Boolean;
begin
Filename := "C:\"; // 例: "C:\"を調べます
SetLength(PhysicalDrives,0);
PathnameToPhysicalDriveNumber(Filename,PhysicalDrives);
try
IsSSD := False;
for Index := Low(PhysicalDrives) to High(PhysicalDrives) do
begin
PhysicalDrivePath := Format('\\.\PhysicalDrive%d',[PhysicalDrives[Index]]);
try
IsSSD := IsSSD or HasNominalMediaRotationRate(PhysicalDrivePath);
except
{ Ignore }
end;
if IsSSD = True then
begin
Break;
end;
end;
if IsSSD = True then
begin
MessageDlg(Format('ファイル ''%s'' はSSDに書き込まれます。',[Filename]),
mtInformation,[mbOk],0);
end
else
begin
MessageDlg(Format('ファイル ''%s'' はSSDには書き込まれません。',[Filename]),
mtInformation,[mbOk],0);
end;
finally
SetLength(PhysicalDrives,0);
end;
end;
OSによって判定方法を切り替えるのであれば、
if CheckWin32Version(6,1) = True then
begin
{ Windows 7 or later }
IsSSD := IsSSD or HasNoSeekPenalty(PhysicalDrivePath);
end
else
begin
{ Windows Vista or earlier }
IsSSD := IsSSD or HasNominalMediaRotationRate(PhysicalDrivePath);
end;
とすればよいのですが、こうしたところでアプリケーション全体としては管理者権限が必要になってしまうので微妙な感じです(Vistaを考えなければ管理者権限を要求する必要がなくなりますが…)。
0 件のコメント:
コメントを投稿