Reputation: 279
I have a custom hardware device which is connected to a windows computer. I want to provide the static information and dynamic data of this device to other services of the computer which query using WMI.
From my research I've found that I have to write a WMI provider. My current software application uses JPOS to interface the hardware. Hence I have to interface WMI to a Java application.
I've seen C# and c++ examples to achieve this task. My current understanding is to write a C++ wmi provider and use JNI to integrate to my current application. I've seen further examples where JNA is used to query using wmi. Yet my research did not yield any productive information on writing a provider with JNA.
Is writing a C++ and integrating through JNI the best way to handle this situation? Or is there any better solution?
Upvotes: 2
Views: 1163
Reputation: 279
Following are some hints on how I currently solved this issue for anyone who would like to try.
1. Creating a custom wmi class.
Windows wbemtest.exe tool is your friend. This tool can save your life as it can generate new wmi classes and edit them. When opened with administrative privileges, it can generate custom wmi classes, add properties and modify.
Alternatively a .mof file can be written to create a custom class. An example of a .mof file is as follows.
#pragma namespace("\\\\.\\Root\\Cimv2")
class MyTestClass
{
[Key] uint32 KeyProperty = 1;
string Version = "1.1.1";
};
Information on running this .mof file can be found here.
2. Adding properties
While webmtester and .mof method can be used to add properties there are powershell commandlets I found useful. A powerful set of powershell commandlets are here by Stephane van Gulick.
3. Retrieving properties programmatically
Example c++ program to retrieve properties programmatically is as below.
// PropertyRetrieve.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
// WMI query to list all properties and values of the root/CIMV2:Detagger class.
// This C++ code was generated using the WMI Code Generator, Version 10.0.13.0
// https://www.robvanderwoude.com/wmigen.php
//
// The generated code was derived from sample code provided by Microsoft:
// https://msdn.microsoft.com/en-us/library/aa390423(v=vs.85).aspx
// The sample code was modified to display multiple properties.
// Most of the original comments from the sample code were left intact.
// Limited testing has been done in Microsoft Visual C++ 2010 Express Edition.
#define _WIN32_DCOM
#include <iostream>
#include <iomanip>
#include <string>
#include <comdef.h>
#include <Wbemidl.h>
using namespace std;
#pragma comment( lib, "wbemuuid.lib" )
HRESULT hr;
IWbemClassObject *pclsObj = NULL;
void DisplayProperty(LPCWSTR propertyname)
{
VARIANT vtProperty;
VariantInit(&vtProperty);
try
{
hr = pclsObj->Get(propertyname, 0, &vtProperty, 0, 0);
if (vtProperty.vt == VT_DISPATCH)
{
wcout << vtProperty.pdispVal;
}
else if (vtProperty.vt == VT_BSTR)
{
wcout << vtProperty.bstrVal;
}
else if (vtProperty.vt == VT_UI1)
{
wcout << vtProperty.uiVal;
}
else if (vtProperty.vt == VT_EMPTY)
{
wcout << L"[NULL]";
}
}
catch (...)
{
wcout.clear();
wcout << resetiosflags(std::ios::showbase);
}
VariantClear(&vtProperty);
}
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cerr << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
return 1; // 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))
{
cerr << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *)&pLoc
);
if (FAILED(hres))
{
cerr << "Failed to create IWbemLocator object. Err code = 0x" << hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// 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\\CIMV2"), // 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))
{
cerr << "Could not connect. Error code = 0x" << hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cerr << "Connected to root\\CIMV2 WMI namespace" << endl;
// 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))
{
cerr << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
IEnumWbemClassObject* pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT Name,TestValue,Version FROM Detagger"),
NULL,
NULL,
&pEnumerator
);
if (FAILED(hres))
{
cerr << "Query of Detagger class failed. Error code = 0x" << hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
ULONG uReturn = 0;
while (pEnumerator)
{
hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (hr != 0)
{
break;
}
wcout << "Name : ";
DisplayProperty((LPCWSTR)L"Name");
wcout << endl;
wcout << "TestValue : ";
DisplayProperty((LPCWSTR)L"TestValue");
wcout << endl;
wcout << "Version : ";
DisplayProperty((LPCWSTR)L"Version");
wcout << endl;
pclsObj->Release();
}
// Cleanup
// =======
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
cout << "Press anykey to exit.";
cin.ignore();
cin.get();
return 0; // Program successfully completed.
}
4. Modifying a property programmatically
An example c++ code to modify a property programmatically is as below. This option would require administrative privilege.
_variant_t var2(L"15");
IWbemClassObject *detaggerClass = NULL;
HRESULT dflkj = pSvc->GetObjectW(L"Detagger", 0, NULL, &detaggerClass, NULL);
IWbemClassObject *detaggerInstance = NULL;
dflkj = detaggerClass->SpawnInstance(0, &detaggerInstance);
detaggerInstance->Put(L"TestValue", 0, &var2, CIM_UINT8)
|| Fail("Put failed for 'TestValue'");
HRESULT er = pSvc->PutInstance(detaggerInstance, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
Here I have modified the value of the unsigned int 8 variable called "TestValue"
5. Next step
The next option I would have is to interface the c++ application to the main Java application through JNA.
Upvotes: 3