1818import static java .lang .foreign .MemorySegment .NULL ;
1919import static java .lang .foreign .ValueLayout .JAVA_CHAR ;
2020import static java .lang .foreign .ValueLayout .JAVA_INT ;
21- import static net .codecrete .usb .windows .DeviceProperty . DEVPKEY_Device_Service ;
21+ import static net .codecrete .usb .windows .DevicePropertyKey . Service ;
2222import static net .codecrete .usb .windows .Win .allocateErrorState ;
2323import static net .codecrete .usb .windows .WindowsUSBException .throwException ;
2424import static net .codecrete .usb .windows .WindowsUSBException .throwLastError ;
@@ -45,21 +45,13 @@ interface InfoSetCreator {
4545 private MemorySegment devIntfData ;
4646 private int iterationIndex = -1 ;
4747
48- /**
49- * Creates a new empty device info set.
50- *
51- * @return device info set
52- */
53- static DeviceInfoSet ofEmpty () {
54- return new DeviceInfoSet ((arena , errorState ) -> SetupAPI2 .SetupDiCreateDeviceInfoList (NULL , NULL , errorState ));
55- }
56-
5748 /**
5849 * Creates a new device info set containing the present devices of the specified device class and
5950 * optionally device instance ID.
6051 *
6152 * <p>
62- * After creation, there is no current element. {@link #next()} must be called first.
53+ * After creation, there is no current element. {@link #next()} should be called to iterate the first
54+ * and all subsequent elements.
6355 * </p>
6456 *
6557 * @param interfaceGuid device interface class GUID
@@ -74,6 +66,45 @@ static DeviceInfoSet ofPresentDevices(MemorySegment interfaceGuid, String instan
7466 });
7567 }
7668
69+ /**
70+ * Creates a new device info set containing a single device with the specified instance ID.
71+ *
72+ * <p>
73+ * The device becomes the current element. The set cannot be iterated.
74+ * </p>
75+ *
76+ * @param instanceId instance ID
77+ */
78+ static DeviceInfoSet ofInstance (String instanceId ) {
79+ var devInfoSet = ofEmpty ();
80+ devInfoSet .addInstanceId (instanceId );
81+ return devInfoSet ;
82+ }
83+
84+ /**
85+ * Creates a new device info set containing a single device with the specified path.
86+ *
87+ * <p>
88+ * The device becomes the current element. The set cannot be iterated.
89+ * </p>
90+ *
91+ * @param devicePath device path
92+ */
93+ static DeviceInfoSet ofPath (String devicePath ) {
94+ var devInfoSet = ofEmpty ();
95+ devInfoSet .addDevicePath (devicePath );
96+ return devInfoSet ;
97+ }
98+
99+ /**
100+ * Creates a new empty device info set.
101+ *
102+ * @return device info set
103+ */
104+ private static DeviceInfoSet ofEmpty () {
105+ return new DeviceInfoSet ((arena , errorState ) -> SetupAPI2 .SetupDiCreateDeviceInfoList (NULL , NULL , errorState ));
106+ }
107+
77108 private DeviceInfoSet (InfoSetCreator creator ) {
78109 arena = Arena .ofConfined ();
79110 try {
@@ -101,48 +132,13 @@ public void close() {
101132 arena .close ();
102133 }
103134
104- /**
105- * Iterates to the next element in this set.
106- *
107- * @return {@code true} if there is a current element, {@code false} if the iteration moved beyond the last element
108- */
109- boolean next () {
110- iterationIndex += 1 ;
111- if (SetupAPI2 .SetupDiEnumDeviceInfo (devInfoSet , iterationIndex , devInfoData , errorState ) == 0 ) {
112- var err = Win .getLastError (errorState );
113- if (err == Kernel32 .ERROR_NO_MORE_ITEMS ())
114- return false ;
115- throwLastError (errorState , "internal error (SetupDiEnumDeviceInfo)" );
116- }
117-
118- return true ;
119- }
120-
121- /**
122- * Adds the device with the specified instance ID to this device info set.
123- *
124- * <p>
125- * The added device becomes the current element.
126- * </p>
127- *
128- * @param instanceId instance ID
129- */
130- void addInstance (String instanceId ) {
135+ private void addInstanceId (String instanceId ) {
131136 var instanceIdSegment = Win .createSegmentFromString (instanceId , arena );
132137 if (SetupAPI2 .SetupDiOpenDeviceInfoW (devInfoSet , instanceIdSegment , NULL , 0 , devInfoData , errorState ) == 0 )
133138 throwLastError (errorState , "internal error (SetupDiOpenDeviceInfoW)" );
134139 }
135140
136- /**
137- * Adds the device with the specified path to this device info set.
138- *
139- * <p>
140- * The added device becomes the current element.
141- * </p>
142- *
143- * @param devicePath device path
144- */
145- void addDevice (String devicePath ) {
141+ private void addDevicePath (String devicePath ) {
146142 if (devIntfData != null )
147143 throw new AssertionError ("calling addDevice() multiple times is not implemented" );
148144
@@ -163,14 +159,30 @@ void addDevice(String devicePath) {
163159 }
164160 }
165161
162+ /**
163+ * Iterates to the next element in this set.
164+ *
165+ * @return {@code true} if there is a current element, {@code false} if the iteration moved beyond the last element
166+ */
167+ boolean next () {
168+ iterationIndex += 1 ;
169+ if (SetupAPI2 .SetupDiEnumDeviceInfo (devInfoSet , iterationIndex , devInfoData , errorState ) == 0 ) {
170+ var err = Win .getLastError (errorState );
171+ if (err == Kernel32 .ERROR_NO_MORE_ITEMS ())
172+ return false ;
173+ throwLastError (errorState , "internal error (SetupDiEnumDeviceInfo)" );
174+ }
175+
176+ return true ;
177+ }
166178
167179 /**
168180 * Checks if the current element is a composite USB device
169181 *
170182 * @return {@code true} if it is a composite device
171183 */
172184 boolean isCompositeDevice () {
173- var deviceService = getStringProperty (DEVPKEY_Device_Service );
185+ var deviceService = getStringProperty (Service );
174186
175187 // usbccgp is the USB Generic Parent Driver used for composite devices
176188 return "usbccgp" .equalsIgnoreCase (deviceService );
0 commit comments