Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Features
* [#980](https://github.com/java-native-access/jna/issues/980): Added `PERF_OBJECT_TYPE`, `PERF_COUNTER_BLOCK`, and `PERF_COUNTER_DEFINITION` to `c.s.j.platform.win32.WinPerf` and added `Pointer` constructors to ``PERF_INSTANCE_DEFINITION` and `PERF_DATA_BLOCK` - [@dbwiddis](https://github.com/dbwiddis).
* [#981](https://github.com/java-native-access/jna/issues/981): Added `WTS_PROCESS_INFO_EX`, `WTSEnumerateProcessesEx`, and `WTSFreeMemoryEx` to `c.s.j.platform.win32.Wtsapi32` - [@dbwiddis](https://github.com/dbwiddis).
* [#983](https://github.com/java-native-access/jna/issues/983): Added `GetIfEntry`, `GetIfEntry2`, and `GetNetworkParams` and supporting structures `MIB_IFROW`, `MIB_IF_ROW2`, and `FIXED_INFO` to `c.s.j.platform.win32.IPHlpAPI.java` - [@dbwiddis](https://github.com/dbwiddis).
* [#988](https://github.com/java-native-access/jna/issues/988): Added `PdhLookupPerfIndexByEnglishName` to `c.s.j.platform.win32.PdhUtil` - [@dbwiddis](https://github.com/dbwiddis).

Bug Fixes
---------
Expand Down
91 changes: 70 additions & 21 deletions contrib/platform/src/com/sun/jna/platform/win32/PdhUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
* @author widdis[at]gmail[dot]com
*/
public abstract class PdhUtil {
private static final int CHAR_TO_BYTES = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;

// This REG_MULTI_SZ value in HKLM provides English counters regardless of
// the current locale setting
private static final String ENGLISH_COUNTER_KEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009";
private static final String ENGLISH_COUNTER_VALUE = "Counter";

/**
* Utility method to call Pdh's PdhLookupPerfNameByIndex that allocates the
Expand All @@ -53,24 +59,58 @@ public abstract class PdhUtil {
* @return Returns the name of the performance object or counter.
*/
public static String PdhLookupPerfNameByIndex(String szMachineName, int dwNameIndex) {
int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;

// Call once to get required buffer size
DWORDByReference pcchNameBufferSize = new DWORDByReference(new DWORD(0));
Pdh.INSTANCE.PdhLookupPerfNameByIndex(null, dwNameIndex, null, pcchNameBufferSize);
Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, null, pcchNameBufferSize);

// Can't allocate 0 memory
if (pcchNameBufferSize.getValue().intValue() < 1) {
return "";
}
// Allocate buffer and call again
Memory mem = new Memory(pcchNameBufferSize.getValue().intValue() * charToBytes);
Pdh.INSTANCE.PdhLookupPerfNameByIndex(null, dwNameIndex, mem, pcchNameBufferSize);
Memory mem = new Memory(pcchNameBufferSize.getValue().intValue() * CHAR_TO_BYTES);
Pdh.INSTANCE.PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, mem, pcchNameBufferSize);

// Convert buffer to Java String
if (charToBytes == 1) {
if (CHAR_TO_BYTES == 1) {
return mem.getString(0);
} else {
return mem.getWideString(0);
}
}

/**
* Utility method similar to Pdh's PdhLookupPerfIndexByName that returns the
* counter index corresponding to the specified counter name in English.
* Uses the registry on the local machine to find the index in the English
* locale, regardless of the current language setting on the machine.
*
* @param szNameBuffer
* The English name of the performance counter
* @return The counter's index if it exists, or 0 otherwise.
*/
public static int PdhLookupPerfIndexByEnglishName(String szNameBuffer) {
// Look up list of english names and ids
String[] counters = Advapi32Util.registryGetStringArray(WinReg.HKEY_LOCAL_MACHINE, ENGLISH_COUNTER_KEY,
ENGLISH_COUNTER_VALUE);
// Array contains alternating index/name pairs
// {"1", "1847", "2", "System", "4", "Memory", ... }
// Get position of name in the array (odd index), return parsed value of
// previous even index
for (int i = 1; i < counters.length; i += 2) {
if (counters[i].equals(szNameBuffer)) {
try {
return Integer.parseInt(counters[i - 1]);
} catch (NumberFormatException e) {
// Unexpected but handle anyway
return 0;
}
}
}
// Didn't find the String
return 0;
}

/**
* Utility method to call Pdh's PdhEnumObjectItems that allocates the
* required memory for the mszCounterList parameter based on the type
Expand Down Expand Up @@ -99,26 +139,30 @@ public static String PdhLookupPerfNameByIndex(String szMachineName, int dwNameIn
*/
public static List<String> PdhEnumObjectItemCounters(String szDataSource, String szMachineName, String szObjectName,
int dwDetailLevel) {
int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;
List<String> counters = new ArrayList<String>();

// Call once to get string lengths
DWORDByReference pcchCounterListLength = new DWORDByReference(new DWORD(0));
DWORDByReference pcchInstanceListLength = new DWORDByReference(new DWORD(0));
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength, null,
pcchInstanceListLength, dwDetailLevel, 0);

// Can't allocate 0 memory if no counters
if (pcchCounterListLength.getValue().intValue() < 1) {
return counters;
}
// Allocate memory and call again to populate strings
Memory mszCounterList = new Memory(pcchCounterListLength.getValue().intValue() * charToBytes);
Memory mszInstanceList = new Memory(pcchInstanceListLength.getValue().intValue() * charToBytes);
Memory mszCounterList = new Memory(pcchCounterListLength.getValue().intValue() * CHAR_TO_BYTES);
// Don't need the instances
pcchInstanceListLength.getValue().setValue(0);
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList,
pcchCounterListLength, mszInstanceList, pcchInstanceListLength, dwDetailLevel, 0);
pcchCounterListLength, null, pcchInstanceListLength, dwDetailLevel, 0);

// Fetch counters
List<String> counters = new ArrayList<String>();
int offset = 0;
while (offset < mszCounterList.size()) {
String s = null;
if (charToBytes == 1) {
if (CHAR_TO_BYTES == 1) {
s = mszCounterList.getString(offset);
} else {
s = mszCounterList.getWideString(offset);
Expand All @@ -129,7 +173,7 @@ public static List<String> PdhEnumObjectItemCounters(String szDataSource, String
}
counters.add(s);
// Increment for string + null terminator
offset += (s.length() + 1) * charToBytes;
offset += (s.length() + 1) * CHAR_TO_BYTES;
}

return counters;
Expand Down Expand Up @@ -163,25 +207,30 @@ public static List<String> PdhEnumObjectItemCounters(String szDataSource, String
*/
public static List<String> PdhEnumObjectItemInstances(String szDataSource, String szMachineName,
String szObjectName, int dwDetailLevel) {
int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;
List<String> instances = new ArrayList<String>();

// Call once to get string lengths
DWORDByReference pcchCounterListLength = new DWORDByReference(new DWORD(0));
DWORDByReference pcchInstanceListLength = new DWORDByReference(new DWORD(0));
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength, null,
pcchInstanceListLength, dwDetailLevel, 0);

// Can't allocate 0 memory if no instances
if (pcchInstanceListLength.getValue().intValue() < 1) {
return instances;
}
// Allocate memory and call again to populate strings
Memory mszCounterList = new Memory(pcchCounterListLength.getValue().intValue() * charToBytes);
Memory mszInstanceList = new Memory(pcchInstanceListLength.getValue().intValue() * charToBytes);
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList,
pcchCounterListLength, mszInstanceList, pcchInstanceListLength, dwDetailLevel, 0);
Memory mszInstanceList = new Memory(pcchInstanceListLength.getValue().intValue() * CHAR_TO_BYTES);
// Don't need the counters
pcchCounterListLength.getValue().setValue(0);
Pdh.INSTANCE.PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, null, pcchCounterListLength,
mszInstanceList, pcchInstanceListLength, dwDetailLevel, 0);

List<String> instances = new ArrayList<String>();
// Fetch instances
int offset = 0;
while (offset < mszInstanceList.size()) {
String s = null;
if (charToBytes == 1) {
if (CHAR_TO_BYTES == 1) {
s = mszInstanceList.getString(offset);
} else {
s = mszInstanceList.getWideString(offset);
Expand All @@ -192,7 +241,7 @@ public static List<String> PdhEnumObjectItemInstances(String szDataSource, Strin
}
instances.add(s);
// Increment for string + null terminator
offset += (s.length() + 1) * charToBytes;
offset += (s.length() + 1) * CHAR_TO_BYTES;
}

return instances;
Expand Down
3 changes: 3 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/PdhTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ public void testLookupPerfIndex() {
DWORDByReference pdwIndex = new DWORDByReference();
Pdh.INSTANCE.PdhLookupPerfIndexByName(null, testStr, pdwIndex);
assertEquals(processorIndex, pdwIndex.getValue().intValue());

// Test English name to index
assertEquals(processorIndex, PdhUtil.PdhLookupPerfIndexByEnglishName(processorStr));
}

@Test
Expand Down