This is a advanced C++ library for WMI.
Before we can start using WMI we need to ensure that COM is initialized. To initialize we need to
call ComManager
. At the end of the application we need to cleanup by
calling ComManager::Uninitialize
.
int main()
{
try
{
wmi::ComManager::Initialize(security);
// ...
}
catch (const wmi::ComException& ex)
{
std::cout << ex.What() << std::endl;
std::wcout << ex.Detailed() << std::endl;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
wmi::ComManager::Uninitialize();
// ...
}
One of the core features of WMI is to query system information from remote and local machines. This library makes it easy to define and query objects. It also allows to combine the responses with C++ standard library algorithms with iterators.
In the following example we will query all the processes that are running in our machine.
int main()
{
// ...
// Ensure that we are connected to a namespace resource
auto resource = std::make_shared<wmi::ManagementResource>("root\\cimv2");
resource->Connect();
auto query_processor = resource->GetQueryProcessor("SELECT * FROM Win32_Process");
auto stream = query_processor->GetStream();
for (const auto& obj : stream)
{
std::wcout << std::get<wmi::BasicString>(obj["Name"]) << std::endl;
}
// ...
}
As you can see we are making usage of many std functions like get<T>
to access property values
of our ManagementObject
or use the implemented iterators to enumerate through each item.
Always accessing the properties through the ManagementObject
can be complex and feels
not clean. Therefor it is possible to map WMI classes to our own data structures. To achive this
we need to implement HandleManagementObjectMapped
for our data structure.
// Our Win32_Process struct
struct Win32_Process
{
wmi::Int32 process_id;
wmi::BasicString name;
};
static void HandleManagementObjectMapped(const wmi::ManagementObject& from, Win32_Process& to)
{
to.process_id = std::get<wmi::Int32>(from["ProcessId"]);
to.name = std::get<wmi::BasicString>(from["Name"]);
}
int main()
{
// ...
// Ensure that we are connected to a namespace resource
auto resource = std::make_shared<wmi::ManagementResource>("root\\cimv2");
resource->Connect();
auto query_processor = resource->GetQueryProcessor("SELECT * FROM Win32_Process");
auto stream = query_processor->GetStream<Win32_Process>(); // Pass our structure to template
for (const auto& obj : stream)
{
std::wcout << obj.process << " " << obj.name << std::endl;
}
// ...
}
int main()
{
// ...
auto found = std::find_if(std::begin(stream), std::end(stream), [](const Win32_Process& process)
{
return wcscmp(process.name, TEXT("code.exe"));
});
if (found != std::end(stream))
{
std::wcout << (*found).name << std::endl;
}
// ...
}
WMI provides functionalities to subscribe to events. We are able to react to events for example a new instance was created like a process has been spawned.
In this example we are writing the ProcessId
and Name
everytime a process is spawned on the machine.
int main()
{
// ...
auto event_bus = resource->GetEventBus();
auto token = event_bus->Subscribe(TEXT("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'"), [](const wmi::ManagementObject& obj)
{
auto x = obj["TargetInstance"];
auto y = std::get<wmi::ManagementObject>(x);
auto process = y.Proxy().As<Win32_Process>();
std::wcout << process.process_id << std::endl;
std::wcout << process.name << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(15));
// ...
}