diff options
Diffstat (limited to '')
-rw-r--r-- | os_win32/wmiquery.cpp | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/os_win32/wmiquery.cpp b/os_win32/wmiquery.cpp new file mode 100644 index 0000000..929b22a --- /dev/null +++ b/os_win32/wmiquery.cpp @@ -0,0 +1,190 @@ +/* + * os_win32/wmiquery.cpp + * + * Home page of code is: http://www.smartmontools.org + * + * Copyright (C) 2011-13 Christian Franke + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" +#define WINVER 0x0400 +#define _WIN32_WINNT WINVER + +#include "wmiquery.h" + +#include <stdio.h> + +const char * wmiquery_cpp_cvsid = "$Id: wmiquery.cpp 4760 2018-08-19 18:45:53Z chrfranke $" + WMIQUERY_H_CVSID; + + +///////////////////////////////////////////////////////////////////////////// +// com_bstr + +com_bstr::com_bstr(const char * str) +: m_bstr(0) +{ + int sz = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, (LPWSTR)0, 0); + if (sz <= 0) + return; + m_bstr = SysAllocStringLen((OLECHAR*)0, sz-1); + if (!m_bstr) + return; // throw std::bad_alloc + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, m_bstr, sz); +} + +bool com_bstr::to_str(const BSTR & bstr, std::string & str) +{ + if (!bstr) + return false; + int sz = WideCharToMultiByte(CP_ACP, 0, bstr, -1, (LPSTR)0, 0, (LPCSTR)0, (LPBOOL)0); + if (sz <= 0) + return false; + char * buf = new char[sz]; + WideCharToMultiByte(CP_ACP, 0, bstr, -1, buf, sz, (LPCSTR)0, (LPBOOL)0); + str = buf; + delete [] buf; + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// wbem_object + +std::string wbem_object::get_str(const char * name) /*const*/ +{ + std::string s; + if (!m_intf) + return s; + + VARIANT var; VariantInit(&var); + if (m_intf->Get(com_bstr(name), 0L, &var, (CIMTYPE*)0, (LPLONG)0) /* != WBEM_S_NO_ERROR */) + return s; + + if (var.vt == VT_BSTR) + com_bstr::to_str(var.bstrVal, s); + VariantClear(&var); + return s; +} + + +///////////////////////////////////////////////////////////////////////////// +// wbem_enumerator + +bool wbem_enumerator::next(wbem_object & obj) +{ + if (!m_intf) + return false; + + ULONG n = 0; + HRESULT rc = m_intf->Next(5000 /*5s*/, 1 /*count*/, obj.m_intf.replace(), &n); + if (FAILED(rc) || n != 1) + return false; + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// wbem_services + +const CLSID xCLSID_WbemLocator = {0x4590f811, 0x1d3a, 0x11d0, {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}}; +const IID xIID_IWbemLocator = {0xdc12a687, 0x737f, 0x11cf, {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}}; + +bool wbem_services::connect() +{ + // Init COM during first call. + static HRESULT init_rc = -1; + static bool init_tried = false; + if (!init_tried) { + init_tried = true; + init_rc = CoInitialize((LPVOID)0); + } + if (!(init_rc == S_OK || init_rc == S_FALSE)) + return false; + + /// Create locator. + com_intf_ptr<IWbemLocator> locator; + HRESULT rc = CoCreateInstance(xCLSID_WbemLocator, (LPUNKNOWN)0, + CLSCTX_INPROC_SERVER, xIID_IWbemLocator, (LPVOID*)locator.replace()); + if (FAILED(rc)) + return false; + + // Set timeout flag if supported. + long flags = 0; + OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver); + if (GetVersionExA(&ver) && ver.dwPlatformId == VER_PLATFORM_WIN32_NT + && ( ver.dwMajorVersion >= 6 // Vista + || (ver.dwMajorVersion == 5 && ver.dwMinorVersion >= 1))) // XP + flags = WBEM_FLAG_CONNECT_USE_MAX_WAIT; // return in 2min or less + + // Connect to local server. + rc = locator->ConnectServer(com_bstr("\\\\.\\root\\cimv2"), + (BSTR)0, (BSTR)0, (BSTR)0, // User, Password, Locale + flags, (BSTR)0, (IWbemContext*)0, m_intf.replace()); + if (FAILED(rc)) + return false; + + // Set authentication information, + rc = CoSetProxyBlanket(m_intf.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + (OLECHAR*)0, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, + (RPC_AUTH_IDENTITY_HANDLE*)0, EOAC_NONE); + if (FAILED(rc)) { + m_intf.reset(); + return false; + } + + return true; +} + +bool wbem_services::vquery(wbem_enumerator & result, const char * qstr, va_list args) /*const*/ +{ + if (!m_intf) + return false; + + char qline[1024]; + vsnprintf(qline, sizeof(qline), qstr, args); + qline[sizeof(qline)-1] = 0; + + HRESULT rc = m_intf->ExecQuery( + com_bstr("WQL"), com_bstr(qline), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + (IWbemContext*)0, result.m_intf.replace()); + if (FAILED(rc)) + return false; + + return true; +} + +bool wbem_services::vquery1(wbem_object & obj, const char * qstr, va_list args) /*const*/ +{ + wbem_enumerator result; + if (!vquery(result, qstr, args)) + return false; + + if (!result.next(obj)) + return false; + + wbem_object peek; + if (result.next(peek)) + return false; + + return true; +} + +bool wbem_services::query(wbem_enumerator & result, const char * qstr, ...) /*const*/ +{ + va_list args; va_start(args, qstr); + bool ok = vquery(result, qstr, args); + va_end(args); + return ok; +} + +bool wbem_services::query1(wbem_object & obj, const char * qstr, ...) /*const*/ +{ + va_list args; va_start(args, qstr); + bool ok = vquery1(obj, qstr, args); + va_end(args); + return ok; +} |