Skip to content

Commit

Permalink
Add Cfgmgr32 functions for navigating device tree (java-native-access…
Browse files Browse the repository at this point in the history
  • Loading branch information
dbwiddis authored and matthiasblaesing committed Jul 22, 2018
1 parent 57a9dd0 commit c7419af
Show file tree
Hide file tree
Showing 4 changed files with 382 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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).
* [#984](https://github.com/java-native-access/jna/issues/984): Added `CM_Locate_DevNode`, `CM_Get_Parent`, `CM_Get_Child`, `CM_Get_Sibling`, `CM_Get_Device_ID`, and `CM_Get_Device_ID_Size` to `c.s.j.platform.win32.Cfgmgr32.java` and a `c.s.j.platform.win32.Cfgmgr32Util` class for `CM_Get_Device_ID` - [@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
192 changes: 192 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform.win32;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.W32APIOptions;

/**
* Windows Cfgmgr32.
*
* @author widdis[at]gmail[dot]com
*/
public interface Cfgmgr32 extends Library {
Cfgmgr32 INSTANCE = Native.load("Cfgmgr32", Cfgmgr32.class, W32APIOptions.DEFAULT_OPTIONS);

public final static int CR_SUCCESS = 0;
public final static int CR_BUFFER_SMALL = 0x0000001A;

public final static int CM_LOCATE_DEVNODE_NORMAL = 0;
public final static int CM_LOCATE_DEVNODE_PHANTOM = 1;
public final static int CM_LOCATE_DEVNODE_CANCELREMOVE = 2;
public final static int CM_LOCATE_DEVNODE_NOVALIDATION = 4;
public final static int CM_LOCATE_DEVNODE_BITS = 7;

/**
* The CM_Locate_DevNode function obtains a device instance handle to the
* device node that is associated with a specified device instance ID on the
* local machine.
*
* @param pdnDevInst
* A pointer to a device instance handle that CM_Locate_DevNode
* retrieves. The retrieved handle is bound to the local machine.
* @param pDeviceID
* A pointer to a NULL-terminated string representing a device
* instance ID. If this value is NULL, or if it points to a
* zero-length string, the function retrieves a device instance
* handle to the device at the root of the device tree. *
* @param ulFlags
* A variable of ULONG type that supplies one of the following
* flag values that apply if the caller supplies a device
* instance identifier: CM_LOCATE_DEVNODE_NORMAL,
* CM_LOCATE_DEVNODE_PHANTOM, CM_LOCATE_DEVNODE_CANCELREMOVE, or
* CM_LOCATE_DEVNODE_NOVALIDATION
* @return If the operation succeeds, CM_Locate_DevNode returns CR_SUCCESS.
* Otherwise, the function returns one of the CR_Xxx error codes
* that are defined in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_locate_devnodea">
* CM_Locate_DevNode</A>
*/
int CM_Locate_DevNode(IntByReference pdnDevInst, String pDeviceID, int ulFlags);

/**
* The CM_Get_Parent function obtains a device instance handle to the parent
* node of a specified device node (devnode) in the local machine's device
* tree.
*
* @param pdnDevInst
* Caller-supplied pointer to the device instance handle to the
* parent node that this function retrieves. The retrieved handle
* is bound to the local machine.
* @param dnDevInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @param ulFlags
* Not used, must be zero.
* @return If the operation succeeds, the function returns CR_SUCCESS.
* Otherwise, it returns one of the CR_-prefixed error codes defined
* in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_get_parent">
* CM_Get_Parent</A>
*/
int CM_Get_Parent(IntByReference pdnDevInst, int dnDevInst, int ulFlags);

/**
* The CM_Get_Child function is used to retrieve a device instance handle to
* the first child node of a specified device node (devnode) in the local
* machine's device tree.
*
* @param pdnDevInst
* Caller-supplied pointer to the device instance handle to the
* child node that this function retrieves. The retrieved handle
* is bound to the local machine.
* @param dnDevInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @param ulFlags
* Not used, must be zero.
* @return If the operation succeeds, the function returns CR_SUCCESS.
* Otherwise, it returns one of the CR_-prefixed error codes defined
* in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_get_child">
* CM_Get_Child</A>
*/
int CM_Get_Child(IntByReference pdnDevInst, int dnDevInst, int ulFlags);

/**
* The CM_Get_Sibling function obtains a device instance handle to the next
* sibling node of a specified device node (devnode) in the local machine's
* device tree.
*
* @param pdnDevInst
* Caller-supplied pointer to the device instance handle to the
* sibling node that this function retrieves. The retrieved
* handle is bound to the local machine.
* @param dnDevInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @param ulFlags
* Not used, must be zero.
* @return If the operation succeeds, the function returns CR_SUCCESS.
* Otherwise, it returns one of the CR_-prefixed error codes defined
* in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_get_sibling">
* CM_Get_Sibling</A>
*/
int CM_Get_Sibling(IntByReference pdnDevInst, int dnDevInst, int ulFlags);

/**
* The CM_Get_Device_ID function retrieves the device instance ID for a
* specified device instance on the local machine.
*
* @param devInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @param Buffer
* Address of a buffer to receive a device instance ID string.
* The required buffer size can be obtained by calling
* CM_Get_Device_ID_Size, then incrementing the received value to
* allow room for the string's terminating NULL.
* @param BufferLen
* Caller-supplied length, in characters, of the buffer specified
* by Buffer.
* @param ulFlags
* Not used, must be zero.
* @return If the operation succeeds, the function returns CR_SUCCESS.
* Otherwise, it returns one of the CR_-prefixed error codes defined
* in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_get_device_idw">
* CM_Get_Device_ID</A>
*/
int CM_Get_Device_ID(int devInst, Pointer Buffer, int BufferLen, int ulFlags);

/**
* The CM_Get_Device_ID_Size function retrieves the buffer size required to
* hold a device instance ID for a device instance on the local machine.
*
* @param pulLen
* Receives a value representing the required buffer size, in
* characters.
* @param dnDevInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @param ulFlags
* Not used, must be zero.
* @return If the operation succeeds, the function returns CR_SUCCESS.
* Otherwise, it returns one of the CR_-prefixed error codes defined
* in Cfgmgr32.h.
* @see <A HREF=
* "https://docs.microsoft.com/en-us/windows/desktop/api/cfgmgr32/nf-cfgmgr32-cm_get_device_id_size">
* CM_Get_Device_ID_Size</A>
*/
int CM_Get_Device_ID_Size(IntByReference pulLen, int dnDevInst, int ulFlags);
}
99 changes: 99 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform.win32;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;

/**
* Cfgmgr32 utility API.
*
* @author widdis[at]gmail[dot]com
*/
public abstract class Cfgmgr32Util {
@SuppressWarnings("serial")
public static class Cfgmgr32Exception extends RuntimeException {
private final int errorCode;

public Cfgmgr32Exception(int errorCode) {
this.errorCode = errorCode;
}

public int getErrorCode() {
return errorCode;
}
}

/**
* Utility method to call Cfgmgr32's CM_Get_Device_ID that allocates the
* required memory for the Buffer parameter based on the type mapping used,
* calls to CM_Get_Device_ID, and returns the received string.
*
* @param devInst
* Caller-supplied device instance handle that is bound to the
* local machine.
* @return The device instance ID string.
* @throws Cfgmgr32Exception
*/
public static String CM_Get_Device_ID(int devInst) throws Cfgmgr32Exception {
int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;

// Get Device ID character count
IntByReference pulLen = new IntByReference();
int ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID_Size(pulLen, devInst, 0);
if (ret != Cfgmgr32.CR_SUCCESS) {
throw new Cfgmgr32Exception(ret);
}

// Add one to length to allow null terminator
Memory buffer = new Memory((pulLen.getValue() + 1) * charToBytes);
// Zero the buffer (including the extra character)
buffer.clear();
// Fetch the buffer specifying only the current length
ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, pulLen.getValue(), 0);
// In the unlikely event the device id changes this might not be big
// enough, try again. This happens rarely enough one retry should be
// sufficient.
if (ret == Cfgmgr32.CR_BUFFER_SMALL) {
ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID_Size(pulLen, devInst, 0);
if (ret != Cfgmgr32.CR_SUCCESS) {
throw new Cfgmgr32Exception(ret);
}
buffer = new Memory((pulLen.getValue() + 1) * charToBytes);
buffer.clear();
ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, pulLen.getValue(), 0);
}
// If we still aren't successful throw an exception
if (ret != Cfgmgr32.CR_SUCCESS) {
throw new Cfgmgr32Exception(ret);
}
// Convert buffer to Java String
if (charToBytes == 1) {
return buffer.getString(0);
} else {
return buffer.getWideString(0);
}
}
}
90 changes: 90 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna.platform.win32;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.UnsupportedEncodingException;

