まずは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 件のコメント:
コメントを投稿