Skip to content

Commit 2898fba

Browse files
Fix PdhTest + update PdhEnumObjectItems
1 parent e0a28a3 commit 2898fba

File tree

3 files changed

+142
-97
lines changed

3 files changed

+142
-97
lines changed

contrib/platform/src/com/sun/jna/platform/win32/Pdh.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
*/
2424
package com.sun.jna.platform.win32;
2525

26-
import java.util.List;
27-
2826
import com.sun.jna.Native;
2927
import com.sun.jna.Pointer;
3028
import com.sun.jna.Structure;
@@ -55,6 +53,12 @@ public interface Pdh extends StdCallLibrary {
5553
/** Maximum full counter log name length. */
5654
int PDH_MAX_DATASOURCE_PATH = 1024;
5755

56+
int PDH_MORE_DATA = 0x800007D2;
57+
int PDH_INVALID_ARGUMENT = 0xC0000BBD;
58+
int PDH_MEMORY_ALLOCATION_FAILURE = 0xC0000BBB;
59+
int PDH_CSTATUS_NO_MACHINE = 0x800007D0;
60+
int PDH_CSTATUS_NO_OBJECT = 0xC0000BB8;
61+
5862
/* TODO
5963
* LPVOID CALLBACK AllocateMemory(_In_ SIZE_T AllocSize,_In_ LPVOID pContext)
6064
* void CALLBACK FreeMemory(LPVOID pBuffer,LPVOID pContext)

contrib/platform/src/com/sun/jna/platform/win32/PdhUtil.java

+116-87
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.sun.jna.Native;
3131
import com.sun.jna.platform.win32.WinDef.DWORD;
3232
import com.sun.jna.platform.win32.WinDef.DWORDByReference;
33+
import java.util.Collections;
3334

3435
/**
3536
* Pdh utility API.
@@ -61,16 +62,23 @@ public abstract class PdhUtil {
6162
public static String PdhLookupPerfNameByIndex(String szMachineName, int dwNameIndex) {
6263
// Call once to get required buffer size
6364
DWORDByReference pcchNameBufferSize = new DWORDByReference(new DWORD(0));
64-
Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, null, pcchNameBufferSize);
65-
65+
int result = Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, null, pcchNameBufferSize);
66+
if(result != WinError.ERROR_SUCCESS && result != Pdh.PDH_MORE_DATA) {
67+
throw new PdhException(result);
68+
}
69+
6670
// Can't allocate 0 memory
6771
if (pcchNameBufferSize.getValue().intValue() < 1) {
6872
return "";
6973
}
7074
// Allocate buffer and call again
7175
Memory mem = new Memory(pcchNameBufferSize.getValue().intValue() * CHAR_TO_BYTES);
72-
Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, mem, pcchNameBufferSize);
76+
result = Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, mem, pcchNameBufferSize);
7377

78+
if(result != WinError.ERROR_SUCCESS) {
79+
throw new PdhException(result);
80+
}
81+
7482
// Convert buffer to Java String
7583
if (CHAR_TO_BYTES == 1) {
7684
return mem.getString(0);
@@ -113,9 +121,8 @@ public static int PdhLookupPerfIndexByEnglishName(String szNameBuffer) {
113121

114122
/**
115123
* Utility method to call Pdh's PdhEnumObjectItems that allocates the
116-
* required memory for the mszCounterList parameter based on the type
117-
* mapping used, calls to PdhEnumObjectItems, and returns the received lists
118-
* of strings.
124+
* required memory for the lists parameters based on the type mapping used,
125+
* calls to PdhEnumObjectItems, and returns the received lists of strings.
119126
*
120127
* @param szDataSource
121128
* String that specifies the name of the log file used to
@@ -137,113 +144,135 @@ public static int PdhLookupPerfIndexByEnglishName(String szNameBuffer) {
137144
* returned.
138145
* @return Returns a List of Strings of the counters for the object.
139146
*/
140-
public static List<String> PdhEnumObjectItemCounters(String szDataSource, String szMachineName, String szObjectName,
147+
public static PdhEnumObjectItems PdhEnumObjectItems(String szDataSource, String szMachineName, String szObjectName,
141148
int dwDetailLevel) {
142149
List<String> counters = new ArrayList<String>();
150+
List<String> instances = new ArrayList<String>();
143151

144152
// Call once to get string lengths
145153
DWORDByReference pcchCounterListLength = new DWORDByReference(new DWORD(0));
146154
DWORDByReference pcchInstanceListLength = new DWORDByReference(new DWORD(0));
147-
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength, null,
155+
int result = Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength, null,
148156
pcchInstanceListLength, dwDetailLevel, 0);
157+
if(result != WinError.ERROR_SUCCESS && result != Pdh.PDH_MORE_DATA) {
158+
throw new PdhException(result);
159+
}
149160

150-
// Can't allocate 0 memory if no counters
151-
if (pcchCounterListLength.getValue().intValue() < 1) {
152-
return counters;
161+
Memory mszCounterList = null;
162+
Memory mszInstanceList = null;
163+
164+
if (pcchCounterListLength.getValue().intValue() > 0) {
165+
mszCounterList = new Memory(pcchCounterListLength.getValue().intValue() * CHAR_TO_BYTES);
166+
}
167+
168+
if (pcchInstanceListLength.getValue().intValue() > 0) {
169+
mszInstanceList = new Memory(pcchInstanceListLength.getValue().intValue() * CHAR_TO_BYTES);
170+
}
171+
172+
result = Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList,
173+
pcchCounterListLength, mszInstanceList, pcchInstanceListLength, dwDetailLevel, 0);
174+
175+
if(result != WinError.ERROR_SUCCESS) {
176+
throw new PdhException(result);
153177
}
154-
// Allocate memory and call again to populate strings
155-
Memory mszCounterList = new Memory(pcchCounterListLength.getValue().intValue() * CHAR_TO_BYTES);
156-
// Don't need the instances
157-
pcchInstanceListLength.getValue().setValue(0);
158-
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList,
159-
pcchCounterListLength, null, pcchInstanceListLength, dwDetailLevel, 0);
160178

161179
// Fetch counters
162-
int offset = 0;
163-
while (offset < mszCounterList.size()) {
164-
String s = null;
165-
if (CHAR_TO_BYTES == 1) {
166-
s = mszCounterList.getString(offset);
167-
} else {
168-
s = mszCounterList.getWideString(offset);
180+
if (mszCounterList != null) {
181+
int offset = 0;
182+
while (offset < mszCounterList.size()) {
183+
String s = null;
184+
if (CHAR_TO_BYTES == 1) {
185+
s = mszCounterList.getString(offset);
186+
} else {
187+
s = mszCounterList.getWideString(offset);
188+
}
189+
// list ends with double null
190+
if (s.isEmpty()) {
191+
break;
192+
}
193+
counters.add(s);
194+
// Increment for string + null terminator
195+
offset += (s.length() + 1) * CHAR_TO_BYTES;
169196
}
170-
// list ends with double null
171-
if (s.isEmpty()) {
172-
break;
197+
}
198+
199+
if(mszInstanceList != null) {
200+
int offset = 0;
201+
while (offset < mszInstanceList.size()) {
202+
String s = null;
203+
if (CHAR_TO_BYTES == 1) {
204+
s = mszInstanceList.getString(offset);
205+
} else {
206+
s = mszInstanceList.getWideString(offset);
207+
}
208+
// list ends with double null
209+
if (s.isEmpty()) {
210+
break;
211+
}
212+
instances.add(s);
213+
// Increment for string + null terminator
214+
offset += (s.length() + 1) * CHAR_TO_BYTES;
173215
}
174-
counters.add(s);
175-
// Increment for string + null terminator
176-
offset += (s.length() + 1) * CHAR_TO_BYTES;
177216
}
178217

179-
return counters;
218+
return new PdhEnumObjectItems(counters, instances);
180219
}
181220

221+
182222
/**
183-
* Utility method to call Pdh's PdhEnumObjectItems that allocates the
184-
* required memory for the mszInstanceList parameters based on the type
185-
* mapping used, calls to PdhEnumObjectItems, and returns the received lists
186-
* of strings.
187-
*
188-
* @param szDataSource
189-
* String that specifies the name of the log file used to
190-
* enumerate the counter and instance names. If NULL, the
191-
* function uses the computer specified in the szMachineName
192-
* parameter to enumerate the names.
193-
* @param szMachineName
194-
* String that specifies the name of the computer that contains
195-
* the counter and instance names that you want to enumerate.
196-
* Include the leading slashes in the computer name, for example,
197-
* \\computername. If the szDataSource parameter is NULL, you can
198-
* set szMachineName to NULL to specify the local computer.
199-
* @param szObjectName
200-
* String that specifies the name of the object whose counter and
201-
* instance names you want to enumerate.
202-
* @param dwDetailLevel
203-
* Detail level of the performance items to return. All items
204-
* that are of the specified detail level or less will be
205-
* returned.
206-
* @return Returns a Lists of Strings of the instances of the object.
223+
* Holder Object for PdhEnumObjectsItems. The embedded lists are modifiable
224+
* lists and can be accessed through the {@link #getCounters()} and
225+
* {@link #getInstances()} accessors.
207226
*/
208-
public static List<String> PdhEnumObjectItemInstances(String szDataSource, String szMachineName,
209-
String szObjectName, int dwDetailLevel) {
210-
List<String> instances = new ArrayList<String>();
227+
public static class PdhEnumObjectItems {
228+
private final List<String> counters;
229+
private final List<String> instances;
211230

212-
// Call once to get string lengths
213-
DWORDByReference pcchCounterListLength = new DWORDByReference(new DWORD(0));
214-
DWORDByReference pcchInstanceListLength = new DWORDByReference(new DWORD(0));
215-
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength, null,
216-
pcchInstanceListLength, dwDetailLevel, 0);
231+
public PdhEnumObjectItems(List<String> counters, List<String> instances) {
232+
this.counters = copyAndEmptyListForNullList(counters);
233+
this.instances = copyAndEmptyListForNullList(instances);
234+
}
235+
236+
/**
237+
* @return the embedded counters list, all calls to this function receive
238+
* the same list and thus share modifications
239+
*/
240+
public List<String> getCounters() {
241+
return counters;
242+
}
217243

218-
// Can't allocate 0 memory if no instances
219-
if (pcchInstanceListLength.getValue().intValue() < 1) {
244+
/**
245+
* @return the embedded instances list, all calls to this function receive
246+
* the same list and thus share modifications
247+
*/
248+
public List<String> getInstances() {
220249
return instances;
221250
}
222-
// Allocate memory and call again to populate strings
223-
Memory mszInstanceList = new Memory(pcchInstanceListLength.getValue().intValue() * CHAR_TO_BYTES);
224-
// Don't need the counters
225-
pcchCounterListLength.getValue().setValue(0);
226-
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength,
227-
mszInstanceList, pcchInstanceListLength, dwDetailLevel, 0);
228-
229-
// Fetch instances
230-
int offset = 0;
231-
while (offset < mszInstanceList.size()) {
232-
String s = null;
233-
if (CHAR_TO_BYTES == 1) {
234-
s = mszInstanceList.getString(offset);
251+
252+
private List<String> copyAndEmptyListForNullList (List<String> inputList) {
253+
if(inputList == null) {
254+
return new ArrayList<String>();
235255
} else {
236-
s = mszInstanceList.getWideString(offset);
237-
}
238-
// list ends with double null
239-
if (s.isEmpty()) {
240-
break;
256+
return new ArrayList<String>(inputList);
241257
}
242-
instances.add(s);
243-
// Increment for string + null terminator
244-
offset += (s.length() + 1) * CHAR_TO_BYTES;
245258
}
246259

247-
return instances;
260+
@Override
261+
public String toString() {
262+
return "PdhEnumObjectItems{" + "counters=" + counters + ", instances=" + instances + '}';
263+
}
264+
}
265+
266+
public static final class PdhException extends RuntimeException {
267+
private final int errorCode;
268+
269+
public PdhException(int errorCode) {
270+
super(String.format("Pdh call failed with error code 0x%08X", errorCode));
271+
this.errorCode = errorCode;
272+
}
273+
274+
public int getErrorCode() {
275+
return errorCode;
276+
}
248277
}
249278
}

contrib/platform/test/com/sun/jna/platform/win32/PdhTest.java

+20-8
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
import java.util.Collection;
1717
import java.util.HashMap;
1818
import java.util.LinkedList;
19-
import java.util.List;
2019
import java.util.Map;
2120

2221
import org.junit.Test;
2322

2423
import com.sun.jna.Native;
2524
import com.sun.jna.platform.win32.Pdh.PDH_COUNTER_PATH_ELEMENTS;
2625
import com.sun.jna.platform.win32.Pdh.PDH_RAW_COUNTER;
26+
import com.sun.jna.platform.win32.PdhUtil.PdhEnumObjectItems;
27+
import com.sun.jna.platform.win32.PdhUtil.PdhException;
2728
import com.sun.jna.platform.win32.WinDef.DWORD;
2829
import com.sun.jna.platform.win32.WinDef.DWORDByReference;
2930
import com.sun.jna.platform.win32.WinNT.HANDLE;
@@ -182,21 +183,32 @@ public void testLookupPerfIndex() {
182183
@Test
183184
public void testEnumObjectItems() {
184185
if (AbstractWin32TestSupport.isEnglishLocale) {
185-
String processorStr = "Processor";
186+
String processorStr = "Processor";
186187
String processorTimeStr = "% Processor Time";
187188

188189
// Fetch the counter and instance names
189-
List<String> instances = PdhUtil.PdhEnumObjectItemInstances(null, null, processorStr, 100);
190+
PdhEnumObjectItems objects = PdhUtil.PdhEnumObjectItems(null, null, processorStr, 100);
190191

191-
// Should have at least one processor and total instance
192-
assertTrue(instances.contains("0"));
193-
assertTrue(instances.contains("_Total"));
192+
assertTrue(objects.getInstances().contains("0"));
193+
assertTrue(objects.getInstances().contains("_Total"));
194194

195195
// Should have a "% Processor Time" counter
196-
List<String> counters = PdhUtil.PdhEnumObjectItemCounters(null, null, processorStr, 100);
197-
assertTrue(counters.contains(processorTimeStr));
196+
assertTrue(objects.getCounters().contains(processorTimeStr));
198197
} else {
199198
System.err.println("testEnumObjectItems test can only be run with english locale.");
200199
}
201200
}
201+
202+
@Test
203+
public void testEnumObjectItemsNonExisting() {
204+
Exception caughtException = null;
205+
try {
206+
PdhUtil.PdhEnumObjectItems(null, null, "Unknown counter", 100);
207+
} catch (Exception ex) {
208+
caughtException = ex;
209+
}
210+
assertNotNull(caughtException);
211+
assertTrue(caughtException instanceof PdhException);
212+
assertEquals(Pdh.PDH_CSTATUS_NO_OBJECT, ((PdhException) caughtException).getErrorCode());
213+
}
202214
}

0 commit comments

Comments
 (0)