import org.junit.Test;

import com.sun.jna.ptr.IntByReference;

/**
* Tests methods in Cfgmgr32
*
* @author widdis[at]gmail[dot]com
*/
public class Cfgmgr32Test {
/**
* Tests CM_Locate_DevNode, CM_Get_Parent, CM_Get_Child, CM_Get_Sibling
*/
@Test
public void testDevNode() {
// Fetch the root node
IntByReference outputNode = new IntByReference();
assertEquals(Cfgmgr32.CR_SUCCESS,
Cfgmgr32.INSTANCE.CM_Locate_DevNode(outputNode, null, Cfgmgr32.CM_LOCATE_DEVNODE_NORMAL));
// Get first child
int rootNode = outputNode.getValue();
int inputNode = rootNode;
assertEquals(Cfgmgr32.CR_SUCCESS, Cfgmgr32.INSTANCE.CM_Get_Child(outputNode, inputNode, 0));
// Iterate this child and its siblings
do {
inputNode = outputNode.getValue();
// Get parent, confirm it matches root
assertEquals(Cfgmgr32.CR_SUCCESS, Cfgmgr32.INSTANCE.CM_Get_Parent(outputNode, inputNode, 0));
assertEquals(rootNode, outputNode.getValue());
} while (Cfgmgr32.CR_SUCCESS == Cfgmgr32.INSTANCE.CM_Get_Sibling(outputNode, inputNode, 0));
}

/**
* Tests CM_Locate_DevNode, CM_Get_Device_ID_Size, CM_Get_Device_ID
*
* @throws UnsupportedEncodingException
*/
@Test
public void testDeviceID() {
// Fetch the root node
IntByReference outputNode = new IntByReference();
assertEquals(Cfgmgr32.CR_SUCCESS,
Cfgmgr32.INSTANCE.CM_Locate_DevNode(outputNode, null, Cfgmgr32.CM_LOCATE_DEVNODE_NORMAL));
int rootNode = outputNode.getValue();

// Get Device ID character count
IntByReference pulLen = new IntByReference();
Cfgmgr32.INSTANCE.CM_Get_Device_ID_Size(pulLen, rootNode, 0);
assertTrue(pulLen.getValue() > 0);

// Get Device ID from util
String deviceId = Cfgmgr32Util.CM_Get_Device_ID(rootNode);
assertEquals(pulLen.getValue(), deviceId.length());

// Look up node from device ID
assertEquals(Cfgmgr32.CR_SUCCESS,
Cfgmgr32.INSTANCE.CM_Locate_DevNode(outputNode, deviceId, Cfgmgr32.CM_LOCATE_DEVNODE_NORMAL));
assertEquals(rootNode, outputNode.getValue());
}
}

0 comments on commit c7419af

Please sign in to comment.