0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NVMe SSDの温度情報を取り出す(C++)

Posted at

NVMe SSDの温度情報を取り出す(C++)

SSDの温度情報をコマンドラインで取得したくなったので、ライブラリを調べていてもイマイチ解決しなかったので、いっそ作ってみた。
IOCTL関連とDeviceIoControl関数を利用したHDD温度のよい資料がなかったので、将来わからなくなったときのためにまとめておく。

問題点

NVMe(PCIe)のSSD情報しか取れません。

SATAドライブのSMART情報はWMIコマンドで取得してください。
以下のコードで取得できるはずです。

WMIを使った呼び出し

wmic /namespace:\\Root\WMI path MSStorageDriver_FailurePredictData

Get-WmiObjectを使った呼び出し

Get-WmiObject -Namespace Root\WMI -Class MSStorageDriver_FailurePredictData

VendorSpecificにある194のIDが付いているところに温度情報が入っています。

注意点としては、SATA接続の装置からしか読めません。
(USB不可、NVMe不可)
サポートされていませんと出ます。

##将来検討
SATAとNVMeを識別してどちらも取得できるようにしたい。

###実際のコード
GitHubにアップロードしてみました。
NVMe_GetTemperature

##コード解説
NVMeStorage管理クラスを準備

NVMeStorage.h

#pragma once
#include <string>
#include <winnt.h>
using namespace std;

class NVMeStorage
{
private:
	LPCWSTR wszDrive;

public:
	NVMeStorage();
	NVMeStorage(LPCWSTR wszDrive); //ドライブ名を与えるコンストラクタ
	int setReadDrive(LPCWSTR wszDrive); //ドライブ名を与える
	bool getDriveGeometry(DISK_GEOMETRY* pdg); //ドライブのジオメトリを読み出す
	bool getTemperature(STORAGE_TEMPERATURE_DATA_DESCRIPTOR* stdd); //ドライブの温度情報を読み出す
private:
	bool getDriveQuery(void* obj, int size); //ドライブ温度情報読み出しから呼ばれるPrivateメソッド
};
NVMeStorage.cpp
bool NVMeStorage::getTemperature(STORAGE_TEMPERATURE_DATA_DESCRIPTOR* stdd)
{
	if (stdd == nullptr)
	{
		return false;
	}
	BOOL bResult = FALSE;      // generic results flag
	bResult = getDriveQuery(&(*stdd), sizeof(*stdd));
	return bResult;
}

bool NVMeStorage::getDriveQuery(void* obj, int size)
{

	HANDLE hDevice = INVALID_HANDLE_VALUE;
	BOOL bResult = FALSE;
	DWORD junk = 0;

	hDevice = CreateFileW(this->wszDrive,	// drive to open
		0,				// no access to the drive
		FILE_SHARE_READ |	// share mode
		FILE_SHARE_WRITE,
		NULL,				// default security attributes
		OPEN_EXISTING,			// disposition
		0,				// file attributes
		NULL);			// do not copy file attributes

	if(hDevice == INVALID_HANDLE_VALUE)
	{
		return false;
	}
	
	STORAGE_PROPERTY_QUERY spq;
	spq.PropertyId = StorageDeviceTemperatureProperty;
	spq.QueryType = PropertyStandardQuery;

	bResult = DeviceIoControl(hDevice,    // device to be queried
		IOCTL_STORAGE_QUERY_PROPERTY, // operation to perform
		&spq, sizeof(spq),            // no input buffer
		obj, size,            // output buffer
		&junk,                        // # bytes returned
		(LPOVERLAPPED)NULL);          // synchronous I/O

	CloseHandle(hDevice);

	return (bResult);
}

ドライブ読み出しのためのクラスを作成したので、クラスを利用してNVMeの情報を読み出すための方法

StorageTemperature.cpp
#include "NVMeStorage.h"
#define wszDrive L"\\\\.\\PhysicalDrive0"

int wmain(int argc, wchar_t* argv[])
{
    auto errcode = 0;
    auto Temperature = true;

    // 読み出すドライブを設定
    NVMeStorage ssd(wszDrive);

	// ドライブの温度を読み出し
	if(Temperature)
	{
		STORAGE_TEMPERATURE_DATA_DESCRIPTOR stdd;
		bResult = ssd.getTemperature(&stdd);

		time_t now = time(NULL);
		tm pnow;
		localtime_s(&pnow, &now);

		if (bResult)
		{
			wprintf(L"%2d/%2d/%2d %2d:%2d:%2d Temperature = %d\n", pnow.tm_year + 1900, pnow.tm_mon + 1, pnow.tm_mday, pnow.tm_hour, pnow.tm_min, pnow.tm_sec, stdd.TemperatureInfo->Temperature);
		}
		else
		{
			wprintf(L"GetDriveQuery failed. Error %ld.\n", GetLastError());
		}
		errcode &= bResult;
	}

    return errcode;

##まとめ
目的は簡単なのにIOCTLで検索すると、Linux関連ばかり出てきてWindows関連はほとんど出てこない。そして、出てきたと思ったらQuery投げます。とそこから先に進むのが大変すぎた。

NVMeの温度だけは取れるようになりましたが、CrystalDiskInfoと同じ結果が出てるのできっと正しいはず。

前の方にも記載したけど、ゆくゆくはSATAやUSBの温度も取りたい。

まとまってない…

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?