Files
fastfetch/src/util/windows/wmi.cpp
T

321 lines
9.8 KiB
C++
Raw Normal View History

#include "wmi.hpp"
#include <synchapi.h>
2022-10-06 22:56:56 +08:00
#include <wchar.h>
2022-10-11 22:36:14 +08:00
#include <math.h>
2022-10-16 23:58:13 +08:00
namespace
{
// Provide our bstr_t to avoid libstdc++ dependency
struct bstr_t
{
explicit bstr_t(const wchar_t* str) noexcept: _bstr(SysAllocString(str)) {}
~bstr_t() noexcept { SysFreeString(_bstr); }
explicit operator const wchar_t*() const noexcept { return _bstr; }
operator BSTR() const noexcept { return _bstr; }
private:
BSTR _bstr;
};
}
//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
static void CoUninitializeWrap()
{
CoUninitialize();
}
static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID, PVOID *lpContext)
{
HRESULT hres;
// Initialize COM
hres = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
// Set general COM security levels
hres = CoInitializeSecurity(
nullptr,
-1, // COM authentication
nullptr, // Authentication services
nullptr, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
nullptr, // Authentication info
EOAC_NONE, // Additional capabilities
nullptr // Reserved
);
if (FAILED(hres))
{
CoUninitialize();
2022-10-13 18:12:54 +08:00
*((const char**)lpContext) = "Failed to initialize security";
return FALSE;
}
// Obtain the initial locator to WMI
IWbemLocator* pLoc = nullptr;
hres = CoCreateInstance(
CLSID_WbemLocator,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
(LPVOID*) &pLoc);
if (FAILED(hres))
{
CoUninitialize();
2022-10-13 18:12:54 +08:00
*((const char**)lpContext) = "Failed to create IWbemLocator object";
return FALSE;
}
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices* pSvc = nullptr;
// 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\\CIMV2"), // Object path of WMI namespace
nullptr, // User name. nullptr = current user
nullptr, // User password. nullptr = current
0, // Locale. nullptr indicates current
0, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&pSvc // pointer to IWbemServices proxy
);
pLoc->Release();
pLoc = nullptr;
if (FAILED(hres))
{
CoUninitialize();
2022-10-13 18:12:54 +08:00
*((const char**)lpContext) = "Could not connect WMI server";
return FALSE;
}
// 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
nullptr, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
nullptr, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
pSvc->Release();
CoUninitialize();
2022-10-13 18:12:54 +08:00
*((const char**)lpContext) = "Could not set proxy blanket";
return FALSE;
}
*((IWbemServices**)lpContext) = pSvc;
atexit(CoUninitializeWrap);
return TRUE;
}
2022-10-16 23:58:13 +08:00
FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error)
: pEnumerator(nullptr)
{
static INIT_ONCE s_InitOnce = INIT_ONCE_STATIC_INIT;
const char* context;
if (InitOnceExecuteOnce(&s_InitOnce, &InitHandleFunction, nullptr, (void**)&context) == FALSE)
{
if(error)
ffStrbufInitS(error, context);
2022-10-16 23:58:13 +08:00
return;
}
// Use the IWbemServices pointer to make requests of WMI
HRESULT hres;
hres = ((IWbemServices*)context)->ExecQuery(
bstr_t(L"WQL"),
bstr_t(queryStr),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
nullptr,
&pEnumerator);
if (FAILED(hres))
{
if(error)
2022-10-13 18:12:54 +08:00
ffStrbufAppendF(error, "Query for '%ls' failed. Error code = 0x%lX", queryStr, hres);
}
}
2022-10-16 23:58:13 +08:00
static void ffBstrToStrbuf(BSTR bstr, FFstrbuf* strbuf)
{
int len = (int)SysStringLen(bstr);
2022-10-11 20:13:44 +08:00
if(len <= 0)
{
ffStrbufClear(strbuf);
return;
}
int size_needed = WideCharToMultiByte(CP_UTF8, 0, bstr, len, nullptr, 0, nullptr, nullptr);
ffStrbufEnsureFree(strbuf, (uint32_t)size_needed);
WideCharToMultiByte(CP_UTF8, 0, bstr, len, strbuf->chars, size_needed, nullptr, nullptr);
strbuf->length = (uint32_t)size_needed;
2022-10-06 17:47:49 +08:00
strbuf->chars[size_needed] = '\0';
}
2022-10-16 23:58:13 +08:00
bool FFWmiRecord::getString(const wchar_t* key, FFstrbuf* strbuf)
{
bool result = true;
VARIANT vtProp;
VariantInit(&vtProp);
CIMTYPE type;
2022-10-06 22:56:56 +08:00
if(FAILED(obj->Get(key, 0, &vtProp, &type, nullptr)) || vtProp.vt != VT_BSTR)
{
result = false;
}
else
{
2022-10-06 22:56:56 +08:00
switch(vtProp.vt)
{
2022-10-06 22:56:56 +08:00
case VT_BSTR:
if(type == CIM_DATETIME)
{
ISWbemDateTime *pDateTime;
BSTR dateStr;
if(FAILED(CoCreateInstance(__uuidof(SWbemDateTime), 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDateTime))))
result = false;
else if(FAILED(pDateTime->put_Value(vtProp.bstrVal)))
result = false;
else if(FAILED(pDateTime->GetFileTime(VARIANT_TRUE, &dateStr)))
result = false;
else
ffBstrToStrbuf(dateStr, strbuf);
}
else
2022-10-06 22:56:56 +08:00
{
ffBstrToStrbuf(vtProp.bstrVal, strbuf);
}
break;
case VT_LPSTR:
ffStrbufAppendS(strbuf, vtProp.pcVal);
break;
case VT_LPWSTR: // TODO
default:
result = false;
break;
}
}
VariantClear(&vtProp);
return result;
}
2022-10-06 01:23:28 +08:00
2022-10-16 23:58:13 +08:00
bool FFWmiRecord::getSigned(const wchar_t* key, int64_t* integer)
2022-10-06 01:23:28 +08:00
{
bool result = true;
VARIANT vtProp;
VariantInit(&vtProp);
CIMTYPE type;
if(FAILED(obj->Get(key, 0, &vtProp, &type, nullptr)))
{
result = false;
}
else
{
2022-10-06 22:56:56 +08:00
switch(vtProp.vt)
{
case VT_BSTR: *integer = wcstoll(vtProp.bstrVal, nullptr, 10); break;
case VT_I1: *integer = vtProp.cVal; break;
case VT_I2: *integer = vtProp.iVal; break;
case VT_INT:
case VT_I4: *integer = vtProp.intVal; break;
case VT_I8: *integer = vtProp.llVal; break;
case VT_UI1: *integer = (int64_t)vtProp.bVal; break;
case VT_UI2: *integer = (int64_t)vtProp.uiVal; break;
case VT_UINT:
case VT_UI4: *integer = (int64_t)vtProp.uintVal; break;
case VT_UI8: *integer = (int64_t)vtProp.ullVal; break;
case VT_BOOL: *integer = vtProp.boolVal != VARIANT_FALSE; break;
2022-10-11 22:36:14 +08:00
default: *integer = 0; result = false;
2022-10-06 22:56:56 +08:00
}
}
VariantClear(&vtProp);
return result;
}
2022-10-16 23:58:13 +08:00
bool FFWmiRecord::getUnsigned(const wchar_t* key, uint64_t* integer)
2022-10-06 22:56:56 +08:00
{
bool result = true;
VARIANT vtProp;
VariantInit(&vtProp);
if(FAILED(obj->Get(key, 0, &vtProp, nullptr, nullptr)))
{
result = false;
}
else
{
switch(vtProp.vt)
{
case VT_BSTR: *integer = wcstoull(vtProp.bstrVal, nullptr, 10); break;
case VT_I1: *integer = (uint64_t)vtProp.cVal; break;
case VT_I2: *integer = (uint64_t)vtProp.iVal; break;
case VT_INT:
case VT_I4: *integer = (uint64_t)vtProp.intVal; break;
case VT_I8: *integer = (uint64_t)vtProp.llVal; break;
case VT_UI1: *integer = vtProp.bVal; break;
case VT_UI2: *integer = vtProp.uiVal; break;
case VT_UINT:
case VT_UI4: *integer = vtProp.uintVal; break;
case VT_UI8: *integer = vtProp.ullVal; break;
case VT_BOOL: *integer = vtProp.boolVal != VARIANT_FALSE; break;
2022-10-11 22:36:14 +08:00
default: *integer = 0; result = false;
2022-10-06 22:56:56 +08:00
}
}
VariantClear(&vtProp);
return result;
}
2022-10-16 23:58:13 +08:00
bool FFWmiRecord::getReal(const wchar_t* key, double* real)
2022-10-06 22:56:56 +08:00
{
bool result = true;
VARIANT vtProp;
VariantInit(&vtProp);
if(FAILED(obj->Get(key, 0, &vtProp, nullptr, nullptr)))
{
result = false;
}
else
{
switch(vtProp.vt)
2022-10-06 01:23:28 +08:00
{
2022-10-06 22:56:56 +08:00
case VT_BSTR: *real = wcstod(vtProp.bstrVal, nullptr); break;
case VT_I1: *real = vtProp.cVal; break;
case VT_I2: *real = vtProp.iVal; break;
case VT_INT:
case VT_I4: *real = vtProp.intVal; break;
case VT_I8: *real = (double)vtProp.llVal; break;
case VT_UI1: *real = vtProp.bVal; break;
case VT_UI2: *real = vtProp.uiVal; break;
case VT_UINT:
case VT_UI4: *real = vtProp.uintVal; break;
case VT_UI8: *real = (double)vtProp.ullVal; break;
case VT_R4: *real = vtProp.fltVal; break;
case VT_R8: *real = vtProp.dblVal; break;
case VT_BOOL: *real = vtProp.boolVal != VARIANT_FALSE; break;
2022-10-11 22:36:14 +08:00
default: *real = NAN; result = false;
2022-10-06 01:23:28 +08:00
}
}
VariantClear(&vtProp);
return result;
}