SATA接続のSSD,ハードディスクのSMART情報を取得 ~Delphiソースコード集
~S.M.A.R.T.(Self-Monitoring Analysis and Reporting Technology)
ハードディスクの健康状態の情報を表示する
NVMe接続のM.2 SSDのHealth Information情報(ディスクの健康状態の情報)を取得したい場合は以下を参照してください。
NVMe接続のM.2 SSDのディスクの健康状態の情報を取得(https://mam-mam.net/delphi/smart_nvme.html)
SATA接続のM.2コネクタのSSDの場合は以下のソースコードでS.M.A.R.T情報を取得できます。
Delphiを起動して新規作成を行う
Delphiを起動し、ファイル→新規作成→Windows VCLアプリケーションをクリックし、 空のアプリケーションを選択してOKボタンを押してプロジェクトを作成します。TButtonとTMemoをフォームにドラッグ&ドロップします。
すべて保存を押して、プロジェクトフォルダを作成してプロジェクトとユニットを保存します。

SMART情報取得ユニットの作成
ファイル⇒新規作成⇒ユニット-Delphiをクリックして新規ユニットを作成します。以下ソースを入力してファイル名「USmart.pas」として保存します。
unit USmart; interface uses Winapi.Windows, System.SysUtils; type TMamSmart=record AttrID:Byte; StatusFlags:Word; Value:Byte; WorstValue:Byte; Threshold:Byte; RawValue:Array[0..5] of Byte; end; TMamSmartArray=Array of TMamSmart; //DriveNum(0~)とMamSmartArrayを与えるとSmart情報をMamSmartArrayに返す procedure getSmart(DriveNum:Integer;var MamSmartArray:TMamSmartArray); implementation const NUM_ATTR_STRUCTS = 30; SMART_READ_ATTRIBUTE_VALUES = $D0; SMART_READ_ATTRIBUTE_THRESHOLDS = $D1; SMART_CYL_LOW = $4F; SMART_CYL_HIGH = $C2; //SMART_CMD Performs SMART cmd. IDE_EXECUTE_SMART_FUNCTION = $B0; //BUFFER SIZE READ_ATTRIBUTE_BUFFER_SIZE = 512; //DeviceIOControlのAPIへの命令 DFP_GET_VERSION = $00074080; DFP_SEND_DRIVE_COMMAND = $0007c084; DFP_RECEIVE_DRIVE_DATA = $0007c088; type //Attribute情報の構造体 DriveAttribute = packed record bAttrID:Byte; wStatusFlags:Word; bAttrValue:Byte; bWorstValue:Byte; bRawValue:array[0..5] of Byte; bReserved:Byte; end; //DFP_RECEIVE_DRIVE_DATA命令のINとOUTの構造体 _IDEREGS=packed record bFeaturesReg:Byte; bSectorCountReg:Byte; bSectorNumberReg:Byte; bCylLowReg:Byte; bCylHighReg:Byte; bDriveHeadReg:Byte; bCommandReg:Byte; bReserved:Byte; end; IDEREGS=_IDEREGS; _SENDCMDINPARAMS=packed record cBufferSize:DWORD; irDriveRegs:IDEREGS; bDriveNumber:Byte; bReserved:array[0..2] of Byte; dwReserved:array[0..3] of DWORD; bBuffer:array[0..0] of Byte; end; SENDCMDINPARAMS=_SENDCMDINPARAMS; _DRIVERSTATUS = packed record bDriveError:Byte; bIDEStatus:Byte; bReserved:array[0..1] of Byte; dwReserved:array[0..1] of DWORD; end; DRIVERSTATUS=_DRIVERSTATUS; _BSENDCMDOUTPARAMS = packed record cBufferSize:DWORD; DriverStatus:DRIVERSTATUS; bBuffer:array [0..511] of Byte; end; BSENDCMDOUTPARAMS=_BSENDCMDOUTPARAMS; BDriveAttribute = packed record AttrStructRevision:WORD; DA:array[0..NUM_ATTR_STRUCTS-1] of DriveAttribute; end; PBDriveAttribute =^BDriveAttribute; //Threshold情報の構造体 AttrThreshold = packed record bAttrID:Byte; bWarrantyThreshold:Byte; bReserved:array[0..9] of Byte; end; BAttrThreshold = packed record ThreStructRevision:Word; AT:array[0..NUM_ATTR_STRUCTS-1] of AttrThreshold end; PBAttrThreshold =^BAttrThreshold; procedure getSmart(DriveNum:Integer;var MamSmartArray:TMamSmartArray); var hd:THandle; st:string; wst:array[0..127] of char; br:Cardinal; SCIP:SENDCMDINPARAMS; SCOP_ATTR:BSENDCMDOUTPARAMS; SCOP_THRE:BSENDCMDOUTPARAMS; PBAttr:PBDriveAttribute; PBThre:PBAttrThreshold; i,ct:Integer; begin st:='\\.\PhysicalDrive'+Trim(InttoStr(DriveNum)); strpcopy(wst,st); //deviceハンドルの取得 hd:=CreateFile(wst,GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hd = INVALID_HANDLE_VALUE then exit; ZeroMemory(@SCIP,SizeOf(SENDCMDINPARAMS)); ZeroMemory(@SCOP_ATTR,SizeOf(BSENDCMDOUTPARAMS)); SCIP.irDriveRegs.bFeaturesReg:=SMART_READ_ATTRIBUTE_VALUES; SCIP.irDriveRegs.bSectorCountReg:=1; SCIP.irDriveRegs.bSectorNumberReg:=1; SCIP.irDriveRegs.bCylLowReg:=SMART_CYL_LOW; SCIP.irDriveRegs.bCylHighReg:=SMART_CYL_HIGH; SCIP.irDriveRegs.bDriveHeadReg:=$A0 or ((DriveNum and 1) shl 4); SCIP.irDriveRegs.bCommandReg:=IDE_EXECUTE_SMART_FUNCTION; SCIP.cBufferSize:=READ_ATTRIBUTE_BUFFER_SIZE; SCIP.bDriveNumber:=DriveNum; DeviceIoControl(hd,DFP_RECEIVE_DRIVE_DATA, @SCIP,sizeof(SCIP),@SCOP_ATTR,sizeof(SCOP_ATTR),br,nil); PBAttr:=PBDriveAttribute(Pointer(@(SCOP_ATTR.bBuffer)[0])); ZeroMemory(@SCIP,SizeOf(SENDCMDINPARAMS)); ZeroMemory(@SCOP_THRE,SizeOf(BSENDCMDOUTPARAMS)); SCIP.irDriveRegs.bFeaturesReg:=SMART_READ_ATTRIBUTE_THRESHOLDS; SCIP.irDriveRegs.bSectorCountReg:=1; SCIP.irDriveRegs.bSectorNumberReg:=1; SCIP.irDriveRegs.bCylLowReg:=SMART_CYL_LOW; SCIP.irDriveRegs.bCylHighReg:=SMART_CYL_HIGH; SCIP.irDriveRegs.bDriveHeadReg:=$A0 or ((DriveNum and 1) shl 4); SCIP.irDriveRegs.bCommandReg:=IDE_EXECUTE_SMART_FUNCTION; SCIP.cBufferSize:=READ_ATTRIBUTE_BUFFER_SIZE; SCIP.bDriveNumber:=DriveNum; DeviceIoControl(hd,DFP_RECEIVE_DRIVE_DATA, @SCIP,sizeof(SCIP),@SCOP_THRE,sizeof(SCOP_THRE),br,nil); PBThre:=PBAttrThreshold(pointer(@SCOP_THRE.bBuffer)); CloseHandle(hd); setlength(MamSmartArray,0); ct:=0; for i := 0 to NUM_ATTR_STRUCTS-1 do begin if PBAttr.DA[i].bAttrID>0 then begin inc(ct); setlength(MamSmartArray,ct); MamSmartArray[ct-1].AttrID:=PBAttr.DA[i].bAttrID; MamSmartArray[ct-1].StatusFlags:=PBAttr.DA[i].wStatusFlags; MamSmartArray[ct-1].Value:=PBAttr.DA[i].bAttrValue; MamSmartArray[ct-1].WorstValue:=PBAttr.DA[i].bWorstValue; MamSmartArray[ct-1].Threshold:=PBThre.AT[i].bWarrantyThreshold; MamSmartArray[ct-1].RawValue[0]:=PBAttr.DA[i].bRawValue[0]; MamSmartArray[ct-1].RawValue[1]:=PBAttr.DA[i].bRawValue[1]; MamSmartArray[ct-1].RawValue[2]:=PBAttr.DA[i].bRawValue[2]; MamSmartArray[ct-1].RawValue[3]:=PBAttr.DA[i].bRawValue[3]; MamSmartArray[ct-1].RawValue[4]:=PBAttr.DA[i].bRawValue[4]; MamSmartArray[ct-1].RawValue[5]:=PBAttr.DA[i].bRawValue[5]; end; end; end; end.
Button1クリック時のソースコードを記述する
Unit1のフォームのButton1をダブルクリックしてソースコードを記述します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls
,System.Win.Registry ,USmart;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var reg:TRegistry;
i,j,ct:integer;
smart:TMamSmartArray;
begin
ct:=0;
//レジストリから物理ドライブ数を取得する
reg:=TRegistry.Create(Winapi.Windows.KEY_READ);
reg.RootKey:=HKEY_LOCAL_MACHINE;
if reg.KeyExists(
'SYSTEM\CurrentControlSet\Services\disk\Enum') then
begin
reg.OpenKey('SYSTEM\CurrentControlSet\Services\disk\Enum',False);
ct:=reg.ReadInteger('Count');
end;
reg.CloseKey;
reg.Free;
//物理ドライブ数ループ
for i := 0 to ct-1 do
begin
//SMART情報の取得
getSmart(i,smart);
//SMART情報が取得出来たら
if length(smart)>0 then
begin
memo1.Lines.Add('DriveNum:'+IntToStr(i));
//属性数ループ
for j := 0 to length(smart)-1 do
begin
memo1.Lines.Add(
format('%3d,%4d,%2d,%2d,%2d,%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x',
[ smart[j].AttrID, smart[j].StatusFlags,
smart[j].Value, smart[j].WorstValue, smart[j].Threshold,
smart[j].RawValue[5], smart[j].RawValue[4],
smart[j].RawValue[3], smart[j].RawValue[2],
smart[j].RawValue[1], smart[j].RawValue[0]
])
);
end;
end;
end;
end;
end.
コンパイルする
[プロジェクト]⇒[すべてのプロジェクトをコンパイル]を選択してコンパイルします。実行
本アプリケーションは管理者権限が必要(DeviceIoControl APIを使用するには管理者権限が必要となる)なので、 実行ボタンを押して、Button1をクリックしても実行されません。コンパイルされた実行ファイルを右クリックして「管理者として実行」をクリックして実行し、Button1をクリックします。
