jacob-project
jacob-project copied to clipboard
Support WMI
WMI is a layer over COM with its own peculiarities. Not easy to use with COM directly. I have developed a thin layer over Jacob that handles WMI, consisting of six small interfaces and classes. I'll post it here after some more testing.
Provisional Javadoc attached for comment. Jacob-WMI-Javadoc.zip
Do you have any other examples?
If there is another release, I'm going to drop 32 bit process support. Is that a problem?
I have 9 test classes and an entire implementation ready to contribute when I next get a window to work on this. Now consists of 37 interfaces and classes. Example test below.
Please don't remove 32-bit support. At present that is the only one I can build for.
Sample test case, for the common case of enumerating and interrogating Services:
/*
* Copyright (c) Esmond Pitt, 2023.
* All rights reserved.
*/
package com.jacob.wmi;
import com.jacob.com.ComThread;
import com.jacob.com.Variant;
import java.util.Date;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.runners.MethodSorters;
/**
*
* @author Esmond Pitt
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SWbemServicesTest
{
@Rule
public TestName name = new TestName();
public SWbemServicesTest()
{
}
@BeforeClass
public static void setUpClass()
{
}
@AfterClass
public static void tearDownClass()
{
}
@Before
public void setUp()
{
System.out.println("SWbemServicesTest."+name.getMethodName());
ComThread.InitMTA();
}
@After
public void tearDown()
{
ComThread.Release();
}
/**
* Test of constructors of class SWbemServices.
* This demonstrates that "winmgmts:" connects to "winmgmts:\\\\.\\root\\CIMv2".
*/
public void testConstructor1()
{
SWbemServices services = new SWbemServices();
SWbemObject w32p = services.getService("Win32_Process");
// System.out.println(w32p.getPropertyAsString("CreationClassName"));
// w32p
// .getProperties()
// .stream()
// .forEach(System.out::println)
// ;
}
/**
* Test of constructors of class SWbemServices.
*/
public void testConstructor2()
{
SWbemServices services = new SWbemServices("winmgmts:\\\\.\\root\\CIMV2");
SWbemObject w32p = services.getService("Win32_Process");
System.out.println(w32p);
}
/**
* Test of associatorsOf() method, of class SWbemServices.
*/
@Test
public void testAssociatorsOf()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemObjectSet set = services.associatorsOf
(
"Win32_Service.Name='MySQL'",
null,
null,
null,
null,
false,
false,
null,
null,
WbemFlags.ReturnImmediately|WbemFlags.ForwardOnly,
// WbemFlags.ReturnWhenComplete,
null
);
// SWbemLastError lastError = new SWbemLastError();
// System.out.println(set.getCount()+" instances of Win32_service");
set
.stream()
.forEach(System.out::println)
;
}
/**
* Test of associatorsOfAsync() method, of class SWbemServices.
*/
@Test
public void testAssociatorsOfAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
};
services.associatorsOfAsync
(
sink,
"Win32_Service.Name='MySQL'",
null,
null,
null,
null,
false,
false,
null,
null,
WbemFlags.SendStatus,
null,
null
);
// E_CALL_CANCELLED=0x80041032
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(30*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
}
/**
* Test of execNotificationQuery method, of class SWbemServices.
*/
@Test
public void testExecNotificationQuery()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s = locator.connectServer(".", "root\\CIMv2", null, null);
// s
// .getMethods()
// .stream()
// .forEach(m -> System.out.println(m.name.getMethodName()))
// ;
SWbemSink sink = new SWbemDebugSink()
{
// @Override
// protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
// {
// super.onObjectReady(object, asyncContext);
// }
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
}
;
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testExecNotificationQueryAsync"));
// Now using a disk activity query so we don't have to start and stop processes.
SWbemEventSource source = s.execNotificationQuery
(
// "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'",
// __InstanceOperationEvent is the base class of __InstanceCreationEvent, __InstanceDeletionEvent, and __InstanceModificationEvent.
// "SELECT * FROM __InstanceOperationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_LogicalDisk'",
"SELECT * FROM __InstanceModificationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_LogicalDisk'",
0,
null
);
// System.out.println(new Date()+": waiting for you to start a process");
// Start notepad in another thread.
// Thread t = new Thread
// (
// () ->
// {
// try
// {
//// System.out.println("Starting notepad.exe");
// Process p = Runtime.getRuntime().exec("c:\\windows\\notepad.exe");
// synchronized (sink)
// {
// // Wait for the sink to get OnComplete.
// sink.wait(10*1000);
// }
//// System.out.println("Destroying");
// p.destroyForcibly();
//// System.out.println("Destroyed");
// }
// catch (IOException|InterruptedException exc)
// {
// exc.printStackTrace();
// }
// }
// );
// t.start();
System.out.println(new Date()+": calling nextEvent()");
SWbemObject o =
// Test the timeout.
// If there is a timeout here a JVM crash ensues.
// This is perhaps a Jacob problem,
// as this is a method which can return null instead of an object,
// which may be unexplored territory.
// source.nextEvent(3*1000)
// Test the iterator, which also tests nextEvent().
source.iterator().next();
;
System.out.println("nextEvent="+o);
if (o == null)
{
System.out.println(new Date()+": nextEvent() timed out");
}
else
{
System.out.println(new Date()+": nextEvent() completed");
o
.getProperties()
.stream()
.forEach(System.out::println)
;
}
// Cancel the query, otherwise this method will never exit.
System.out.println(name.getMethodName()+": cancelling WbemEventSource");
source.cancel();
System.out.println(name.getMethodName()+": cancelled WbemEventSource");
// try
// {
// t.join();
// }
// catch (InterruptedException exc)
// {
// exc.printStackTrace();
// }
}
@Test
public void testNewVariantIsNull()
{
Variant v = new Variant();
System.out.println(v.isNull());
}
/**
* Test of testExecNotificationQueryAsync method, of class SWbemServices.
*/
@Test
public void testExecNotificationQueryAsync()
{
// if (true)
// // Not working. JMV doesn't exit.
// return;
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
// @Override
// protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
// {
// super.onObjectReady(object, asyncContext);
// }
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
// System.out.println("onCompleted called: result=0x"+Integer.toHexString(result));
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
}
;
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testExecNotificationQueryAsync"));
// Now using a disk activity query so we don't have to start and stop processes.
services.execNotificationQueryAsync
(
sink,
// "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'",
// __InstanceOperationEvent is the base class of __InstanceCreationEvent, __InstanceDeletionEvent, and __InstanceModificationEvent.
// "SELECT * FROM __InstanceOperationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_LogicalDisk'",
"SELECT * FROM __InstanceModificationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_LogicalDisk'",
// WbemFlags.QueryPrototype| // DOES NOT WORK
WbemFlags.SendStatus,
null,
context
);
try
{
// System.out.println(new Date()+": waiting for you to start a process");
// TODO Start notepad in another thread.
// Thread t = new Thread
// (
// () ->
// {
// try
// {
//// System.out.println("Starting notepad.exe");
// Process p = Runtime.getRuntime().exec("c:\\windows\\notepad.exe");
// synchronized (sink)
// {
// // Wait for the sink to get OnComplete.
// sink.wait(10*1000);
// }
//// System.out.println("Destroying");
// p.destroyForcibly();
//// System.out.println("Destroyed");
// }
// catch (IOException|InterruptedException exc)
// {
// exc.printStackTrace();
// }
// }
// );
// t.start();
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
System.out.println(new Date()+": wait completed or timed out");
// t.join();
}
catch (InterruptedException exc)
{
exc.printStackTrace();
System.out.println(new Date()+": wait interrupted");
}
finally
{
// This test never exits.
// WELL IT SHOULD, and cancelling the sink is how.
System.out.println(name.getMethodName()+": cancelling the async query");
// Works occasionally.
// Sometimes JVM exits abnomrmally.
// Mostly the JVM doesn't exit at all after running this test.
sink.cancel();
System.out.println(name.getMethodName()+": cancelled the async query");
services.safeRelease(); // Didn't help.
System.out.println("Released the SWbemServices object");
}
}
/**
* Test of execQuery method, of class SWbemServices.
*/
@Test
public void testExecQuery()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s = locator.connectServer(".", "root\\CIMv2", null, null);
// Events e = new Events();
// DispatchEvents ev = new DispatchEvents(s, e);
// Execute a query to retrieve all the java.exe processes.
SWbemObjectSet r = s.execQuery("Select * from Win32_Process where name=\"java.exe\"");
r
.stream()
.map(ax -> ax.getPropertyAsString("Name"))
.forEach(System.out::println)
;
// Get the Win32_Process object.
SWbemObject w32p = s.getService("Win32_Process");
// Get the 'SetPriority()' method.
SWbemMethod m = w32p.getMethod("SetPriority");
// Get an InParameters instance.
SWbemObject p = m.getInParameters();
// Set the Priority property to 32 (normal priority).
p.setProperty("Priority", 32);
// Call the method on all the query results, i.e. set all their priorities to 32.
System.out.println("SetPriority------:");
r
.stream()
.map(o -> o.execMethod("SetPriority", p))
.map(o -> o.getPropertyAsInt("ReturnValue"))
.forEach(System.out::println)
;
// Get the owner: demonstration of getting output parameters.
System.out.println("GetOwner------:");
r
.stream()
.map(o -> o.execMethod("GetOwner", o.getMethod("GetOwner").getInParameters()))
.forEach
(
o ->
{
System.out.println("User="+o.getPropertyAsString("User"));
System.out.println("Domain="+o.getPropertyAsString("Domain"));
System.out.println("ReturnValue="+o.getPropertyAsInt("ReturnValue"));
}
);
}
@Test
public void testExecQueryAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
// onCompleted
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
// TODO call the OnCompletionListeners.
// System.out.println("onCompleted called");
super.onCompleted(result, errorObject, asyncContext);
// Just to confirm the property names, undocumented by Microsoft.
// if (result != 0)
// {
// errorObject
// .getProperties()
// .stream()
// .map(SWbemProperty::getName)
// .forEach(System.out::println)
// ;
// }
if (result != 0)
System.out.println(errorObject);
synchronized (this)
{
this.notifyAll();
}
}
// onObjectPut
@Override
protected void onObjectPut(SWbemObjectPath path, SWbemNamedValueSet asyncContext)
{
// TODO call the OnObjectPutListeners.
System.out.println("OnObjectPut called");
}
// onObjectReady
protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
{
// TODO call the OnObjectReadyListeners.
// System.out.println("onObjectReady called");
System.out.println("Name="+object.getPropertyAsString("Name"));
System.out.println("ConnectionsEstablished="+object.getProperty("ConnectionsEstablished"));
super.onObjectReady(object, asyncContext);
// System.out.println("source="+asyncContext.getPropertyAsString("Source"));
}
// onProgress
protected void onProgress(int upperBound, int current, String message, SWbemNamedValueSet asyncContext)
{
// TODO call the OnProgressListeners.
System.out.println("OnProgress called");
}
}
;
SWbemNamedValueSet nvs = null;
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testExecuteQueryAsync"));
// context
// .stream()
// .forEach(nv -> System.out.println("Name="+nv.name.getMethodName()+" Value="+nv.getValue()))
// ;
// Execute a query to retrieve all the java.exe processes.
services.execQueryAsync
(
sink,
"Select * from Win32_PerfFormattedData_TCPIP_TCPv4",
WbemFlags.SendStatus,
nvs,
context
);
// Events e = new Events();
// DispatchEvents ev = new DispatchEvents(s, e);
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
context
.stream()
.forEach(nv -> System.out.println("Name="+nv.getName()+" Value="+nv.getValue()))
;
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
services.safeRelease();
System.out.println(name.getMethodName()+": releaseed the SWbemServices object");
}
// public class Events
// {
// public void DoneExecuteQuery(Variant[] args)
// {
// System.out.println("ExecuteQuery was called with "+args.length+" arguments");
// }
// public void DoneGetService(Variant[] args)
// {
// System.out.println("GetService was called with "+args.length+" arguments");
// }
// // onCompleted
// public void OnCompletion(long handle, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
// {
// // TODO call the OnCompletionListeners.
// System.out.println("OnCompletion called");
// }
// // onObjectPut
// public void onObjectPut(SWbemObjectPath path, SWbemNamedValueSet asyncContext)
// {
// // TODO call the OnObjectPutListeners.
// System.out.println("onObjectPut called");
// }
// // onObjectReady
// public void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
// {
// // TODO call the OnObjectReadyListeners.
// System.out.println("onObjectReady called");
// }
// // onProgress
// public void onProgress(int upperBound, int current, String message, SWbemNamedValueSet asyncContext)
// {
// // TODO call the OnProgressListeners.
// System.out.println("onProgress called");
// }
// }
/**
* Test of get() method, of class SWbemServices.
*/
@Test
public void testGet()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemObject o = s.get("Win32_Service.Name='MySQL'", 0, null);
o
.getProperties()
.stream()
.forEach(System.out::println)
;
}
/**
* Test of getAsync() method, of class SWbemServices.
*/
@Test
public void testGetAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
@Override
protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
{
// super.onObjectReady(object, asyncContext);
System.out.println("onObjectReady(): got object name="+object.getPropertyAsString("Name"));
}
};
s.getAsync
(
sink,
"Win32_Service.Name='MySQL'",
WbemFlags.SendStatus,
null,
null
);
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
}
/**
* Test of testGetSecurity method, of class SWbemServices.
*/
@Test
public void testGetSecurity()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s =
locator.connectServer(".", "root\\CIMv2", null, null)
// new SWbemServices()
;
SWbemSecurity security = s.getSecurity();
System.out.println("security="+security);
}
/**
* Test of getService method, of class SWbemServices.
*/
@Test
public void testGetService()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices s = locator.connectServer(".", "root\\CIMv2", null, null);
// Get the Win32_Process object.
SWbemObject w32p = s.getService("Win32_Process");
// List the property names of an instance (a process).
System.out.println("Properties------:");
w32p
.getProperties()
.stream()
.map(SWbemProperty::getName)
.forEach(System.out::println)
;
// List the Win32_Process method names.
System.out.println("Methods------:");
w32p
.getMethods()
.stream()
.map(SWbemMethod::getName)
.forEach(System.out::println)
;
}
/**
* Test of instancesOf() method, of class SWbemServices.
*/
@Test
public void testInstancesOf()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemObjectSet set = services.instancesOf
(
"Win32_Service",
WbemFlags.ReturnImmediately|WbemFlags.ForwardOnly,
// WbemFlags.ReturnWhenComplete,
null
);
set
.stream()
.forEach(o -> System.out.println("Service name="+o.getPropertyAsString("Name")))
;
System.out.println(set.getCount()+" instances of Win32_service");
}
/**
* Test of instancesOfAsync() method, of class SWbemServices.
*/
@Test
public void testInstancesOfAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
@Override
protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
{
// super.onObjectReady(object, asyncContext);
System.out.println("Context source="+asyncContext.item("Source"));
System.out.println("Service name="+object.getPropertyAsString("Name"));
}
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
};
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testInstancesOfAsync"));
services.instancesOfAsync
(
sink,
"Win32_Service",
WbemFlags.SendStatus,
null,
context
);
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
}
/**
* Test of referenceTo() method, of class SWbemServices.
*/
@Test
public void testReferencesTo()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
/*
String objectPath,
String resultClass,
String role,
boolean classesOnly,
boolean schemaOnly,
String requiredQualifier,
int flags,
SWbemNamedValueSet nvs
*/
SWbemObjectSet set = services.referencesTo
(
"Win32_Service",
null,
null,
false,
false,
null,
WbemFlags.ReturnImmediately|WbemFlags.ForwardOnly,
// WbemFlags.ReturnWhenComplete,
null
);
set
.stream()
.forEach(o -> System.out.println("Reference name="+o.getPropertyAsString("Name")))
;
// Can't use getCount() with ForwardOnly.
// System.out.println(set.getCount()+" references to Win32_service");
}
/**
* Test of referencesToAsync() method, of class SWbemServices.
*/
@Test
public void testReferencesToAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
@Override
protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
{
// super.onObjectReady(object, asyncContext);
System.out.println("Context source="+asyncContext.item("Source"));
System.out.println("Reference name="+object.getPropertyAsString("Name"));
}
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
};
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testReferencesToAsync"));
services.referencesToAsync
(
sink,
"Win32_Service",
null,
null,
false,
false,
null,
WbemFlags.SendStatus,
null,
context
);
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
}
/**
* Test of subClassesOf() method, of class SWbemServices.
*/
@Test
public void testSubClassesOf()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemObjectSet set = services.subClassesOf
(
"Win32_Service",
WbemFlags.ReturnImmediately|WbemFlags.ForwardOnly|WbemQueryFlags.Shallow,
// WbemFlags.ReturnWhenComplete|WbemQueryFlags.Shallow,
null
);
set
.stream()
.peek(System.out::println)
.forEach(o -> System.out.println("Subclass name="+o.getPropertyAsString("Name")))
;
System.out.println(set.getCount()+" subclass of Win32_service");
}
/**
* Test of subClassesOfAsync() method, of class SWbemServices.
*/
@Test
public void testSubClassesOfAsync()
{
SWbemLocator locator = new SWbemLocator();
SWbemServices services = locator.connectServer(".", "root\\CIMv2", null, null);
SWbemSink sink = new SWbemDebugSink()
{
@Override
protected void onObjectReady(SWbemObject object, SWbemNamedValueSet asyncContext)
{
// super.onObjectReady(object, asyncContext);
System.out.println("Context source="+asyncContext.item("Source"));
System.out.println("Subclass name="+object.getPropertyAsString("Name"));
}
@Override
protected void onCompleted(int result, SWbemLastError errorObject, SWbemNamedValueSet asyncContext)
{
super.onCompleted(result, errorObject, asyncContext);
synchronized (this)
{
this.notifyAll();
}
}
};
SWbemNamedValueSet context = new SWbemNamedValueSet();
context.add("Source", new Variant("testSubClassesOfAsync"));
services.subClassesOfAsync
(
sink,
"Win32_Service",
WbemFlags.SendStatus|WbemQueryFlags.Shallow,
null,
context
);
try
{
synchronized (sink)
{
// Wait for the sink to get OnComplete.
sink.wait(10*1000);
}
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
System.out.println(name.getMethodName()+": cancelling sink");
sink.cancel();
System.out.println(name.getMethodName()+": cancelled sink");
}
}
Please don't remove 32-bit support. At present that is the only one I can build for. In any case I will bet money that most of your current users are 32-bit and not up to Java 17. Don't break backwards compatibility please.
Rolled back yesterday's commit that removed X86 support. Returned to Java 8