Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Cfgmgr32 functions for navigating device tree #984

Merged
merged 5 commits into from
Jul 22, 2018
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 @@ -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());
}
}