In this post I look at a definitive way to determine if your Microsoft Windows Machine is using a Solid State Drive (SSD) or an older style Rotary Disk (HDD). I’m using C++ with WMI here and making use of the MSFT_PhysicalDisk class in the ROOT\\\microsoft\\windows\\storage namespace.

You can watch the video as I step through developing the code (apologies for bad sound, I’m travelling atm!).

Full source code is available from the link in the footer of this article.

WARNING!!

If you load up the source in VS, please note You may well need to set the linker “additional include directories” or remove the entry currently in there – there are some issues with installing the Driver Development Toolkit that clobbers some of the SDK paths.

WMI

If you’re not familiar with WMI (Windows Management Instrumentation) it provides a common interface for accessing device level and performance level data from a fairly high level. Because it’s COM, it can be accessed throughout Windows pretty agnostically without facing the barriers of only being accessable to a particular programming language or runtime.

Program Sysnopsis

At the program entry point I create two variables

int main()
{
	IWbemLocator *wbemLocator = NULL;
	IWbemServices *wbemServices = NULL;

The wbemLocator is the object we will use as a service locator to get us the actual wbemServices object that we will use to execute queries against the WMI Management Service. The Service Locator Pattern is fairly common in the industry as a run-time linker to avoid instantiating concrete classes directly, although personally I’m not a huge fan of such abstractions without real world benefits in exchange for the complexity they often introduce, especially locating breaking changes in the instantiated objects… anyway!!!

Initialize COM

In the next line we call into the COM Runtime to Initialize COM for our running program and make a call to use our locator to get our service proxy

IntializeCOM();

Which calls into the function

void IntializeCOM()
{
	HRESULT hres;
	hres = CoInitializeEx(0, COINIT_MULTITHREADED);
	if (FAILED(hres))
	{
		cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
		// Program has failed.
	}
	// Step 2: --------------------------------------------------
	// Set general COM security levels --------------------------
	hres = CoInitializeSecurity(
		NULL,
		-1,                          // COM authentication
		NULL,                        // Authentication services
		NULL,                        // Reserved
		RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
		RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
		NULL,                        // Authentication info
		EOAC_NONE,                   // Additional capabilities 
		NULL                         // Reserved
	);

	if (FAILED(hres))
	{
		cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
		CoUninitialize();             // Program has failed.
	}
}

Setting up WMI

Next I make a call to ask COM to set up our WMI Service (and locator)

SetupWBEM(wbemLocator, wbemServices);

This calls the method


void SetupWBEM(IWbemLocator*& pLoc, IWbemServices*& pSvc)
{
	// Step 3: ---------------------------------------------------
	// Obtain the initial locator to WMI -------------------------

	HRESULT hres;
	//IWbemLocator *pLoc = NULL;

	hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);

	if (FAILED(hres))
	{
		cout << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << endl;
		CoUninitialize();
	}

	// Step 4: -----------------------------------------------------
	// Connect to WMI through the IWbemLocator::ConnectServer method

	//IWbemServices *pSvc = NULL;

	// Connect to the root\cimv2 namespace with
	// the current user and obtain pointer pSvc
	// to make IWbemServices calls.
	hres = pLoc->ConnectServer(
		_bstr_t(L"ROOT\\\microsoft\\windows\\storage"), // Object path of WMI namespace
		NULL,                    // User name. NULL = current user
		NULL,                    // User password. NULL = current
		0,                       // Locale. NULL indicates current
		NULL,                    // Security flags.
		0,                       // Authority (for example, Kerberos)
		0,                       // Context object 
		&pSvc                    // pointer to IWbemServices proxy
	);

	if (FAILED(hres))
	{
		cout << "Could not connect. Error code = 0x" << hex << hres << endl;
		pLoc->Release();
		CoUninitialize();
	}


	// Step 5: --------------------------------------------------
	// Set security levels on the proxy -------------------------

	hres = CoSetProxyBlanket(
		pSvc,                        // Indicates the proxy to set
		RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
		RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
		NULL,                        // Server principal name 
		RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
		RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
		NULL,                        // client identity
		EOAC_NONE                    // proxy capabilities 
	);

	if (FAILED(hres))
	{
		cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
		pSvc->Release();
		pLoc->Release();
		CoUninitialize();
	}

}

In the line

CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);

We ask COM to create our Service Locator

The get the locator to actually get the service for us passing in the namespace ROOT\\\microsoft\\windows\\storage


hres = pLoc->ConnectServer(
		_bstr_t(L"ROOT\\\microsoft\\windows\\storage"), // Object path of WMI namespace
		NULL,                    // User name. NULL = current user
		NULL,                    // User password. NULL = current
		0,                       // Locale. NULL indicates current
		NULL,                    // Security flags.
		0,                       // Authority (for example, Kerberos)
		0,                       // Context object 
		&pSvc                    // pointer to IWbemServices proxy
	);

This gives us a pointer to a WMIService object &pSvc

Next we call the query SELECT * FROM MSFT_PhysicalDisk against the WMI management system to give us an enumerator that we can use to derive instances of the WMI class MSFT_PhysicalDisk that represents the physical disks in the underlying hardware


IEnumWbemClassObject* storageEnumerator = NULL;
	HRESULT hres = wbemServices->ExecQuery(
		bstr_t("WQL"),
		bstr_t("SELECT * FROM MSFT_PhysicalDisk"),
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		NULL,
		&storageEnumerator);

Let's get the data

We next iterate through the storageEnumerator object returned for the ExecQuery function


while (storageEnumerator)
	{
		HRESULT hr = storageEnumerator->Next(WBEM_INFINITE, 1, &storageWbemObject, &uReturn);
		if (0 == uReturn)
		{
			break;
		}

This gives is the storageWbemObject object we can use to pull our data from

We declare some variant types to hold our data


	VARIANT deviceId;
		VARIANT busType;
		VARIANT healthStatus;
		VARIANT spindleSpeed;
		VARIANT	mediaType;

And call the Get method on the storageWbemObject object itself passing in the string property name we wish to retrieve


storageWbemObject->Get(L"DeviceId", 0, &deviceId, 0, 0);
		storageWbemObject->Get(L"BusType", 0, &busType, 0, 0);
		storageWbemObject->Get(L"HealthStatus", 0, &healthStatus, 0, 0);
		storageWbemObject->Get(L"SpindleSpeed", 0, &spindleSpeed, 0, 0);
		storageWbemObject->Get(L"MediaType", 0, &mediaType, 0, 0);

We then just need to pull the data out of these variant and into a real object we can use to consume elsewhere


StorageDevice storageDevice;

storageDevice.DeviceId = deviceId.bstrVal == NULL ? "" : _bstr_t(deviceId.bstrVal);
		storageDevice.BusType = busType.uintVal;
		storageDevice.HealthStatus = healthStatus.uintVal;
		storageDevice.SpindleSpeed = spindleSpeed.uintVal;
		storageDevice.MediaType = mediaType.uintVal;

The actual StorageDevice class looks like the following

Header



#pragma once
#include 

using namespace::std;

class StorageDevice
{
public:
	StorageDevice();
	~StorageDevice();

	string  DeviceId;
	int BusType;
	int HealthStatus;
	int SpindleSpeed;
	int MediaType;

};

Source


#include "StorageDevice.h"



StorageDevice::StorageDevice()
{
}


StorageDevice::~StorageDevice()
{
}

Where's da code at

Source code and be downloaded from here

Written by admin