diff --git a/contrib/platform/src/com/sun/jna/platform/linux/Udev.java b/contrib/platform/src/com/sun/jna/platform/linux/Udev.java
index 23db457cfa..a9dd758a2b 100644
--- a/contrib/platform/src/com/sun/jna/platform/linux/Udev.java
+++ b/contrib/platform/src/com/sun/jna/platform/linux/Udev.java
@@ -51,7 +51,7 @@ class UdevContext extends PointerType {
*
* @return this object, unmodified.
*/
- UdevContext ref() {
+ public UdevContext ref() {
return INSTANCE.udev_ref(this);
}
diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
index 5e9b26605b..8aa38f601c 100644
--- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
+++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Daniel Widdis
+ * Copyright (c) 2019, 2021 Daniel Widdis
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
@@ -303,7 +303,7 @@ public boolean booleanValue() {
*
* CFArray is “toll-free bridged” with its Cocoa Foundation counterpart,
* {@code NSArray}. Therefore, in a method where you see an {@code NSArray *}
- * parameter, you can pass in a {@link #CFArrayRef}.
+ * parameter, you can pass in a {@code CFArrayRef} .
*/
class CFArrayRef extends CFTypeRef {
public CFArrayRef() {
@@ -487,14 +487,20 @@ public static CFStringRef createCFString(String s) {
* failed.
*/
public String stringValue() {
+ // Get number of characters (UTF-16 code pairs)
+ // Code points > 0xffff will have 2 characters per Unicode character
CFIndex length = INSTANCE.CFStringGetLength(this);
if (length.longValue() == 0) {
return "";
}
+ // Calculate maximum possible size in UTF8 bytes
+ // This will be 3 x length
CFIndex maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
if (maxSize.intValue() == kCFNotFound) {
throw new StringIndexOutOfBoundsException("CFString maximum number of bytes exceeds LONG_MAX.");
}
+ // Increment size by 1 for a null byte
+ maxSize.setValue(maxSize.longValue() + 1);
Memory buf = new Memory(maxSize.longValue());
if (0 != INSTANCE.CFStringGetCString(this, buf, maxSize, kCFStringEncodingUTF8)) {
return buf.getString(0, "UTF8");
diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java
index c09b0693b8..38b56f72e2 100644
--- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java
+++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java
@@ -763,7 +763,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, C
* @param connect
* An {@code io_connect_t} handle is returned on success, to be used
* with the IOConnectXXX APIs. It should be destroyed with
- * {@link IOServiceClose}.
+ * {@link #IOServiceClose}.
* @return A return code generated by {@code IOService::newUserClient}.
*/
int IOServiceOpen(IOService service, int owningTask, int type, PointerByReference connect);
@@ -828,7 +828,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, C
*
* Caller should NOT release the returned CFDictionary - it will be
* released as part of the {@link CFTypeRef} returned by
- * {@link IOPSCopyPowerSourcesInfo}.
+ * {@link #IOPSCopyPowerSourcesInfo}.
*/
CFDictionaryRef IOPSGetPowerSourceDescription(CFTypeRef blob, CFTypeRef ps);
diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java
index d11396b630..04e5459ddc 100644
--- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java
+++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java
@@ -623,10 +623,10 @@ class Timezone extends Structure {
* The sysctl() function retrieves system information and allows processes with
* appropriate privileges to set system information. The information available
* from sysctl() consists of integers, strings, and tables.
- *
+ *
* The state is described using a "Management Information Base" (MIB) style
* name, listed in name, which is a namelen length array of integers.
- *
+ *
* The information is copied into the buffer specified by oldp. The size of the
* buffer is given by the location specified by oldlenp before the call, and
* that location gives the amount of data copied after a successful call and
@@ -635,32 +635,41 @@ class Timezone extends Structure {
* as much data as fits in the buffer provided and returns with the error code
* ENOMEM. If the old value is not desired, oldp and oldlenp should be set to
* NULL.
- *
+ *
* The size of the available data can be determined by calling sysctl() with the
* NULL argument for oldp. The size of the available data will be returned in
* the location pointed to by oldlenp. For some operations, the amount of space
* may change often. For these operations, the system attempts to round up so
* that the returned size is large enough for a call to return the data shortly
* thereafter.
- *
+ *
* To set a new value, newp is set to point to a buffer of length newlen from
* which the requested value is to be taken. If a new value is not to be set,
* newp should be set to NULL and newlen set to 0.
*
* @param name
- * MIB array of integers
+ * a Management Information Base (MIB) array of integers
* @param namelen
- * length of the MIB array
+ * the length of the array in {@code name}
* @param oldp
- * Information retrieved
+ * A buffer to hold the information retrieved
* @param oldlenp
- * Size of information retrieved
+ * Size of the buffer, a pointer to a {@link com.sun.jna.platform.unix.LibCAPI.size_t} value
* @param newp
- * Information to be written
+ * To set a new value, a buffer of information to be written. May be
+ * null if no value is to be set.
* @param newlen
- * Size of information to be written
+ * Size of the information to be written. May be 0 if no value is to
+ * be set.
* @return 0 on success; sets errno on failure
*/
+ int sysctl(int[] name, int namelen, Pointer oldp, size_t.ByReference oldlenp, Pointer newp, size_t newlen);
+
+ /**
+ * @deprecated Use
+ * {@link #sysctl(int[], int, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t.ByReference, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t)}
+ */
+ @Deprecated
int sysctl(int[] name, int namelen, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen);
/**
@@ -671,15 +680,24 @@ class Timezone extends Structure {
* @param name
* ASCII representation of the MIB name
* @param oldp
- * Information retrieved
+ * A buffer to hold the information retrieved
* @param oldlenp
- * Size of information retrieved
+ * Size of the buffer, a pointer to a {@link com.sun.jna.platform.unix.LibCAPI.size_t} value
* @param newp
- * Information to be written
+ * To set a new value, a buffer of information to be written. May be
+ * null if no value is to be set.
* @param newlen
- * Size of information to be written
+ * Size of the information to be written. May be 0 if no value is to
+ * be set.
* @return 0 on success; sets errno on failure
*/
+ int sysctlbyname(String name, Pointer oldp, size_t.ByReference oldlenp, Pointer newp, size_t newlen);
+
+ /**
+ * @deprecated Use
+ * {@link #sysctlbyname(String, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t.ByReference, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t)}
+ */
+ @Deprecated
int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen);
/**
@@ -705,12 +723,18 @@ class Timezone extends Structure {
* ASCII representation of the name
* @param mibp
* Integer array containing the corresponding name vector.
- * @param size
+ * @param sizep
* On input, number of elements in the returned array; on output, the
* number of entries copied.
* @return 0 on success; sets errno on failure
*/
- int sysctlnametomib(String name, Pointer mibp, IntByReference size);
+ int sysctlnametomib(String name, Pointer mibp, size_t.ByReference sizep);
+
+ /**
+ * @deprecated Use {@link #sysctlnametomib(String, Pointer, com.sun.jna.platform.unix.LibCAPI.size_t.ByReference)}
+ */
+ @Deprecated
+ int sysctlnametomib(String name, Pointer mibp, IntByReference sizep);
/**
* The host_processor_info function returns information about processors.
diff --git a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java
index c2a9b9485e..934ee17602 100644
--- a/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java
+++ b/contrib/platform/src/com/sun/jna/platform/unix/LibCAPI.java
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015 Goldstein Lyor, All Rights Reserved
+/* Copyright (c) 2015 Goldstein Lyor, 2021 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
@@ -43,6 +43,41 @@ class size_t extends IntegerType {
private static final long serialVersionUID = 1L;
+ public static class ByReference extends com.sun.jna.ptr.ByReference {
+ public ByReference() {
+ this(0);
+ }
+
+ public ByReference(long value) {
+ this(new size_t(value));
+ }
+
+ public ByReference(size_t value) {
+ super(Native.SIZE_T_SIZE);
+ setValue(value);
+ }
+
+ public void setValue(long value) {
+ setValue(new size_t(value));
+ }
+
+ public void setValue(size_t value) {
+ if (Native.SIZE_T_SIZE > 4) {
+ getPointer().setLong(0, value.longValue());
+ } else {
+ getPointer().setInt(0, value.intValue());
+ }
+ }
+
+ public long longValue() {
+ return Native.SIZE_T_SIZE > 4 ? getPointer().getLong(0) : getPointer().getInt(0);
+ }
+
+ public size_t getValue() {
+ return new size_t(longValue());
+ }
+ }
+
public size_t() {
this(0);
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32.java b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32.java
index 6f6087e4a2..e9c1b23f43 100755
--- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32.java
@@ -1361,6 +1361,149 @@ int RegGetValue(HKEY hkey, String lpSubKey, String lpValue,
int dwFlags, IntByReference pdwType, byte[] pvData,
IntByReference pcbData);
+ /**
+ * Notifies the caller about changes to the attributes or contents of a
+ * specified registry key.
+ *
+ * @param hKey A handle to an open registry key. This handle is
+ * returned by the {@code RegCreateKeyEx} or
+ * {@code RegOpenKeyEx} function. It can also be one of
+ * the following predefined
+ * keys. The key must have been opened with the
+ * {@code KEY_NOTIFY} access right. For more information,
+ * see Registry
+ * Key Security and Access Rights.
+ * @param bWatchSubtree If this parameter is {@code TRUE}, the function reports
+ * changes in the specified key and its subkeys. If the
+ * parameter is {@code FALSE}, the function reports
+ * changes only in the specified key.
+ * @param dwNotifyFilter A value that indicates the changes that should be
+ * reported. This parameter can be one or more of the
+ * following values.
+ *
+ *
+ *
+ * Value |
+ * Meaning |
+ *
+ *
+ *
+ * REG_NOTIFY_CHANGE_NAME
+ * 0x00000001L |
+ * Notify the caller if a subkey is added or deleted.
+ * |
+ *
+ *
+ * REG_NOTIFY_CHANGE_ATTRIBUTES
+ * 0x00000002L |
+ * Notify the caller of changes to the attributes of
+ * the key, such as the security descriptor
+ * information. |
+ *
+ *
+ * REG_NOTIFY_CHANGE_LAST_SET
+ * 0x00000004L |
+ * Notify the caller of changes to a value of the key.
+ * This can include adding or deleting a value, or
+ * changing an existing value. |
+ *
+ *
+ * REG_NOTIFY_CHANGE_SECURITY
+ * 0x00000008L |
+ * Notify the caller of changes to the security
+ * descriptor of the key. |
+ *
+ *
+ * REG_NOTIFY_THREAD_AGNOSTIC
+ * 0x10000000L |
+ * Indicates that the lifetime of the registration
+ * must not be tied to the lifetime of the thread issuing
+ * the RegNotifyChangeKeyValue call.
+ * Note: This flag value is only supported in
+ * Windows 8 and later. |
+ *
+ *
+ *
+ * @param hEvent A handle to an event. If the {@code fAsynchronous}
+ * parameter is {@code TRUE}, the function returns
+ * immediately and changes are reported by signaling this
+ * event. If {@code fAsynchronous} is {@code FALSE},
+ * {@code hEvent} is ignored.
+ * @param fAsynchronous If this parameter is {@code TRUE}, the function returns
+ * immediately and reports changes by signaling the
+ * specified event. If this parameter is {@code FALSE},
+ * the function does not return until a change has
+ * occurred. If {@code hEvent} does not specify a valid
+ * event, the {@code fAsynchronous} parameter cannot be
+ * {@code TRUE}.
+ * @return If the function succeeds, the return value is {@code ERROR_SUCCESS}.
+ * If the function fails, the return value is a nonzero error code
+ * defined in Winerror.h. You can use the {@code FormatMessage} function
+ * with the {@code FORMAT_MESSAGE_FROM_SYSTEM} flag to get a generic
+ * description of the error.
+ *
+ * Remarks: This function detects a single change. After the
+ * caller receives a notification event, it should call the function
+ * again to receive the next notification.
+ *
+ * This function cannot be used to detect changes to the registry that
+ * result from using the RegRestoreKey function.
+ *
+ * If the specified key is closed, the event is signaled. This means
+ * that an application should not depend on the key being open after
+ * returning from a wait operation on the event.
+ *
+ * The {@code REG_NOTIFY_THREAD_AGNOSTIC} flag introduced in Windows 8
+ * enables the use of {@code RegNotifyChangeKeyValue} for ThreadPool
+ * threads.
+ *
+ * If the thread that called {@code RegNotifyChangeKeyValue} exits, the
+ * event is signaled. To continue to monitor additional changes in the
+ * value of the key, call {@code RegNotifyChangeKeyValue} again from
+ * another thread.
+ *
+ * With the exception of {@code RegNotifyChangeKeyValue} calls with
+ * {@code REG_NOTIFY_THREAD_AGNOSTIC} set, this function must be called
+ * on persistent threads. If the calling thread is from a thread pool
+ * and it is not persistent, the event is signaled every time the thread
+ * terminates, not just when there is a registry change. To ensure
+ * accurate results, run the thread pool work in a persistent thread by
+ * using the {@code SetThreadpoolCallbackPersistent} function, or create
+ * your own thread using the CreateThread function. (For the original
+ * thread pool API, specify {@code WT_EXECUTEINPERSISTENTTHREAD} using
+ * the QueueUserWorkItem function.)
+ *
+ * This function should not be called multiple times with the same value
+ * for the hKey but different values for the {@code bWatchSubtree} and
+ * {@code dwNotifyFilter} parameters. The function will succeed but the
+ * changes will be ignored. To change the watch parameters, you must
+ * first close the key handle by calling {@code RegCloseKey}, reopen the
+ * key handle by calling {@code RegOpenKeyEx}, and then call
+ * {@code RegNotifyChangeKeyValue} with the new parameters.
+ *
+ * Each time a process calls {@code RegNotifyChangeKeyValue} with the
+ * same set of parameters, it establishes another wait operation,
+ * creating a resource leak. Therefore, check that you are not calling
+ * {@code RegNotifyChangeKeyValue} with the same parameters until the
+ * previous wait operation has completed.
+ *
+ * To monitor registry operations in more detail, see Registry.
+ *
+ * Windows XP/2000: When {@code RegNotifyChangeKeyValue} is called for a
+ * particular key handle, change notifications occur for as long as the
+ * key handle is valid. This causes a second call to
+ * {@code RegNotifyChangeKeyValue} to return immediately, if any changes
+ * occur in the interim between the first and second calls. If the
+ * function is being used asynchronously, the passed event handle will
+ * be signaled immediately if any changes occur in the interim.
+ *
+ */
+ int RegNotifyChangeKeyValue(HKEY hKey, boolean bWatchSubtree, int dwNotifyFilter, HANDLE hEvent,
+ boolean fAsynchronous);
+
/**
* Retrieves a registered handle to the specified event log.
*
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
index df4d06f795..73e773bcbc 100755
--- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
@@ -961,6 +961,19 @@ public static String[] registryGetStringArray(HKEY hKey, String value) {
&& rc != W32Errors.ERROR_INSUFFICIENT_BUFFER) {
throw new Win32Exception(rc);
}
+ return regMultiSzBufferToStringArray(data);
+ }
+
+ /**
+ * Convert the null-delimited buffer of strings returned from registry values of
+ * type {@link WinNT#REG_MULTI_SZ} to an array of strings.
+ *
+ * @param data
+ * A buffer containing strings delimited by a null character, ending
+ * with two null characters.
+ * @return An array of strings corresponding to the strings in the buffer.
+ */
+ static String[] regMultiSzBufferToStringArray(Memory data) {
ArrayList result = new ArrayList();
int offset = 0;
while (offset < data.size()) {
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java
index 89c859734e..3693ccef92 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java
@@ -37,11 +37,9 @@
import com.sun.jna.platform.win32.OleAuto;
import com.sun.jna.platform.win32.OleAuto.DISPPARAMS;
import com.sun.jna.platform.win32.Variant.VARIANT;
-import com.sun.jna.platform.win32.Variant.VariantArg;
import com.sun.jna.platform.win32.WTypes;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.LCID;
-import com.sun.jna.platform.win32.WinDef.UINT;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
@@ -187,8 +185,7 @@ protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult,
COMUtils.checkRC(hr);
- return this
- .oleMethod(nType, pvResult, iDispatch, pdispID.getValue(), pArgs);
+ return this.oleMethod(nType, pvResult, pdispID.getValue(), pArgs);
}
protected HRESULT oleMethod(int nType, VARIANT.ByReference pvResult,
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMLateBindingObject.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMLateBindingObject.java
index e85107f32f..43ab72ce48 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMLateBindingObject.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMLateBindingObject.java
@@ -397,6 +397,7 @@ protected void invokeNoReply(String methodName, COMLateBindingObject comObject,
/**
* @deprecated Use {@link #invokeNoReply(java.lang.String, com.sun.jna.platform.win32.Variant.VARIANT)}
*/
+ @Deprecated
protected void invokeNoReply(String methodName,
COMLateBindingObject comObject, VARIANT arg) {
this.oleMethod(OleAuto.DISPATCH_METHOD, null, comObject.getIDispatch(),
@@ -565,7 +566,12 @@ protected void setProperty(String propertyName, short value) {
* the value
*/
protected void setProperty(String propertyName, String value) {
- this.oleMethod(OleAuto.DISPATCH_PROPERTYPUT, null, propertyName, new VARIANT(value));
+ VARIANT wrappedValue = new VARIANT(value);
+ try {
+ this.oleMethod(OleAuto.DISPATCH_PROPERTYPUT, null, propertyName, wrappedValue);
+ } finally {
+ OleAuto.INSTANCE.VariantClear(wrappedValue);
+ }
}
/**
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32.java b/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32.java
index 17cd4b5759..18cc018c74 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32.java
@@ -37,14 +37,112 @@
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;
+ int CR_SUCCESS = 0;
+ int CR_DEFAULT = 0x00000001;
+ int CR_OUT_OF_MEMORY = 0x00000002;
+ int CR_INVALID_POINTER = 0x00000003;
+ int CR_INVALID_FLAG = 0x00000004;
+ int CR_INVALID_DEVNODE = 0x00000005;
+ int CR_INVALID_DEVINST = CR_INVALID_DEVNODE;
+ int CR_INVALID_RES_DES = 0x00000006;
+ int CR_INVALID_LOG_CONF = 0x00000007;
+ int CR_INVALID_ARBITRATOR = 0x00000008;
+ int CR_INVALID_NODELIST = 0x00000009;
+ int CR_DEVNODE_HAS_REQS = 0x0000000A;
+ int CR_DEVINST_HAS_REQS = CR_DEVNODE_HAS_REQS;
+ int CR_INVALID_RESOURCEID = 0x0000000B;
+ int CR_DLVXD_NOT_FOUND = 0x0000000C; // WIN 95 ONLY
+ int CR_NO_SUCH_DEVNODE = 0x0000000D;
+ int CR_NO_SUCH_DEVINST = CR_NO_SUCH_DEVNODE;
+ int CR_NO_MORE_LOG_CONF = 0x0000000E;
+ int CR_NO_MORE_RES_DES = 0x0000000F;
+ int CR_ALREADY_SUCH_DEVNODE = 0x00000010;
+ int CR_ALREADY_SUCH_DEVINST = CR_ALREADY_SUCH_DEVNODE;
+ int CR_INVALID_RANGE_LIST = 0x00000011;
+ int CR_INVALID_RANGE = 0x00000012;
+ int CR_FAILURE = 0x00000013;
+ int CR_NO_SUCH_LOGICAL_DEV = 0x00000014;
+ int CR_CREATE_BLOCKED = 0x00000015;
+ int CR_NOT_SYSTEM_VM = 0x00000016; // WIN 95 ONLY
+ int CR_REMOVE_VETOED = 0x00000017;
+ int CR_APM_VETOED = 0x00000018;
+ int CR_INVALID_LOAD_TYPE = 0x00000019;
+ int CR_BUFFER_SMALL = 0x0000001A;
+ int CR_NO_ARBITRATOR = 0x0000001B;
+ int CR_NO_REGISTRY_HANDLE = 0x0000001C;
+ int CR_REGISTRY_ERROR = 0x0000001D;
+ int CR_INVALID_DEVICE_ID = 0x0000001E;
+ int CR_INVALID_DATA = 0x0000001F;
+ int CR_INVALID_API = 0x00000020;
+ int CR_DEVLOADER_NOT_READY = 0x00000021;
+ int CR_NEED_RESTART = 0x00000022;
+ int CR_NO_MORE_HW_PROFILES = 0x00000023;
+ int CR_DEVICE_NOT_THERE = 0x00000024;
+ int CR_NO_SUCH_VALUE = 0x00000025;
+ int CR_WRONG_TYPE = 0x00000026;
+ int CR_INVALID_PRIORITY = 0x00000027;
+ int CR_NOT_DISABLEABLE = 0x00000028;
+ int CR_FREE_RESOURCES = 0x00000029;
+ int CR_QUERY_VETOED = 0x0000002A;
+ int CR_CANT_SHARE_IRQ = 0x0000002B;
+ int CR_NO_DEPENDENT = 0x0000002C;
+ int CR_SAME_RESOURCES = 0x0000002D;
+ int CR_NO_SUCH_REGISTRY_KEY = 0x0000002E;
+ int CR_INVALID_MACHINENAME = 0x0000002F; // NT ONLY
+ int CR_REMOTE_COMM_FAILURE = 0x00000030; // NT ONLY
+ int CR_MACHINE_UNAVAILABLE = 0x00000031; // NT ONLY
+ int CR_NO_CM_SERVICES = 0x00000032; // NT ONLY
+ int CR_ACCESS_DENIED = 0x00000033; // NT ONLY
+ int CR_CALL_NOT_IMPLEMENTED = 0x00000034;
+ int CR_INVALID_PROPERTY = 0x00000035;
+ int CR_DEVICE_INTERFACE_ACTIVE = 0x00000036;
+ int CR_NO_SUCH_DEVICE_INTERFACE = 0x00000037;
+ int CR_INVALID_REFERENCE_STRING = 0x00000038;
+ int CR_INVALID_CONFLICT_LIST = 0x00000039;
+ int CR_INVALID_INDEX = 0x0000003A;
+ int CR_INVALID_STRUCTURE_SIZE = 0x0000003B;
+ int NUM_CR_RESULTS = 0x0000003C;
- 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;
+ int CM_LOCATE_DEVNODE_NORMAL = 0;
+ int CM_LOCATE_DEVNODE_PHANTOM = 1;
+ int CM_LOCATE_DEVNODE_CANCELREMOVE = 2;
+ int CM_LOCATE_DEVNODE_NOVALIDATION = 4;
+ int CM_LOCATE_DEVNODE_BITS = 7;
+
+ int CM_DRP_DEVICEDESC = 0x00000001; // DeviceDesc REG_SZ property (RW)
+ int CM_DRP_HARDWAREID = 0x00000002; // HardwareID REG_MULTI_SZ property (RW)
+ int CM_DRP_COMPATIBLEIDS = 0x00000003; // CompatibleIDs REG_MULTI_SZ property (RW)
+ int CM_DRP_SERVICE = 0x00000005; // Service REG_SZ property (RW)
+ int CM_DRP_CLASS = 0x00000008; // Class REG_SZ property (RW)
+ int CM_DRP_CLASSGUID = 0x00000009; // ClassGUID REG_SZ property (RW)
+ int CM_DRP_DRIVER = 0x0000000A; // Driver REG_SZ property (RW)
+ int CM_DRP_CONFIGFLAGS = 0x0000000B; // ConfigFlags REG_DWORD property (RW)
+ int CM_DRP_MFG = 0x0000000C; // Mfg REG_SZ property (RW)
+ int CM_DRP_FRIENDLYNAME = 0x0000000D; // FriendlyName REG_SZ property (RW)
+ int CM_DRP_LOCATION_INFORMATION = 0x0000000E; // LocationInformation REG_SZ property (RW)
+ int CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000F; // PhysicalDeviceObjectName REG_SZ property (R)
+ int CM_DRP_CAPABILITIES = 0x00000010; // Capabilities REG_DWORD property (R)
+ int CM_DRP_UI_NUMBER = 0x00000011; // UiNumber REG_DWORD property (R)
+ int CM_DRP_UPPERFILTERS = 0x00000012; // UpperFilters REG_MULTI_SZ property (RW)
+ int CM_DRP_LOWERFILTERS = 0x00000013; // LowerFilters REG_MULTI_SZ property (RW)
+ int CM_DRP_BUSTYPEGUID = 0x00000014; // Bus Type Guid, GUID, (R)
+ int CM_DRP_LEGACYBUSTYPE = 0x00000015; // Legacy bus type, INTERFACE_TYPE, (R)
+ int CM_DRP_BUSNUMBER = 0x00000016; // Bus Number, DWORD, (R)
+ int CM_DRP_ENUMERATOR_NAME = 0x00000017; // Enumerator Name REG_SZ property (R)
+ int CM_DRP_SECURITY = 0x00000018; // Security - Device override (RW)
+ int CM_DRP_SECURITY_SDS = 0x00000019; // Security - Device override (RW)
+ int CM_DRP_DEVTYPE = 0x0000001A; // Device Type - Device override (RW)
+ int CM_DRP_EXCLUSIVE = 0x0000001B; // Exclusivity - Device override (RW)
+ int CM_DRP_CHARACTERISTICS = 0x0000001C; // Characteristics - Device Override (RW)
+ int CM_DRP_ADDRESS = 0x0000001D; // Device Address (R)
+ int CM_DRP_UI_NUMBER_DESC_FORMAT = 0x0000001E; // UINumberDescFormat REG_SZ property (RW)
+ int CM_DRP_DEVICE_POWER_DATA = 0x0000001F; // CM_POWER_DATA REG_BINARY property (R)
+ int CM_DRP_REMOVAL_POLICY = 0x00000020; // CM_DEVICE_REMOVAL_POLICY REG_DWORD (R)
+ int CM_DRP_REMOVAL_POLICY_HW_DEFAULT = 0x00000021; // CM_DRP_REMOVAL_POLICY_HW_DEFAULT REG_DWORD (R)
+ int CM_DRP_REMOVAL_POLICY_OVERRIDE = 0x00000022; // CM_DRP_REMOVAL_POLICY_OVERRIDE REG_DWORD (RW)
+ int CM_DRP_INSTALL_STATE = 0x00000023; // CM_DRP_INSTALL_STATE REG_DWORD (R)
+ int CM_DRP_LOCATION_PATHS = 0x00000024; // CM_DRP_LOCATION_PATHS REG_MULTI_SZ (R)
+ int CM_DRP_BASE_CONTAINERID = 0x00000025; // Base ContainerID REG_SZ property (R)
/**
* The CM_Locate_DevNode function obtains a device instance handle to the
@@ -189,4 +287,43 @@ public interface Cfgmgr32 extends Library {
* CM_Get_Device_ID_Size
*/
int CM_Get_Device_ID_Size(IntByReference pulLen, int dnDevInst, int ulFlags);
+
+ /**
+ * The CM_Get_DevNode_Registry_Property function retrieves a specified device
+ * property from the registry.
+ *
+ * @param dnDevInst
+ * A caller-supplied device instance handle that is bound to the
+ * local machine.
+ * @param ulProperty
+ * A {@code CM_DRP_}-prefixed constant value that identifies the
+ * device property to be obtained from the registry. These constants
+ * are defined in Cfgmgr32.h.
+ * @param pulRegDataType
+ * Optional, can be {@code null}. A pointer to a location that
+ * receives the registry data type, specified as a
+ * {@code REG_}-prefixed constant defined in Winnt.h.
+ * @param buffer
+ * Optional, can be {@code null}. A pointer to a caller-supplied
+ * buffer that receives the requested device property. If this value
+ * is {@code null}, the function supplies only the length of the
+ * requested data in the address pointed to by {@code pulLength}.
+ * @param pulLength
+ * A pointer to a {@code ULONG} variable into which the function
+ * stores the length, in bytes, of the requested device property.
+ *
+ * If the Buffer parameter is set to {@code null}, the ULONG variable
+ * must be set to zero.
+ *
+ * If the Buffer parameter is not set to {@code null}, the
+ * {@code ULONG} variable must be set to the length, in bytes, of the
+ * caller-supplied buffer.
+ * @param ulFlags
+ * Not used, must be zero.
+ * @return If the operation succeeds, the function returns {@code CR_SUCCESS}.
+ * Otherwise, it returns one of the {@code CR_}-prefixed error codes
+ * that are defined in Cfgmgr32.h.
+ */
+ int CM_Get_DevNode_Registry_Property(int dnDevInst, int ulProperty, IntByReference pulRegDataType, Pointer buffer,
+ IntByReference pulLength, int ulFlags);
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java
index 664ecbd053..2dfa89c3d6 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
+/* Copyright (c) 2018, 2021 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
@@ -26,11 +26,10 @@
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.win32.W32APITypeMapper;
/**
* Cfgmgr32 utility API.
- *
- * @author widdis[at]gmail[dot]com
*/
public abstract class Cfgmgr32Util {
@SuppressWarnings("serial")
@@ -44,16 +43,21 @@ public Cfgmgr32Exception(int errorCode) {
public int getErrorCode() {
return errorCode;
}
+
+ @Override
+ public String toString() {
+ return super.toString() + String.format(" [errorCode: 0x%08x]", errorCode);
+ }
}
/**
- * Utility method to call Cfgmgr32's CM_Get_Device_ID that allocates the
+ * Utility method to call Cfgmgr32's CM_Get_Device_ID_Size, 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.
+ * Caller-supplied device instance handle that is bound to the local
+ * machine.
* @return The device instance ID string.
* @throws Cfgmgr32Exception
*/
@@ -96,4 +100,96 @@ public static String CM_Get_Device_ID(int devInst) throws Cfgmgr32Exception {
return buffer.getWideString(0);
}
}
+
+ /**
+ * Utility method to call Cfgmgr32's CM_Get_DevNode_Registry_Property that
+ * allocates the required memory for the Buffer parameter, and returns values of
+ * the appropriate type.
+ *
+ * @param devInst
+ * Caller-supplied device instance handle that is bound to the local
+ * machine.
+ * @param ulProperty
+ * A {@code CM_DRP_}-prefixed constant value that identifies the
+ * device property to be obtained from the registry. These constants
+ * are defined in Cfgmgr32.h.
+ * @return An {@link Object} containing the specified registry property for the
+ * device.
+ *
+ * If the property is of type {@link WinNT#REG_SZ}, a
+ * {@link java.lang.String} is returned.
+ *
+ * If the property is of type {@link WinNT#REG_MULTI_SZ}, an array of
+ * {@link java.lang.String} is returned.
+ *
+ * If the property is of type {@link WinNT#REG_DWORD}, an
+ * {@link java.lang.Integer} is returned.
+ *
+ * If the property is of type {@link WinNT#REG_BINARY}, an array of
+ * {@link java.lang.Byte} is returned.
+ *
+ * If no value exists for this property (error
+ * {@link Cfgmgr32#CR_NO_SUCH_VALUE}), returns {@code null}.
+ * @throws Cfgmgr32Exception
+ * on any errors other than {@link Cfgmgr32#CR_NO_SUCH_VALUE}
+ */
+ public static Object CM_Get_DevNode_Registry_Property(int devInst, int ulProperty) throws Cfgmgr32Exception {
+
+ // Get byte count and type
+ IntByReference size = new IntByReference();
+ IntByReference type = new IntByReference();
+ int ret = Cfgmgr32.INSTANCE.CM_Get_DevNode_Registry_Property(devInst, ulProperty, type, null, size, 0);
+ // If this property does not exist return null
+ if (ret == Cfgmgr32.CR_NO_SUCH_VALUE) {
+ return null;
+ }
+ // If successful in retrieving type and size, should fail with CR_BUFFER_SMALL,
+ // otherwise throw an exception
+ if (ret != Cfgmgr32.CR_BUFFER_SMALL) {
+ throw new Cfgmgr32Exception(ret);
+ }
+
+ // It is possible to have a valid value with registry data type, but 0 size.
+ // Leave the memory buffer null in that case
+ Memory buffer = null;
+ if (size.getValue() > 0) {
+ buffer = new Memory(size.getValue());
+ ret = Cfgmgr32.INSTANCE.CM_Get_DevNode_Registry_Property(devInst, ulProperty, type, buffer, size, 0);
+ if (ret != Cfgmgr32.CR_SUCCESS) {
+ throw new Cfgmgr32Exception(ret);
+ }
+ }
+
+ // Get the appropriate type of data from the buffer
+ switch (type.getValue()) {
+ case WinNT.REG_SZ:
+ // Convert buffer to Java String
+ if (buffer == null) {
+ return "";
+ }
+ return W32APITypeMapper.DEFAULT == W32APITypeMapper.UNICODE ? buffer.getWideString(0)
+ : buffer.getString(0);
+ case WinNT.REG_MULTI_SZ:
+ // Convert buffer to String Array
+ if (buffer == null) {
+ return new String[0];
+ }
+ return Advapi32Util.regMultiSzBufferToStringArray(buffer);
+ case WinNT.REG_DWORD:
+ // Convert buffer to int
+ if (buffer == null) {
+ return 0;
+ }
+ return buffer.getInt(0);
+ case WinNT.REG_NONE:
+ return null;
+ default:
+ // Intended for WinNT.REG_BINARY but safe default for any data
+ if (buffer == null) {
+ return new byte[0];
+ }
+ // Convert buffer to array of bytes
+ return buffer.getByteArray(0, (int) buffer.size());
+ }
+ }
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java
index ba38b52643..89a866fcf2 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Crypt32Util.java
@@ -23,6 +23,8 @@
*/
package com.sun.jna.platform.win32;
+import java.util.Arrays;
+
import com.sun.jna.Pointer;
import com.sun.jna.Memory;
import com.sun.jna.Native;
@@ -80,17 +82,44 @@ public static byte[] cryptProtectData(byte[] data, byte[] entropy, int flags,
DATA_BLOB pDataIn = new DATA_BLOB(data);
DATA_BLOB pDataProtected = new DATA_BLOB();
DATA_BLOB pEntropy = (entropy == null) ? null : new DATA_BLOB(entropy);
+ Win32Exception err = null;
+ byte[] protectedData = null;
try {
if (! Crypt32.INSTANCE.CryptProtectData(pDataIn, description,
pEntropy, null, prompt, flags, pDataProtected)) {
- throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ err = new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ } else {
+ protectedData = pDataProtected.getData();
}
- return pDataProtected.getData();
} finally {
+ if (pDataIn.pbData != null) {
+ pDataIn.pbData.clear(pDataIn.cbData);
+ }
+ if (pEntropy != null && pEntropy.pbData != null) {
+ pEntropy.pbData.clear(pEntropy.cbData);
+ }
if (pDataProtected.pbData != null) {
- Kernel32Util.freeLocalMemory(pDataProtected.pbData);
+ pDataProtected.pbData.clear(pDataProtected.cbData);
+ try {
+ Kernel32Util.freeLocalMemory(pDataProtected.pbData);
+ } catch(Win32Exception e) {
+ if (err == null) {
+ err = e;
+ } else {
+ err.addSuppressedReflected(e);
+ }
+ }
}
}
+
+ if (err != null) {
+ if (protectedData != null) {
+ Arrays.fill(protectedData, (byte) 0);
+ }
+ throw err;
+ }
+
+ return protectedData;
}
/**
@@ -135,18 +164,24 @@ public static byte[] cryptUnprotectData(byte[] data, byte[] entropy, int flags,
DATA_BLOB pDataIn = new DATA_BLOB(data);
DATA_BLOB pDataUnprotected = new DATA_BLOB();
DATA_BLOB pEntropy = (entropy == null) ? null : new DATA_BLOB(entropy);
- PointerByReference pDescription = new PointerByReference();
Win32Exception err = null;
byte[] unProtectedData = null;
try {
- if (! Crypt32.INSTANCE.CryptUnprotectData(pDataIn, pDescription,
+ if (! Crypt32.INSTANCE.CryptUnprotectData(pDataIn, null,
pEntropy, null, prompt, flags, pDataUnprotected)) {
err = new Win32Exception(Kernel32.INSTANCE.GetLastError());
} else {
unProtectedData = pDataUnprotected.getData();
}
} finally {
+ if (pDataIn.pbData != null) {
+ pDataIn.pbData.clear(pDataIn.cbData);
+ }
+ if (pEntropy != null && pEntropy.pbData != null) {
+ pEntropy.pbData.clear(pEntropy.cbData);
+ }
if (pDataUnprotected.pbData != null) {
+ pDataUnprotected.pbData.clear(pDataUnprotected.cbData);
try {
Kernel32Util.freeLocalMemory(pDataUnprotected.pbData);
} catch(Win32Exception e) {
@@ -157,21 +192,12 @@ public static byte[] cryptUnprotectData(byte[] data, byte[] entropy, int flags,
}
}
}
-
- if (pDescription.getValue() != null) {
- try {
- Kernel32Util.freeLocalMemory(pDescription.getValue());
- } catch(Win32Exception e) {
- if (err == null) {
- err = e;
- } else {
- err.addSuppressedReflected(e);
- }
- }
- }
}
if (err != null) {
+ if (unProtectedData != null) {
+ Arrays.fill(unProtectedData, (byte) 0);
+ }
throw err;
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
index 4a396c209d..45a7c3a3d6 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
@@ -2787,7 +2787,7 @@ boolean SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION lpTimeZone,
/**
* @deprecated Use
- * {@link #CreateRemoteThread(com.sun.jna.platform.win32.WinNT.HANDLE, com.sun.jna.platform.win32.WinBase.SECURITY_ATTRIBUTES, int, com.sun.jna.Pointer, com.sun.jna.Pointer, int, com.sun.jna.platform.win32.WinDef.DWORDByReference)
+ * {@link #CreateRemoteThread(com.sun.jna.platform.win32.WinNT.HANDLE, com.sun.jna.platform.win32.WinBase.SECURITY_ATTRIBUTES, int, com.sun.jna.Pointer, com.sun.jna.Pointer, int, com.sun.jna.platform.win32.WinDef.DWORDByReference)}
*/
@Deprecated
HANDLE CreateRemoteThread(HANDLE hProcess, WinBase.SECURITY_ATTRIBUTES lpThreadAttributes, int dwStackSize, FOREIGN_THREAD_START_ROUTINE lpStartAddress, Pointer lpParameter, DWORD dwCreationFlags, Pointer lpThreadId);
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java
index 193afb9865..efa5bacf45 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/PsapiUtil.java
@@ -71,11 +71,11 @@ public static int[] enumProcesses() {
* @throws Win32Exception in case an error occurs
* @see MSDN
*/
- public static String GetProcessImageFileName(HANDLE process) {
+ public static String GetProcessImageFileName(HANDLE hProcess) {
int size = 2048;
while (true) {
final char[] filePath = new char[size];
- int length = Psapi.INSTANCE.GetProcessImageFileName(process,
+ int length = Psapi.INSTANCE.GetProcessImageFileName(hProcess,
filePath, filePath.length);
if(length == 0) {
if(Native.getLastError() != WinError.ERROR_INSUFFICIENT_BUFFER) {
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java
index a52812be03..22d96b5260 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java
@@ -24,8 +24,10 @@
package com.sun.jna.platform.win32;
import com.sun.jna.Native;
+import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Guid.GUID;
+import com.sun.jna.platform.win32.WTypes.LPWSTR;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HICON;
import com.sun.jna.platform.win32.WinDef.HWND;
@@ -33,6 +35,7 @@
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HRESULT;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
@@ -409,5 +412,28 @@ public interface Shell32 extends ShellAPI, StdCallLibrary {
*/
HRESULT SetCurrentProcessExplicitAppUserModelID(WString appID);
+ /**
+ * Parses a Unicode command line string and returns an array of pointers to the
+ * command line arguments, along with a count of such arguments, in a way that
+ * is similar to the standard C run-time {@code argv} and {@code argc} values.
+ *
+ * @param lpCmdLine
+ * A Unicode string that contains the full command line. If this
+ * parameter is an empty string the function returns the path to the
+ * current executable file.
+ * @param pNumArgs
+ * Pointer to an {@code int} that receives the number of array
+ * elements returned, similar to {@code argc}.
+ * @return A pointer to an array of {@link LPWSTR} values, similar to
+ * {@code argv}. If the function fails, the return value is
+ * {@code null}. To get extended error information, call
+ * {@link Kernel32#GetLastError}.
+ * CommandLineToArgvW allocates a block of contiguous memory for
+ * pointers to the argument strings, and for the argument strings
+ * themselves; the calling application must free the memory used by the
+ * argument list when it is no longer needed. To free the memory, use a
+ * single call to the {@link Kernel32#LocalFree} function.
+ */
+ Pointer CommandLineToArgvW(WString lpCmdLine, IntByReference pNumArgs);
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java
index b33163235f..a177394833 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java
@@ -24,11 +24,14 @@
package com.sun.jna.platform.win32;
import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.WString;
import com.sun.jna.platform.win32.Guid.GUID;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HRESULT;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
/**
@@ -112,4 +115,28 @@ public static final String getSpecialFolderPath(final int csidl, final boolean c
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
return Native.toString(pszPath);
}
+
+ /**
+ * Parses a command line string and returns an array of Strings of the command
+ * line arguments.
+ *
+ * @param cmdLine
+ * A string that contains the full command line. If this parameter is
+ * an empty string the function returns the path to the current
+ * executable file.
+ * @return An array of strings, similar to {@code argv}.
+ */
+ public static final String[] CommandLineToArgv(String cmdLine) {
+ WString cl = new WString(cmdLine);
+ IntByReference nargs = new IntByReference();
+ Pointer strArr = Shell32.INSTANCE.CommandLineToArgvW(cl, nargs);
+ if (strArr != null) {
+ try {
+ return strArr.getWideStringArray(0, nargs.getValue());
+ } finally {
+ Kernel32.INSTANCE.LocalFree(strArr);
+ }
+ }
+ throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ }
}
\ No newline at end of file
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/User32.java b/contrib/platform/src/com/sun/jna/platform/win32/User32.java
index 8179155716..a1e43aada1 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/User32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/User32.java
@@ -359,6 +359,18 @@ public interface User32 extends StdCallLibrary, WinUser, WinNT {
*/
boolean EnumThreadWindows(int dwThreadId, WNDENUMPROC lpEnumFunc, Pointer data);
+
+ /**
+ * Brings the specified window to the top of the Z order. If the window is a top-level window, it is activated. If
+ * the window is a child window, the top-level parent window associated with the child window is activated.
+ *
+ * @param hWnd
+ * A handle to the window to bring to the top of the Z order.
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.
+ * To get extended error information, call GetLastError.
+ */
+ boolean BringWindowToTop(HWND hWnd);
+
/**
* The FlashWindowEx function flashes the specified window. It does not
* change the active state of the window.
@@ -2262,6 +2274,30 @@ LRESULT SendMessageTimeout(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam,
*/
HWND GetAncestor(HWND hwnd, int gaFlags);
+ /**
+ * Retrieves a handle to the specified window's parent or owner.
+ *
+ * To retrieve a handle to a specified ancestor, use the GetAncestor function.
+ *
+ * @param hwnd
+ * A handle to the window whose parent window handle is to be retrieved.
+ * @return Type: HWND
+ * If the window is a child window, the return value is a handle to the
+ * parent window. If the window is a top-level window with the WS_POPUP style,
+ * the return value is a handle to the owner window.
+ *
+ * If the function fails, the return value is NULL. To get extended error
+ * information, call GetLastError.
+ *
+ * This function typically fails for one of the following reasons:
+ *
+ * - The window is a top-level window that is unowned or does not have
+ * the WS_POPUP style
+ *
- The owner window has WS_POPUP style
+ *
+ */
+ HWND GetParent(HWND hwnd);
+
/**
* Retrieves the position of the mouse cursor, in screen coordinates.
*
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java b/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java
index a893e8bb83..a382d25940 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WTypes.java
@@ -108,7 +108,7 @@ public BSTR() {
* Instantiate a BSTR from a pointer. The user is responsible for allocating and
* releasing memory for the {@link BSTR}, most commonly using
* {@link OleAuto#SysAllocString(String)} and
- * {@link OleAuto#SysFreeString(BSTR)}
+ * {@link OleAuto#SysFreeString(com.sun.jna.platform.win32.WTypes.BSTR)}
*
* @param pointer
* A pointer to the string
@@ -119,7 +119,7 @@ public BSTR(Pointer pointer) {
/**
* @deprecated Use {@link OleAuto#SysAllocString(String)} and
- * {@link OleAuto#SysFreeString(BSTR)}
+ * {@link OleAuto#SysFreeString(com.sun.jna.platform.win32.WTypes.BSTR)}
*/
@Deprecated
public BSTR(String value) {
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java b/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java
index e860466dd8..a8cbce3e19 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinCrypt.java
@@ -72,10 +72,19 @@ public DATA_BLOB(Pointer memory) {
}
public DATA_BLOB(byte [] data) {
- pbData = new Memory(data.length);
- pbData.write(0, data, 0, data.length);
- cbData = data.length;
- allocateMemory();
+ super();
+ if (data.length > 0) {
+ pbData = new Memory(data.length);
+ pbData.write(0, data, 0, data.length);
+ cbData = data.length;
+ } else {
+ // We allocate 1 byte memory region because `malloc` may return `NULL` if requested size is 0.
+ // However, `CryptProtectData` and `CryptUnprotectData` consider `NULL` as invalid data.
+ // The fact that we allocate 1 byte does not affect the final result because
+ // we pass the correct size explicitly on `cbData` field.
+ pbData = new Memory(1);
+ cbData = 0;
+ }
}
public DATA_BLOB(String s) {
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
index 2475d6ed0a..20d345862b 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
@@ -23,6 +23,11 @@
*/
package com.sun.jna.platform.win32;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
import com.sun.jna.FromNativeContext;
import com.sun.jna.IntegerType;
import com.sun.jna.Memory;
@@ -1074,10 +1079,11 @@ public FILE_NOTIFY_INFORMATION next() {
int REG_NOTIFY_CHANGE_ATTRIBUTES = 0x00000002;
int REG_NOTIFY_CHANGE_LAST_SET = 0x00000004;
int REG_NOTIFY_CHANGE_SECURITY = 0x00000008;
+ int REG_NOTIFY_THREAD_AGNOSTIC = 0x10000000;
int REG_LEGAL_CHANGE_FILTER = REG_NOTIFY_CHANGE_NAME
| REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET
- | REG_NOTIFY_CHANGE_SECURITY;
+ | REG_NOTIFY_CHANGE_SECURITY | REG_NOTIFY_THREAD_AGNOSTIC;
//
// Predefined Value Types.
@@ -2988,7 +2994,7 @@ protected SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Pointer memory) {
* Create a new instance of the appropriate subclass of
* {@link SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX} from the provided
* {@link Pointer} to native memory. Use this method rather than
- * {@link #SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Pointer)} to properly
+ * {@code SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Pointer)} to properly
* cast the Pointer to the appropriate subclass and populate variable
* length arrays.
*
@@ -3017,9 +3023,12 @@ public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX fromPointer(Pointer memory
switch (relationship) {
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore:
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage:
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorDie:
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorModule:
result = new PROCESSOR_RELATIONSHIP(memory);
break;
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode:
+ case LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNodeEx:
result = new NUMA_NODE_RELATIONSHIP(memory);
break;
case LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache:
@@ -3117,7 +3126,10 @@ public PROCESSOR_RELATIONSHIP(Pointer memory) {
@Override
public void read() {
readField("groupCount");
- groupMask = new GROUP_AFFINITY[groupCount];
+ // Resize if needed
+ if (groupCount != groupMask.length) {
+ groupMask = new GROUP_AFFINITY[groupCount];
+ }
super.read();
}
}
@@ -3125,33 +3137,80 @@ public void read() {
/**
* Represents information about a NUMA node in a processor group.
*/
- @FieldOrder({ "nodeNumber", "reserved", "groupMask" })
+ @FieldOrder({ "nodeNumber", "reserved", "groupCount", "groupMasks" })
public static class NUMA_NODE_RELATIONSHIP extends SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
/**
- * Identifies the NUMA node. Valid values are {@code 0} to the highest
- * NUMA node number inclusive. A non-NUMA multiprocessor system will
- * report that all processors belong to one NUMA node.
+ * Identifies the NUMA node. Valid values are {@code 0} to the highest NUMA node
+ * number inclusive. A non-NUMA multiprocessor system will report that all
+ * processors belong to one NUMA node.
*/
public int nodeNumber;
/**
* This member is reserved.
*/
- public byte[] reserved = new byte[20];
+ public byte[] reserved = new byte[18];
+
+ /**
+ * The number of groups included in the GroupMasks array. This field was
+ * introduced in TBD Release Iron. On earlier versions, this value is always 0.
+ */
+ public short groupCount;
/**
* A {@link GROUP_AFFINITY} structure that specifies a group number and
- * processor affinity within the group.
+ * processor affinity within the group. This member is only relevant if
+ * {@code groupCount} is 0.
*/
public GROUP_AFFINITY groupMask;
+ /**
+ * An array of {@link GROUP_AFFINITY} structures that specifies a group number
+ * and processor affinity within the group. This member is only relevant if
+ * {@code groupCount} is 1 or greater.
+ */
+ public GROUP_AFFINITY[] groupMasks = new GROUP_AFFINITY[1];
+
public NUMA_NODE_RELATIONSHIP() {
}
public NUMA_NODE_RELATIONSHIP(Pointer memory) {
super(memory);
}
+
+ @Override
+ public void read() {
+ readField("groupCount");
+ // In older version of structure this is part of reserved array and has 0 value.
+ // Force a minimum array size of 1.
+ int actualGroupCount = Math.max(1, groupCount);
+ // Resize if needed
+ if (actualGroupCount != groupMasks.length) {
+ groupMasks = new GROUP_AFFINITY[actualGroupCount];
+ }
+ super.read();
+ // Copy first value from array to older version of structure for compatibility
+ groupMask = groupMasks[0];
+ }
+
+ /*
+ * The groupMask field is provided as a public instance variable for
+ * compatibility. getFieldList is overridden to remove it before comparing
+ * against the structure field order.
+ */
+ @Override
+ protected List getFieldList() {
+ List fields = new ArrayList(super.getFieldList());
+ Iterator fieldIterator = fields.iterator();
+ while (fieldIterator.hasNext()) {
+ Field field = fieldIterator.next();
+ if ("groupMask".equals(field.getName())) {
+ fieldIterator.remove();
+ }
+ }
+ return fields;
+ }
}
/**
@@ -3247,7 +3306,10 @@ public GROUP_RELATIONSHIP(Pointer memory) {
@Override
public void read() {
readField("activeGroupCount");
- groupInfo = new PROCESSOR_GROUP_INFO[activeGroupCount];
+ // Resize if needed
+ if (activeGroupCount != groupInfo.length) {
+ groupInfo = new PROCESSOR_GROUP_INFO[activeGroupCount];
+ }
super.read();
}
}
@@ -3386,8 +3448,10 @@ public interface LOGICAL_PROCESSOR_RELATIONSHIP {
/**
*
- * Upcoming value of this enum added for forward compatibility. Documentation
- * will be added when available.
+ * Introduced in TBD - Release Iron. Requests that the full affinity be
+ * returned. Unlike the other relation types, RelationNumaNodeEx is not used on
+ * input. It is simply a request for RelationNumaNode with full group
+ * information.
*
*/
int RelationNumaNodeEx = 6;
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinReg.java b/contrib/platform/src/com/sun/jna/platform/win32/WinReg.java
index 5dc2da513b..f0b6b004dc 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinReg.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinReg.java
@@ -78,4 +78,5 @@ public HKEY getValue() {
HKEY HKEY_PERFORMANCE_NLSTEXT = new HKEY(0x80000060);
HKEY HKEY_CURRENT_CONFIG = new HKEY(0x80000005);
HKEY HKEY_DYN_DATA = new HKEY(0x80000006);
+ HKEY HKEY_CURRENT_USER_LOCAL_SETTINGS = new HKEY(0x80000007);
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Wtsapi32.java b/contrib/platform/src/com/sun/jna/platform/win32/Wtsapi32.java
index 94af3c8bbd..9b80eb0589 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Wtsapi32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Wtsapi32.java
@@ -149,7 +149,7 @@ public interface WTS_CONNECTSTATE_CLASS {
/**
* Contains values that indicate the type of session information to retrieve in
- * a call to the {@link #WTSQuerySessionInformation()} function.
+ * a call to the {@link #WTSQuerySessionInformation(com.sun.jna.platform.win32.WinNT.HANDLE, int, int, com.sun.jna.ptr.PointerByReference, com.sun.jna.ptr.IntByReference)} function.
*/
public interface WTS_INFO_CLASS {
int WTSInitialProgram = 0;
diff --git a/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java b/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java
index 902bb72806..f8953cf483 100644
--- a/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/ByReferencePlatformToStringTest.java
@@ -30,6 +30,7 @@
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
+import com.sun.jna.platform.unix.LibCAPI.size_t;
import com.sun.jna.platform.unix.X11.AtomByReference;
import com.sun.jna.platform.unix.X11.WindowByReference;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
@@ -137,6 +138,9 @@ public void testPlatformToStrings() {
SCODEByReference scodebr = new SCODEByReference(new SCODE(42));
parseAndTest(scodebr.toString(), "SCODE", "42");
+ size_t.ByReference sizetbr = new size_t.ByReference(42);
+ parseAndTest(sizetbr.toString(), "size_t", "42");
+
UINTByReference uibr = new UINTByReference(new UINT(42));
parseAndTest(uibr.toString(), "UINT", "42");
diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
index f6ff8e966f..2fedb7a988 100644
--- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assert.fail;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -62,25 +63,37 @@ public class CoreFoundationTest {
@Test
public void testCFStringRef() throws UnsupportedEncodingException {
- String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode
- CFStringRef cfAwesome = CFStringRef.createCFString(awesome);
- assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue());
- assertEquals(awesome, cfAwesome.stringValue());
- assertEquals(CoreFoundation.STRING_TYPE_ID, cfAwesome.getTypeID());
-
- byte[] awesomeArr = awesome.getBytes("UTF-8");
- Memory mem = new Memory(awesomeArr.length + 1);
- mem.clear();
- assertNotEquals(0,
- CF.CFStringGetCString(cfAwesome, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8));
- byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1);
- assertArrayEquals(awesomeArr, awesomeBytes);
- // Essentially a toString, can't rely on format but should contain the string
- CFStringRef desc = CF.CFCopyDescription(cfAwesome);
- assertTrue(desc.stringValue().contains(awesome));
-
- desc.release();
- cfAwesome.release();
+ // Generate strings with different UTF8 byte lengths
+ byte[] pound = { (byte) 0xc2, (byte) 0xa3 };
+ byte[] euro = { (byte) 0xe2, (byte) 0x82, (byte) 0xac };
+ byte[] smileEmoji = { (byte) 0xf0, (byte) 0x9f, (byte) 0x98, (byte) 0x83 };
+ String[] testStrings = new String[4];
+ testStrings[0] = "ascii";
+ testStrings[1] = new String(pound, StandardCharsets.UTF_8);
+ testStrings[2] = new String(euro, StandardCharsets.UTF_8);
+ testStrings[3] = new String(smileEmoji, StandardCharsets.UTF_8);
+ for (String utf8Str : testStrings) {
+ CFStringRef cfStr = CFStringRef.createCFString(utf8Str);
+ // Length matches length of char array
+ // 2 for code points > 0xffff, 1 otherwise
+ assertEquals(utf8Str.length(), CF.CFStringGetLength(cfStr).intValue());
+ assertEquals(utf8Str, cfStr.stringValue());
+ assertEquals(CoreFoundation.STRING_TYPE_ID, cfStr.getTypeID());
+
+ byte[] utf8Arr = utf8Str.getBytes("UTF-8");
+ Memory mem = new Memory(utf8Arr.length + 1);
+ mem.clear();
+ assertNotEquals(0,
+ CF.CFStringGetCString(cfStr, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8));
+ byte[] utf8Bytes = mem.getByteArray(0, (int) mem.size() - 1);
+ assertArrayEquals(utf8Arr, utf8Bytes);
+ // Essentially a toString, can't rely on format but should contain the string
+ CFStringRef desc = CF.CFCopyDescription(cfStr);
+ assertTrue(desc.stringValue().contains(utf8Str));
+
+ desc.release();
+ cfStr.release();
+ }
CFStringRef cfEmpty = CFStringRef.createCFString("");
assertTrue(cfEmpty.stringValue().equals(""));
diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java
index 6b9af6ebca..b658eefb5e 100644
--- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java
@@ -54,7 +54,7 @@
import com.sun.jna.ptr.PointerByReference;
import junit.framework.TestCase;
-
+import static com.sun.jna.platform.unix.LibCAPI.size_t;
/**
* Exercise the {@link SystemB} class.
*/
@@ -64,33 +64,36 @@ public void testSysctl() {
final String mibName = "hw.logicalcpu";
final int nCpu = Runtime.getRuntime().availableProcessors();
- IntByReference size = new IntByReference(SystemB.INT_SIZE);
- Pointer p = new Memory(size.getValue());
- int ret = SystemB.INSTANCE.sysctlbyname(mibName, p, size, null, 0);
- assertEquals(ret, 0);
+ // This sysctl returns a 32-bit integer cpu count
+ Memory p = new Memory(SystemB.INT_SIZE);
+ size_t.ByReference plen = new size_t.ByReference(p.size());
+ assertEquals(0, SystemB.INSTANCE.sysctlbyname(mibName, p, plen, null, size_t.ZERO));
// These values should be equal unless affinity is set, limiting nCpu
assertTrue(p.getInt(0) >= nCpu);
- size = new IntByReference();
- ret = SystemB.INSTANCE.sysctlnametomib(mibName, null, size);
- assertEquals(ret, 0);
- // Size should be 2
- assertEquals(size.getValue(), 2);
-
- Pointer mibp = new Memory(size.getValue() * SystemB.INT_SIZE);
- ret = SystemB.INSTANCE.sysctlnametomib(mibName, mibp, size);
- assertEquals(ret, 0);
- // Size should be 2
- assertEquals(size.getValue(), 2);
-
- int[] mib = mibp.getIntArray(0, size.getValue());
+ // Get the same value by converting the string to the MIB array
+ // Get the size of the MIB array
+ size_t.ByReference sizep = new size_t.ByReference();
+ assertEquals(0, SystemB.INSTANCE.sysctlnametomib(mibName, null, sizep));
+ // Array size should be 2
+ long sizepval = sizep.longValue();
+ assertEquals(2L, sizepval);
+
+ // Allocate the correct size and fill the MIB array
+ Pointer mibp = new Memory(sizepval * SystemB.INT_SIZE);
+ assertEquals(0, SystemB.INSTANCE.sysctlnametomib(mibName, mibp, sizep));
+ // Array size should still be 2
+ sizepval = sizep.longValue();
+ assertEquals(2L, sizepval);
+
+ int[] mib = mibp.getIntArray(0, (int) sizepval);
// mib should be { 6, 103(?) }
assertEquals(mib.length, 2);
assertEquals(mib[0], 6);
- size = new IntByReference(SystemB.INT_SIZE);
- p = new Memory(size.getValue());
- ret = SystemB.INSTANCE.sysctl(mib, mib.length, p, size, null, 0);
+ p = new Memory(SystemB.INT_SIZE);
+ plen = new size_t.ByReference(p.size());
+ assertEquals(0, SystemB.INSTANCE.sysctl(mib, mib.length, p, plen, null, size_t.ZERO));
assertTrue(p.getInt(0) >= nCpu);
}
@@ -257,16 +260,16 @@ public void testStatfs() {
public void testXswUsage() {
XswUsage xswUsage = new XswUsage();
assertEquals(0, SystemB.INSTANCE.sysctlbyname("vm.swapusage", xswUsage.getPointer(),
- new IntByReference(xswUsage.size()), null, 0));
+ new size_t.ByReference(xswUsage.size()), null, size_t.ZERO));
xswUsage.read();
assertTrue(xswUsage.xsu_used <= xswUsage.xsu_total);
}
public void testProcessStructures() {
// Calc max # of processes
- IntByReference size = new IntByReference(4);
- Memory mem = new Memory(4);
- assertEquals(0, SystemB.INSTANCE.sysctlbyname("kern.maxproc", mem, size, null, 0));
+ Memory mem = new Memory(SystemB.INT_SIZE);
+ size_t.ByReference size = new size_t.ByReference(mem.size());
+ assertEquals(0, SystemB.INSTANCE.sysctlbyname("kern.maxproc", mem, size, null, size_t.ZERO));
int maxProc = mem.getInt(0);
// Get list of pids
@@ -330,15 +333,16 @@ public void testIFs() {
int NET_RT_IFLIST2 = 6;
int[] mib = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 };
- IntByReference len = new IntByReference();
- assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, null, len, null, 0));
- // Add enough room for max size of IFmsgHdr to avoid JNA bounds check
- // problems with worst case structure size
- Memory buf = new Memory(len.getValue() + 112);
- assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, 0));
+ size_t.ByReference len = new size_t.ByReference();
+ assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, null, len, null, size_t.ZERO));
+ // Add enough room in buffer for later iteration so that max size of IFmsgHdr
+ // or IFMsgHdr2 does not cause bounds check issues with worst case size.
+ Memory buf = new Memory(len.longValue() + 112);
+ // We still pass the original buffer size to native.
+ assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, size_t.ZERO));
// Iterate offset from buf's pointer up to limit of buf
- int lim = len.getValue();
+ long lim = len.longValue();
int next = 0;
while (next < lim) {
// Get pointer to current native part of buf
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32Test.java
index 3a2b0132f6..c872514e7c 100755
--- a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32Test.java
@@ -700,6 +700,23 @@ public void testRegQueryInfoKey() {
assertTrue(lpcSubKeys.getValue() > 0);
}
+ public void testRegNotifyChangeKeyValue() {
+ final HKEYByReference phKey = new HKEYByReference();
+ assertEquals(W32Errors.ERROR_SUCCESS, Advapi32.INSTANCE.RegOpenKeyEx(WinReg.HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, WinNT.KEY_NOTIFY, phKey));
+ final HANDLE event = Kernel32.INSTANCE.CreateEvent(null, true /* manual reset */, false /* initial state */,
+ null);
+ assertNotNull(event);
+ final int filter = WinNT.REG_NOTIFY_CHANGE_LAST_SET | WinNT.REG_NOTIFY_CHANGE_NAME;
+ assertEquals(W32Errors.ERROR_SUCCESS,
+ Advapi32.INSTANCE.RegNotifyChangeKeyValue(phKey.getValue(), true, filter, event, true));
+ final int res = Kernel32.INSTANCE.WaitForSingleObject(event, 1000);
+ // Two possible outcomes: Either we notice a timeout or we notice a change:
+ assertTrue(res == WinError.WAIT_TIMEOUT || res == WinBase.WAIT_OBJECT_0);
+ assertEquals(W32Errors.ERROR_SUCCESS, Advapi32.INSTANCE.RegCloseKey(phKey.getValue()));
+ assertTrue(Kernel32.INSTANCE.CloseHandle(event));
+ }
+
public void testIsWellKnownSid() {
String sidString = EVERYONE;
PSIDByReference sid = new PSIDByReference();
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/COMLateBindingObjectTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/COMLateBindingObjectTest.java
new file mode 100644
index 0000000000..3c2a7ad639
--- /dev/null
+++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/COMLateBindingObjectTest.java
@@ -0,0 +1,123 @@
+/* Copyright (c) 2021 Matthias Bläsing, 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.COM;
+
+import com.sun.jna.WString;
+import com.sun.jna.platform.win32.AbstractWin32TestSupport;
+import com.sun.jna.platform.win32.Guid;
+import com.sun.jna.platform.win32.Guid.CLSID;
+import com.sun.jna.platform.win32.Guid.REFIID;
+import com.sun.jna.platform.win32.OaIdl.DISPIDByReference;
+import com.sun.jna.platform.win32.OaIdl.EXCEPINFO;
+import com.sun.jna.platform.win32.Ole32;
+import com.sun.jna.platform.win32.OleAuto;
+import com.sun.jna.platform.win32.OleAuto.DISPPARAMS;
+import com.sun.jna.platform.win32.Variant.VARIANT;
+import com.sun.jna.platform.win32.WTypes;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinDef.LCID;
+import com.sun.jna.platform.win32.WinNT.HRESULT;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class COMLateBindingObjectTest {
+
+ static {
+ ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
+ }
+
+ private final CLSID CLSID_InternetExplorer = new CLSID("{0002DF01-0000-0000-C000-000000000046}");
+ private final LCID lcid = new LCID(0x0409); // LCID for english locale
+ private final WinDef.WORD methodFlags = new WinDef.WORD(OleAuto.DISPATCH_METHOD);
+
+ private final REFIID niid = new REFIID(Guid.IID_NULL);
+ private final DISPIDByReference dispIdQuit = new DISPIDByReference();
+
+ private PointerByReference ieApp;
+ private Dispatch ieDispatch;
+
+ public COMLateBindingObjectTest() {
+ }
+
+ @Before
+ public void before() {
+ AbstractWin32TestSupport.killProcessByName("iexplore.exe");
+ try {
+ Thread.sleep(5 * 1000);
+ } catch (InterruptedException ex) {
+ }
+
+ HRESULT hr = Ole32.INSTANCE.CoInitializeEx(null, Ole32.COINIT_MULTITHREADED);
+ COMUtils.checkRC(hr);
+
+ // Create InternetExplorer object
+ ieApp = new PointerByReference();
+ hr = Ole32.INSTANCE
+ .CoCreateInstance(CLSID_InternetExplorer, null, WTypes.CLSCTX_SERVER, IDispatch.IID_IDISPATCH, ieApp);
+ COMUtils.checkRC(hr);
+
+ ieDispatch = new Dispatch(ieApp.getValue());
+ ieDispatch.AddRef();
+ hr = ieDispatch.GetIDsOfNames(new REFIID(Guid.IID_NULL), new WString[]{new WString("Quit")}, 1, lcid, dispIdQuit);
+ COMUtils.checkRC(hr);
+ }
+
+ @After
+ public void after() {
+ // Shutdown Internet Explorer
+ DISPPARAMS.ByReference pDispParams = new DISPPARAMS.ByReference();
+ VARIANT.ByReference pVarResult = new VARIANT.ByReference();
+ IntByReference puArgErr = new IntByReference();
+ EXCEPINFO.ByReference pExcepInfo = new EXCEPINFO.ByReference();
+
+ HRESULT hr = ieDispatch.Invoke(dispIdQuit.getValue(), niid, lcid, methodFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+ COMUtils.checkRC(hr, pExcepInfo, puArgErr);
+
+ ieDispatch.Release();
+ Ole32.INSTANCE.CoUninitialize();
+ }
+
+ @Test
+ public void testPropertyAccessor() throws InterruptedException {
+ final String testString = "Hallo Welt";
+ COMLateBindingObject ieBinding = new COMLateBindingObject(ieDispatch);
+ ieBinding.setProperty("Visible", true);
+ assertTrue(ieBinding.getBooleanProperty("Visible"));
+ boolean statusBarInitial = ieBinding.getBooleanProperty("StatusBar");
+ ieBinding.setProperty("StatusBar", true);
+ assertTrue(ieBinding.getBooleanProperty("StatusBar"));
+ ieBinding.setProperty("StatusText", testString);
+ assertEquals(testString, ieBinding.getStringProperty("StatusText"));
+ ieBinding.setProperty("StatusBar", false);
+ assertFalse(ieBinding.getBooleanProperty("StatusBar"));
+ ieBinding.setProperty("StatusBar", statusBarInitial);
+ ieBinding.setProperty("Visible", false);
+ assertFalse(ieBinding.getBooleanProperty("Visible"));
+ }
+}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java
index 061b57cdf9..d4409a4459 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComEventCallbacks_Test.java
@@ -55,8 +55,6 @@
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import org.junit.Assert;
public class ComEventCallbacks_Test {
@@ -273,10 +271,12 @@ public HRESULT QueryInterface(REFIID refiid, PointerByReference ppvObject) {
return new HRESULT(WinError.E_NOINTERFACE);
}
+ @Override
public int AddRef() {
return 0;
}
+ @Override
public int Release() {
return 0;
}
@@ -341,6 +341,7 @@ public void testComEventCallback() throws InterruptedException {
}
Thread.sleep(1000);
}
+ OleAuto.INSTANCE.VariantClear(arguments[0]);
// At this point the call to Navigate before should be complete
Assert.assertTrue(listener.navigateComplete2Called);
@@ -364,6 +365,7 @@ public void testComEventCallback() throws InterruptedException {
}
Thread.sleep(1000);
}
+ OleAuto.INSTANCE.VariantClear(arguments[0]);
// Naviation will be blocked - so NavigateComplete can't be called
Assert.assertFalse("NavigateComplete Handler was called although it should be blocked", listener.navigateComplete2Called);
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ConvertTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ConvertTest.java
index 746eeebd08..cb7d23d9cc 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ConvertTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/util/ConvertTest.java
@@ -31,6 +31,7 @@
import com.sun.jna.platform.win32.OaIdl.DATE;
import com.sun.jna.platform.win32.OaIdl.VARIANT_BOOL;
import com.sun.jna.platform.win32.Ole32;
+import com.sun.jna.platform.win32.OleAuto;
import com.sun.jna.platform.win32.Variant;
import com.sun.jna.platform.win32.Variant.VARIANT;
import com.sun.jna.platform.win32.WTypes.BSTR;
@@ -84,18 +85,17 @@ public void testConvertVariant() {
@Test
public void testConvertString() {
- // This test leaks the allocated BSTR -- this is tollerated here, as memory usage is minimal
String testString = "Hallo";
- BSTR testValue = new BSTR(testString);
+ BSTR testValue = OleAuto.INSTANCE.SysAllocString(testString);
VARIANT resultVariant = Convert.toVariant(testValue);
assertEquals(testString, resultVariant.stringValue());
assertEquals(testString, Convert.toJavaObject(resultVariant, Object.class, fact, false, false));
- assertEquals(testString, Convert.toJavaObject(resultVariant, String.class, fact, false, false));
+ assertEquals(testString, Convert.toJavaObject(resultVariant, String.class, fact, false, true));
resultVariant = Convert.toVariant(testString);
assertEquals(testString, resultVariant.stringValue());
assertEquals(testString, Convert.toJavaObject(resultVariant, Object.class, fact, false, false));
- assertEquals(testString, Convert.toJavaObject(resultVariant, String.class, fact, false, false));
+ assertEquals(testString, Convert.toJavaObject(resultVariant, String.class, fact, false, true));
}
@Test
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java
index ec77e1da66..ed98d2f12b 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved
+/* Copyright (c) 2018, 2021 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
@@ -23,21 +23,32 @@
*/
package com.sun.jna.platform.win32;
+import static com.sun.jna.platform.win32.Cfgmgr32.CM_DRP_CONFIGFLAGS;
+import static com.sun.jna.platform.win32.Cfgmgr32.CM_DRP_DEVICEDESC;
+import static com.sun.jna.platform.win32.Cfgmgr32.CM_DRP_DEVICE_POWER_DATA;
+import static com.sun.jna.platform.win32.Cfgmgr32.CM_DRP_HARDWAREID;
+import static com.sun.jna.platform.win32.Cfgmgr32.CM_LOCATE_DEVNODE_NORMAL;
+import static com.sun.jna.platform.win32.Cfgmgr32.CR_SUCCESS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayDeque;
+import java.util.Queue;
import org.junit.Test;
import com.sun.jna.ptr.IntByReference;
+import static com.sun.jna.platform.win32.Cfgmgr32.CR_INVALID_DEVNODE;
+import static com.sun.jna.platform.win32.Cfgmgr32.CR_INVALID_PROPERTY;
+
/**
* Tests methods in Cfgmgr32
- *
- * @author widdis[at]gmail[dot]com
*/
public class Cfgmgr32Test {
+ private static final Cfgmgr32 CFG = Cfgmgr32.INSTANCE;
+
/**
* Tests CM_Locate_DevNode, CM_Get_Parent, CM_Get_Child, CM_Get_Sibling
*/
@@ -45,19 +56,18 @@ public class Cfgmgr32Test {
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));
+ assertEquals(CR_SUCCESS, CFG.CM_Locate_DevNode(outputNode, null, 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));
+ assertEquals(CR_SUCCESS, CFG.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(CR_SUCCESS, CFG.CM_Get_Parent(outputNode, inputNode, 0));
assertEquals(rootNode, outputNode.getValue());
- } while (Cfgmgr32.CR_SUCCESS == Cfgmgr32.INSTANCE.CM_Get_Sibling(outputNode, inputNode, 0));
+ } while (CR_SUCCESS == CFG.CM_Get_Sibling(outputNode, inputNode, 0));
}
/**
@@ -66,16 +76,15 @@ public void testDevNode() {
* @throws UnsupportedEncodingException
*/
@Test
- public void testDeviceID() {
+ 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));
+ assertEquals(CR_SUCCESS, CFG.CM_Locate_DevNode(outputNode, null, 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);
+ CFG.CM_Get_Device_ID_Size(pulLen, rootNode, 0);
assertTrue(pulLen.getValue() > 0);
// Get Device ID from util
@@ -83,8 +92,93 @@ public void testDeviceID() {
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(CR_SUCCESS, CFG.CM_Locate_DevNode(outputNode, deviceId, CM_LOCATE_DEVNODE_NORMAL));
assertEquals(rootNode, outputNode.getValue());
}
+
+ /**
+ * Tests CM_Get_DevNode_Registry_Property util
+ */
+ @Test
+ public void testDeviceProperties() {
+ Object props;
+
+ // Test an invalid node
+ try {
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(-1, CM_DRP_DEVICEDESC);
+ assertTrue("Should not be reached - method is expected to raise a Cfgmgr32Exception", false);
+ } catch (Cfgmgr32Util.Cfgmgr32Exception ex) {
+ assertEquals(CR_INVALID_DEVNODE, ex.getErrorCode());
+ }
+
+ // Not all devices have all properties and will fail with CR_NO_SUCH_VALUE.
+ // So do BFS of device tree and run tests on all devices until we've tested each
+ boolean descTested = false;
+ boolean hwidTested = false;
+ boolean flagsTested = false;
+ boolean powerTested = false;
+
+ // Fetch the root node
+ IntByReference outputNode = new IntByReference();
+ assertEquals(CR_SUCCESS, CFG.CM_Locate_DevNode(outputNode, null, CM_LOCATE_DEVNODE_NORMAL));
+ int node = outputNode.getValue();
+
+ // Navigate the device tree using BFS
+ Queue deviceQueue = new ArrayDeque();
+ IntByReference child = new IntByReference();
+ IntByReference sibling = new IntByReference();
+ // Initialize queue with root node
+ deviceQueue.add(node);
+ while (!deviceQueue.isEmpty()) {
+ // Process the next device in the queue
+ node = deviceQueue.poll();
+
+ // Run tests
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(node, CM_DRP_DEVICEDESC);
+ if (props != null) {
+ assertTrue(props instanceof String);
+ descTested = true;
+ }
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(node, CM_DRP_HARDWAREID);
+ if (props != null) {
+ assertTrue(props instanceof String[]);
+ hwidTested = true;
+ }
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(node, CM_DRP_CONFIGFLAGS);
+ if (props != null) {
+ assertTrue(props instanceof Integer);
+ flagsTested = true;
+ }
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(node, CM_DRP_DEVICE_POWER_DATA);
+ if (props != null) {
+ assertTrue(props instanceof byte[]);
+ powerTested = true;
+ }
+ // Test an invalid type
+ try {
+ props = Cfgmgr32Util.CM_Get_DevNode_Registry_Property(node, 0);
+ assertTrue("Should not be reached - method is expected to raise a Cfgmgr32Exception", false);
+ } catch (Cfgmgr32Util.Cfgmgr32Exception ex) {
+ assertEquals(CR_INVALID_PROPERTY, ex.getErrorCode());
+ }
+
+ // If we've done all tests we can exit the loop
+ if (descTested && hwidTested && flagsTested && powerTested) {
+ break;
+ }
+
+ // If not done, add any children to the queue
+ if (CR_SUCCESS == CFG.CM_Get_Child(child, node, 0)) {
+ deviceQueue.add(child.getValue());
+ while (CR_SUCCESS == CFG.CM_Get_Sibling(sibling, child.getValue(), 0)) {
+ deviceQueue.add(sibling.getValue());
+ child.setValue(sibling.getValue());
+ }
+ }
+ }
+ assertTrue(descTested);
+ assertTrue(hwidTested);
+ assertTrue(flagsTested);
+ assertTrue(powerTested);
+ }
}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilClearSecuritySensitiveDataTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilClearSecuritySensitiveDataTest.java
new file mode 100644
index 0000000000..12c67c4283
--- /dev/null
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilClearSecuritySensitiveDataTest.java
@@ -0,0 +1,155 @@
+/* Copyright (c) 2021 Dmytro Sheyko, 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 java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+import com.sun.jna.Memory;
+
+import static org.hamcrest.CoreMatchers.is;
+
+/**
+ * https://github.com/java-native-access/jna/issues/1362
+ */
+public class Crypt32UtilClearSecuritySensitiveDataTest {
+ @Rule public ErrorCollector errors = new ErrorCollector();
+ Field fieldMemory_HEAD;
+ Field fieldLinkedReference_next;
+ Field fieldLinkedReference_prev;
+
+ @Before
+ public void setUp() throws NoSuchFieldException, ClassNotFoundException {
+ fieldMemory_HEAD = Memory.class.getDeclaredField("HEAD");
+ fieldMemory_HEAD.setAccessible(true);
+ Class> classLinkedReference = Class.forName("com.sun.jna.Memory$LinkedReference");
+ fieldLinkedReference_next = classLinkedReference.getDeclaredField("next");
+ fieldLinkedReference_next.setAccessible(true);
+ fieldLinkedReference_prev = classLinkedReference.getDeclaredField("prev");
+ fieldLinkedReference_prev.setAccessible(true);
+ }
+
+ boolean stillHover(byte[] sample) throws IllegalAccessException {
+ Object head = fieldMemory_HEAD.get(null);
+ return stillHover(sample, head, fieldLinkedReference_next) || stillHover(sample, head, fieldLinkedReference_prev);
+ }
+
+ boolean stillHover(byte[] sample, Object head, Field fieldNext) throws IllegalAccessException {
+ Object next = head;
+ do {
+ Object curr = next;
+ Memory memory = (Memory) ((WeakReference>) curr).get();
+ byte[] array = memory.getByteArray(0, (int) memory.size());
+ if (Arrays.equals(array, sample)) {
+ return true;
+ }
+ next = fieldNext.get(curr);
+ } while (next != null);
+ return false;
+ }
+
+ @After
+ public void tearDown() {
+ Memory.disposeAll();
+ }
+
+ @Test
+ public void testEncryption() throws IllegalAccessException {
+ byte[] original = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, };
+ Crypt32Util.cryptProtectData(original, null, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, "", null);
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ }
+
+ @Test
+ public void testDecryption() throws IllegalAccessException {
+ byte[] original = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, };
+ byte[] encrypted = Crypt32Util.cryptProtectData(original, null, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, "", null);
+ Crypt32Util.cryptUnprotectData(encrypted, null, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, null);
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ errors.checkThat("encrypted is still hover", false, is(stillHover(encrypted)));
+ }
+
+ @Test
+ public void testEncryptionWithEntropy() throws IllegalAccessException {
+ byte[] original = { 25, 26, 27, 28, 29, 30, };
+ byte[] entropy = { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, };
+ Crypt32Util.cryptProtectData(original, entropy, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, "", null);
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ errors.checkThat("entropy is still hover", false, is(stillHover(entropy)));
+ }
+
+ @Test
+ public void testDecryptionWithEntropy() throws IllegalAccessException {
+ byte[] original = { 31, 32, 33, 34, };
+ byte[] entropy = { 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, };
+ byte[] encrypted = Crypt32Util.cryptProtectData(original, entropy, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, "", null);
+ Crypt32Util.cryptUnprotectData(encrypted, entropy, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, null);
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ errors.checkThat("entropy is still hover", false, is(stillHover(entropy)));
+ errors.checkThat("encrypted is still hover", false, is(stillHover(encrypted)));
+ }
+
+ @Test
+ public void testUnsuccessfulDecryption() throws IllegalAccessException {
+ byte[] original = { 35, 36, 37, 38, 39, 40, 41, };
+ try {
+ Crypt32Util.cryptUnprotectData(original, null, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, null);
+ errors.addError(new AssertionError("Win32Exception is expected"));
+ } catch (Win32Exception e) {
+ // ok, expected
+ }
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ }
+
+ @Test
+ public void testUnsuccessfulDecryptionBadEntropy() throws IllegalAccessException {
+ byte[] original = { 42, 43, };
+ byte[] entropy0 = { 44, 45, 46, };
+ byte[] entropy1 = { 47, 48, 49, 50, };
+ byte[] encrypted = Crypt32Util.cryptProtectData(original, entropy0, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, "", null);
+ try {
+ Crypt32Util.cryptUnprotectData(encrypted, entropy1, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, null);
+ errors.addError(new AssertionError("Win32Exception is expected"));
+ } catch (Win32Exception e) {
+ // ok, expected
+ }
+
+ errors.checkThat("original is still hover", false, is(stillHover(original)));
+ errors.checkThat("entropy0 is still hover", false, is(stillHover(entropy0)));
+ errors.checkThat("entropy1 is still hover", false, is(stillHover(entropy1)));
+ errors.checkThat("encrypted is still hover", false, is(stillHover(encrypted)));
+ }
+}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilTest.java
index 833b8d4389..f3a452abb7 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Crypt32UtilTest.java
@@ -36,6 +36,13 @@ public static void main(String[] args) {
junit.textui.TestRunner.run(Crypt32UtilTest.class);
}
+ public void testCryptProtectUnprotectZeroLengthData() {
+ byte[] data = new byte[0];
+ byte[] protectedData = Crypt32Util.cryptProtectData(data);
+ byte[] unprotectedData = Crypt32Util.cryptUnprotectData(protectedData);
+ assertEquals(0, unprotectedData.length);
+ }
+
public void testCryptProtectUnprotectData() {
byte[] data = new byte[2];
data[0] = 42;
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/SAFEARRAYTest.java b/contrib/platform/test/com/sun/jna/platform/win32/SAFEARRAYTest.java
index c0a02ac314..b5b7621b76 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/SAFEARRAYTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/SAFEARRAYTest.java
@@ -96,6 +96,7 @@ public void teardown() {
public void testCreateVarArray() {
SAFEARRAY varArray = SAFEARRAY.createSafeArray(1);
Assert.assertTrue(varArray != null);
+ varArray.destroy();
}
@Test
@@ -133,6 +134,7 @@ public void testSafeArrayPutGetElement() throws Exception {
OleAuto.INSTANCE.VariantClear(element);
}
}
+ varArray.destroy();
}
@Ignore("Only for live testing")
@@ -266,7 +268,7 @@ public void testMultidimensionalNotNullBased() {
Assert.assertEquals(6, sa.getUBound(1));
// requery the moved array and compare with basic array
- Object[][] relocated = (Object[][]) OaIdlUtil.toPrimitiveArray(sa, false);
+ Object[][] relocated = (Object[][]) OaIdlUtil.toPrimitiveArray(sa, true);
Assert.assertArrayEquals( basic, relocated);
}
@@ -665,10 +667,13 @@ public void testADODB() {
SAFEARRAY arr = SAFEARRAY.createSafeArray(1);
arr.putElement(new VARIANT("System.ItemUrl"), 0);
boolean exceptionCaught = false;
+ VARIANT itemName = new VARIANT("System.ItemName");
try {
- arr.putElement(new VARIANT("System.ItemName"), 1);
+ arr.putElement(itemName, 1);
} catch (COMException ex) {
exceptionCaught = true;
+ } finally {
+ OleAuto.INSTANCE.VariantClear(itemName);
}
assertTrue("Array is initialized to a size of one - it can't hold a second item.", exceptionCaught);
arr.redim(2, 0);
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java
index c88e2b5aee..a46c22ae66 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java
@@ -23,11 +23,14 @@
*/
package com.sun.jna.platform.win32;
+import static org.junit.Assert.assertArrayEquals;
+
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import com.sun.jna.Native;
+import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Guid.GUID;
import com.sun.jna.platform.win32.ShellAPI.APPBARDATA;
@@ -36,11 +39,11 @@
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HRESULT;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import junit.framework.TestCase;
-
/**
* @author dblock[at]dblock[dot]org
* @author markus[at]headcrashing[dot]eu
@@ -260,4 +263,16 @@ public void testCurrentProcessExplicitAppUserModelID() {
Ole32.INSTANCE.CoTaskMemFree(ppszAppID.getValue());
}
+ public void testCommandLineToArgvW() {
+ WString cl = new WString("\"foo bar\" baz");
+ String[] argv = { "foo bar", "baz" };
+ IntByReference nargs = new IntByReference();
+ Pointer strArr = Shell32.INSTANCE.CommandLineToArgvW(cl, nargs);
+ assertNotNull(strArr);
+ try {
+ assertArrayEquals(argv, strArr.getWideStringArray(0, nargs.getValue()));
+ } finally {
+ Kernel32.INSTANCE.LocalFree(strArr);
+ }
+ }
}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java
index 410a6dfc95..c7245191f8 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java
@@ -23,6 +23,8 @@
*/
package com.sun.jna.platform.win32;
+import static org.junit.Assert.assertArrayEquals;
+
import junit.framework.TestCase;
/**
@@ -85,4 +87,10 @@ public void testGetKnownFolderPath()
// assertNotNull(Shell32Util.getKnownFolderPath(KnownFolders.FOLDERID_UserProgramFiles));
// assertNotNull(Shell32Util.getKnownFolderPath(KnownFolders.FOLDERID_UserProgramFilesCommon));
}
+
+ public void testCommandLineToArgv() {
+ String cl = "\"foo bar\" baz";
+ String[] argv = { "foo bar", "baz" };
+ assertArrayEquals(argv, Shell32Util.CommandLineToArgv(cl));
+ }
}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/User32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/User32Test.java
index 7c2b890777..c3c8321a22 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/User32Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/User32Test.java
@@ -63,6 +63,9 @@
import com.sun.jna.platform.win32.WinUser.MONITORINFO;
import com.sun.jna.platform.win32.WinUser.MONITORINFOEX;
+import javax.swing.JFrame;
+import javax.swing.JWindow;
+
/**
* @author dblock[at]dblock[dot]org
*/
@@ -375,6 +378,35 @@ public void testGetAncestor() {
assertNull("GetAncestor result should be null", result);
}
+ @Test
+ public void testGetParent() {
+ HWND desktopWindow = User32.INSTANCE.GetDesktopWindow();
+ assertNotNull("Failed to get desktop window HWND", desktopWindow);
+
+ HWND result = User32.INSTANCE.GetParent(desktopWindow);
+ assertNull("GetParent result should be null", result);
+
+ final JFrame parent = new JFrame("Parent");
+ final JWindow child = new JWindow(parent);
+
+ try {
+ parent.setVisible(true);
+ child.setVisible(true);
+
+ HWND parentHwnd = new HWND();
+ parentHwnd.setPointer(Native.getComponentPointer(parent));
+
+ HWND childHwnd = new HWND();
+ childHwnd.setPointer(Native.getComponentPointer(child));
+
+ result = User32.INSTANCE.GetParent(childHwnd);
+ assertEquals("GetParent of child should be parent", parentHwnd, result);
+ } finally {
+ child.dispose();
+ parent.dispose();
+ }
+ }
+
@Test
public void testGetCursorPos() {
POINT cursorPos = new POINT();
@@ -439,6 +471,25 @@ public void testGetActiveWindow() {
assertNull("GetActiveWindow result should be null (there is no active window)", result);
}
+ @Test
+ public void testBringWindowToTop() {
+ boolean result = User32.INSTANCE.BringWindowToTop(null);
+ assertFalse("BringWindowToTop(null) result should be false", result);
+
+ final JFrame w = new JFrame("Frame to bring to top");
+ try {
+ w.setVisible(true);
+
+ HWND hwnd = new HWND();
+ hwnd.setPointer(Native.getComponentPointer(w));
+
+ result = User32.INSTANCE.BringWindowToTop(hwnd);
+ assertTrue("Couldn't bring frame to top", result);
+ } finally {
+ w.dispose();
+ }
+ }
+
@Test
public void testSendMessage() {
DesktopWindow explorerProc = getWindowByProcessPath("explorer.exe");
diff --git a/dist/doc.zip b/dist/doc.zip
index 6819dfaffa..72df86e22f 100644
Binary files a/dist/doc.zip and b/dist/doc.zip differ
diff --git a/dist/jna-jpms.jar b/dist/jna-jpms.jar
index ea8168855b..adc42f8531 100644
Binary files a/dist/jna-jpms.jar and b/dist/jna-jpms.jar differ
diff --git a/dist/jna-min.jar b/dist/jna-min.jar
index 51183c00d6..587d8775a4 100644
Binary files a/dist/jna-min.jar and b/dist/jna-min.jar differ
diff --git a/dist/jna-platform-jpms.jar b/dist/jna-platform-jpms.jar
index ecfdcbfa50..f2c403d91b 100644
Binary files a/dist/jna-platform-jpms.jar and b/dist/jna-platform-jpms.jar differ
diff --git a/dist/jna-platform.jar b/dist/jna-platform.jar
index 388cc4bab1..59a794ccae 100644
Binary files a/dist/jna-platform.jar and b/dist/jna-platform.jar differ
diff --git a/dist/jna.aar b/dist/jna.aar
index d909b6c6f1..11957eb18c 100644
Binary files a/dist/jna.aar and b/dist/jna.aar differ
diff --git a/dist/jna.jar b/dist/jna.jar
index c3d534c1d9..acd2658791 100644
Binary files a/dist/jna.jar and b/dist/jna.jar differ
diff --git a/dist/jnacontrib/demo-alphamask.jar b/dist/jnacontrib/demo-alphamask.jar
index 9267557b03..2cccbc2bc9 100644
Binary files a/dist/jnacontrib/demo-alphamask.jar and b/dist/jnacontrib/demo-alphamask.jar differ
diff --git a/dist/jnacontrib/demo-balloonmanager.jar b/dist/jnacontrib/demo-balloonmanager.jar
index 2b130c58ee..4e91752eba 100644
Binary files a/dist/jnacontrib/demo-balloonmanager.jar and b/dist/jnacontrib/demo-balloonmanager.jar differ
diff --git a/dist/jnacontrib/demo-balloontips.jar b/dist/jnacontrib/demo-balloontips.jar
index 29cdc78505..7c5cc057da 100644
Binary files a/dist/jnacontrib/demo-balloontips.jar and b/dist/jnacontrib/demo-balloontips.jar differ
diff --git a/dist/jnacontrib/demo-dnd.jar b/dist/jnacontrib/demo-dnd.jar
index ae0c789de8..4bfcdd223b 100644
Binary files a/dist/jnacontrib/demo-dnd.jar and b/dist/jnacontrib/demo-dnd.jar differ
diff --git a/dist/jnacontrib/demo-monitordemo.jar b/dist/jnacontrib/demo-monitordemo.jar
index bb7d5b2145..705fb8a05a 100644
Binary files a/dist/jnacontrib/demo-monitordemo.jar and b/dist/jnacontrib/demo-monitordemo.jar differ
diff --git a/dist/jnacontrib/demo-msoffice.jar b/dist/jnacontrib/demo-msoffice.jar
index e83c7059b3..6116041ecf 100644
Binary files a/dist/jnacontrib/demo-msoffice.jar and b/dist/jnacontrib/demo-msoffice.jar differ
diff --git a/dist/jnacontrib/demo-nativewindowmsg.jar b/dist/jnacontrib/demo-nativewindowmsg.jar
index 59d52cde4a..1622f123de 100644
Binary files a/dist/jnacontrib/demo-nativewindowmsg.jar and b/dist/jnacontrib/demo-nativewindowmsg.jar differ
diff --git a/dist/jnacontrib/demo-shapedwindow.jar b/dist/jnacontrib/demo-shapedwindow.jar
index e28dc3e78d..f7a213e8d0 100644
Binary files a/dist/jnacontrib/demo-shapedwindow.jar and b/dist/jnacontrib/demo-shapedwindow.jar differ
diff --git a/dist/jnacontrib/demo-w32printing.jar b/dist/jnacontrib/demo-w32printing.jar
index ee1a3cc1ff..81ffe9fa49 100644
Binary files a/dist/jnacontrib/demo-w32printing.jar and b/dist/jnacontrib/demo-w32printing.jar differ
diff --git a/dist/jnacontrib/demo-w32windowhooks.jar b/dist/jnacontrib/demo-w32windowhooks.jar
index 228216efa1..64b3bd893d 100644
Binary files a/dist/jnacontrib/demo-w32windowhooks.jar and b/dist/jnacontrib/demo-w32windowhooks.jar differ
diff --git a/dist/jnacontrib/demo-x11.jar b/dist/jnacontrib/demo-x11.jar
index 472c3eb2f0..6c822eb359 100644
Binary files a/dist/jnacontrib/demo-x11.jar and b/dist/jnacontrib/demo-x11.jar differ
diff --git a/dist/src-full.zip b/dist/src-full.zip
index d244225b1f..e267c17b32 100644
Binary files a/dist/src-full.zip and b/dist/src-full.zip differ
diff --git a/dist/src.zip b/dist/src.zip
index 69ad9320da..3a7f267fc3 100644
Binary files a/dist/src.zip and b/dist/src.zip differ
diff --git a/pom-jna-jpms.xml b/pom-jna-jpms.xml
index 672feafc75..0a509e528d 100644
--- a/pom-jna-jpms.xml
+++ b/pom-jna-jpms.xml
@@ -14,16 +14,26 @@
https://github.com/java-native-access/jna
-
- LGPL, version 2.1
- http://www.gnu.org/licenses/licenses.html
- repo
-
-
- Apache License v2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
+
+ LGPL-2.1-or-later
+ https://www.gnu.org/licenses/old-licenses/lgpl-2.1
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
diff --git a/pom-jna-platform-jpms.xml b/pom-jna-platform-jpms.xml
index f022e3557f..5ee608e389 100644
--- a/pom-jna-platform-jpms.xml
+++ b/pom-jna-platform-jpms.xml
@@ -14,16 +14,26 @@
https://github.com/java-native-access/jna
-
- LGPL, version 2.1
- http://www.gnu.org/licenses/licenses.html
- repo
-
-
- Apache License v2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
+
+ LGPL-2.1-or-later
+ https://www.gnu.org/licenses/old-licenses/lgpl-2.1
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
diff --git a/pom-jna-platform.xml b/pom-jna-platform.xml
index 7ef76fa9c1..29ea3d78c9 100644
--- a/pom-jna-platform.xml
+++ b/pom-jna-platform.xml
@@ -14,16 +14,26 @@
https://github.com/java-native-access/jna
-
- LGPL, version 2.1
- http://www.gnu.org/licenses/licenses.html
- repo
-
-
- Apache License v2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
+
+ LGPL-2.1-or-later
+ https://www.gnu.org/licenses/old-licenses/lgpl-2.1
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
diff --git a/pom-jna.xml b/pom-jna.xml
index 359f88aaa2..a7322d3d50 100644
--- a/pom-jna.xml
+++ b/pom-jna.xml
@@ -14,16 +14,26 @@
https://github.com/java-native-access/jna
-
- LGPL, version 2.1
- http://www.gnu.org/licenses/licenses.html
- repo
-
-
- Apache License v2.0
- http://www.apache.org/licenses/LICENSE-2.0.txt
- repo
-
+
+ LGPL-2.1-or-later
+ https://www.gnu.org/licenses/old-licenses/lgpl-2.1
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+ Java Native Access (JNA) is licensed under the LGPL, version 2.1 or
+ later, or the Apache License, version 2.0. You can freely decide which
+ license you want to apply to the project.
+
+
diff --git a/test/com/sun/jna/VMCrashProtectionTest.java b/test/com/sun/jna/VMCrashProtectionTest.java
index ff73437000..1944b99b58 100644
--- a/test/com/sun/jna/VMCrashProtectionTest.java
+++ b/test/com/sun/jna/VMCrashProtectionTest.java
@@ -24,7 +24,6 @@
package com.sun.jna;
import junit.framework.TestCase;
-import org.junit.Assume;
public class VMCrashProtectionTest extends TestCase {
@@ -52,12 +51,14 @@ public void testAccessViolation() {
else
m.setLong(0, 1);
Pointer p = m.getPointer(0);
+ Throwable actual = null;
try {
p.setInt(0, 0);
- fail("Exception should be thrown");
}
catch(Throwable e) {
+ actual = e;
}
+ assertNotNull("Exception should be thrown", actual);
}
public static void main(String[] args) {
diff --git a/www/FrequentlyAskedQuestions.md b/www/FrequentlyAskedQuestions.md
index 3e9e6d97df..28b47bb34c 100644
--- a/www/FrequentlyAskedQuestions.md
+++ b/www/FrequentlyAskedQuestions.md
@@ -244,33 +244,24 @@ a combination of TypeMapper and FunctionMapper (see
Does JNA publish a module descriptor (module-info.java) to support the Java Module System (JPMS)?
-------------------------------------------------------------------------------------------------------------------------------------------
-Since version 5.7.0, JNA publishes an additional JAR with a `module-info` class alongside
-the main project JAR, using the `jpms` classifier, e.g. `jna-5.7.0-jpms.jar`. For a
-Maven build, use the following dependency statement:
+Since version 5.8.0, JNA publishes an additional JAR with a `module-info` class alongside
+the main project JAR, using an artifact with `-jpms` appended, e.g., `jna-jpms-5.8.0.jar`
+and `jna-platform-jpms-5.8.0.jar`. For a Maven build, use the following dependency statement:
```
net.java.dev.jna
- jna
- 5.7.0
- jpms
+ jna-jpms
+ 5.8.0
```
and include `requires com.sun.jna;` in your module descriptor in your `module-info.java` file.
-If you use the `jna-platform` artifact or any other artifact which depends transitively on `jna`, it
-requires special handling to exclude the non-modular JAR:
+If you use the `jna-platform` user-contributed mappings:
```
net.java.dev.jna
- jna-platform
- 5.7.0
- jpms
-
-
- net.java.dev.jna
- jna
-
-
+ jna-platform-jpms
+ 5.8.0
```
and include `requires com.sun.jna.platform;` in your module descriptor.
@@ -282,7 +273,7 @@ for inheritance make use of reflection to access constructors and/or fields of t
Reflection is disabled by the module system's strong encapsulation. It may be necessary to
make packages which include subclasses of JNA's classes (such as `Structure` and
`PointerType` among others) accessible via reflection to the `com.sun.jna` module
-using either an `open`, `opens`, or `opens ... to` directive, or an `exports`
+using either an `open` module, `opens`, or `opens ... to` directive, or an `exports`
or `exports ... to` directive, depending on the particular application and level of
access required. If migrating an existing project, `opens` replicates the full
non-modular (classpath) reflective access.