diff --git a/.travis.yml b/.travis.yml index c8514bf64d..af95e0f31e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,6 @@ dist: trusty language: java -# disable shallow clone -git: - depth: false - before_install: - | if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qvE '(\.md$)' @@ -19,7 +15,7 @@ before_install: - export PATH=$JAVA_HOME/bin:$PATH; install: - - export APACHE_ANT_BASE=$(curl http://apache.mirror.iphh.net/ant/binaries/ | grep "apache-ant-1.9..*-bin.tar.gz" | tail -1 | sed 's/.*href="\(.*\)-bin.tar.gz".*/\1/g') + - export APACHE_ANT_BASE=$(curl http://apache.mirror.iphh.net/ant/binaries/ | grep "apache-ant-1.9..*-bin.tar.gz" | tail -1 | sed 's/.*href="\([^"]*\)-bin.tar.gz".*/\1/g') - 'echo "Apache Ant ARCHIVE: $APACHE_ANT_BASE"' - 'wget http://apache.mirror.iphh.net/ant/binaries/$APACHE_ANT_BASE-bin.tar.gz && tar xzf $APACHE_ANT_BASE-bin.tar.gz && sudo mv $APACHE_ANT_BASE /usr/local/$APACHE_ANT_BASE && sudo rm -f /usr/local/ant && sudo ln -s /usr/local/$APACHE_ANT_BASE /usr/local/ant && sudo ln -s /usr/local/$APACHE_ANT_BASE/bin/ant /usr/local/bin/ant || true' - 'sudo apt-get -y install texinfo || true' diff --git a/CHANGES.md b/CHANGES.md index 0e4c634cc1..9aa453f3b8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,27 @@ NOTE: as of JNA 4.0, JNA is now dual-licensed under LGPL and AL 2.0 (see LICENSE NOTE: JNI native support is typically incompatible between minor versions, and almost always incompatible between major versions. +Release 5.9.0 +============= + +Features +-------- +* [#1336](https://github.com/java-native-access/jna/pull/1336): Add `HKEY_CURRENT_USER_LOCAL_SETTINGS` to `c.s.j.p.win32.WinReg` - [@Dani-Hub](https://github.com/Dani-Hub). +* [#1337](https://github.com/java-native-access/jna/pull/1337): Add `REG_NOTIFY_THREAD_AGNOSTIC` to `c.s.j.p.win32.WinNet` and update `REG_LEGAL_CHANGE_FILTER` - [@Dani-Hub](https://github.com/Dani-Hub). +* [#1338](https://github.com/java-native-access/jna/pull/1338): Add `RegNotifyChangeKeyValue` to `c.s.j.p.win32.Advapi32` - [@Dani-Hub](https://github.com/Dani-Hub). +* [#1340](https://github.com/java-native-access/jna/issues/1340): Add `CM_Get_DevNode_Registry_Property` to `c.s.j.p.win32.Cfgmgr32` and corresponding util in `c.s.j.p.win32.Cfgmgr32Util` - [@dbwiddis](https://github.com/dbwiddis). +* [#1352](https://github.com/java-native-access/jna/pull/1352): Add `BringWindowToTop` to `c.s.j.p.win32.User32` - [@kahgoh](https://github.com/kahgoh). +* [#1354](https://github.com/java-native-access/jna/pull/1352): Add `GetParent` to `c.s.j.p.win32.User32` - [@kahgoh](https://github.com/kahgoh). +* [#1360](https://github.com/java-native-access/jna/issues/1360): Add `CommandLineToArgvW` to `c.s.j.p.win32.Shell32` and corresponding util in `c.s.j.p.win32.Shell32Util` - [@dbwiddis](https://github.com/dbwiddis). +* [#1363](https://github.com/java-native-access/jna/issues/1363): Update `NUMA_NODE_RELATIONSHIP` in `c.s.j.p.win32.WinNT` to new version of the structure and improve support for future values of `c.s.j.p.win32.WinNT.LOGICAL_PROCESSOR_RELATIONSHIP` - [@dbwiddis](https://github.com/dbwiddis). + +Bug Fixes +--------- +* [#1343](https://github.com/java-native-access/jna/issues/1343): `c.s.j.p.mac.CoreFoundation.CFStringRef#stringValue` buffer needs space for a null byte - [@dbwiddis](https://github.com/dbwiddis). +* [#1351](https://github.com/java-native-access/jna/issues/1351): Define `c.s.j.p.unix.size_t.ByReference` and fix macOS sysctl `size_t *` parameters - [@dbwiddis](https://github.com/dbwiddis). +* [#1362](https://github.com/java-native-access/jna/issues/1362): Clear security sensitive data after usage in `c.s.j.p.win32.Crypt32Util#cryptProtectData` and `#cryptUnprotectData` - [@dmytro-sheyko](https://github.com/dmytro-sheyko). +* [#1361](https://github.com/java-native-access/jna/issues/1361): Make `c.s.j.p.win32.Crypt32Util#cryptProtectData` and `#cryptUnprotectData` properly handle 0-length array as input - [@dmytro-sheyko](https://github.com/dmytro-sheyko). + Release 5.8.0 ============= @@ -50,7 +71,7 @@ Features * [#1239](https://github.com/java-native-access/jna/pull/1239): Improve performance of allocation of `c.s.j.Memory` objects - [@joerg1985](https://github.com/joerg1985). * [#1246](https://github.com/java-native-access/jna/pull/1246): Improve performance of `c.s.j.Structure#read` and `c.s.j.Structure#write` - [@joerg1985](https://github.com/joerg1985). * [#1260](https://github.com/java-native-access/jna/pull/1260): Add mapping for X11 generic events - [@lafoletc](https://github.com/lafoletc). -* [#1263](https://github.com/java-native-access/jna/pull/1263): Add LowLevelMouseProc - [@nordiakt](https://github.com/nordiakt) +* [#1263](https://github.com/java-native-access/jna/pull/1263): Add LowLevelMouseProc - [@nordiakt](https://github.com/nordiakt). * [#1265](https://github.com/java-native-access/jna/pull/1265): Add mapping for XQueryExtension - [@lafoletc](https://github.com/lafoletc). * [#1299](https://github.com/java-native-access/jna/pull/1299): Add `c.s.j.p.win32.IPHlpApi#GetExtendedTcpTable`, `c.s.j.p.win32.IPHlpApi#GetExtendedUdpTable`, and supporting structures. - [@dbwiddis](https://github.com/dbwiddis). diff --git a/README.md b/README.md index f5b1e81c98..9f08411489 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ ![Java Native Access - JNA](https://github.com/java-native-access/jna/raw/master/www/images/jnalogo.jpg "Java Native Access - JNA") [![Github Actions Build Status](https://github.com/java-native-access/jna/workflows/Java%20CI/badge.svg)](https://github.com/java-native-access/jna/actions?query=workflow%3A%22Java+CI%22) -[![Travis Build Status](https://travis-ci.org/java-native-access/jna.svg?branch=master)](https://travis-ci.org/java-native-access/jna) +[![Travis Build Status](https://api.travis-ci.com/java-native-access/jna.svg?branch=master)](https://travis-ci.com/github/java-native-access/jna) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/j6vmpjrw5iktb8iu/branch/master?svg=true)](https://ci.appveyor.com/project/dblock/jna-gsxuq/branch/master) Java Native Access (JNA) ======================== -The definitive JNA reference (including an overview and usage details) is in the [JavaDoc](http://java-native-access.github.io/jna/5.8.0/javadoc/). Please read the [overview](http://java-native-access.github.io/jna/5.8.0/javadoc/overview-summary.html#overview_description). Questions, comments, or exploratory conversations should begin on the [mailing list](http://groups.google.com/group/jna-users), although you may find it easier to find answers to already-solved problems on [StackOverflow](http://stackoverflow.com/questions/tagged/jna). +The definitive JNA reference (including an overview and usage details) is in the [JavaDoc](http://java-native-access.github.io/jna/5.9.0/javadoc/). Please read the [overview](http://java-native-access.github.io/jna/5.9.0/javadoc/overview-summary.html#overview_description). Questions, comments, or exploratory conversations should begin on the [mailing list](http://groups.google.com/group/jna-users), although you may find it easier to find answers to already-solved problems on [StackOverflow](http://stackoverflow.com/questions/tagged/jna). JNA provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes. @@ -63,12 +63,12 @@ Pre-built platform support may be found [here](https://github.com/java-native-ac Download ======== -Version 5.8.0 +Version 5.9.0 JNA --- -[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna/5.8.0/jar) [jna-5.8.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.8.0/jna-5.8.0.jar) [jna-5.8.0-jpms.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.8.0/jna-5.8.0-jpms.jar) +[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna/5.9.0/jar) [jna-5.9.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.9.0/jna-5.9.0.jar) [jna-jpms-5.9.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-jpms/5.9.0/jna-jpms-5.9.0.jar) This is the core artifact of JNA and contains only the binding library and the core helper classes. @@ -76,7 +76,7 @@ core helper classes. JNA Platform ------------ -[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna-platform.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna-platform/5.8.0/jar) [jna-platform-5.8.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.8.0/jna-platform-5.8.0.jar) [jna-platform-5.8.0-jpms.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.8.0/jna-platform-5.8.0-jpms.jar) +[![Maven Central](https://img.shields.io/maven-central/v/net.java.dev.jna/jna-platform.svg?label=Maven%20Central)](https://search.maven.org/artifact/net.java.dev.jna/jna-platform/5.9.0/jar) [jna-platform-5.9.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform/5.9.0/jna-platform-5.9.0.jar) [jna-platform-jpms-5.9.0.jar](https://repo1.maven.org/maven2/net/java/dev/jna/jna-platform-jpms/5.9.0/jna-platform-jpms-5.9.0.jar) This artifact holds cross-platform mappings and mappings for a number of commonly used platform functions, including a large number of Win32 mappings as well as a set of utility classes @@ -144,12 +144,12 @@ Using the Library * [Platform Library](https://github.com/java-native-access/jna/blob/master/www/PlatformLibrary.md) * [Direct Method Mapping](https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md) (Optimization) * [Frequently Asked Questions (FAQ)](https://github.com/java-native-access/jna/blob/master/www/FrequentlyAskedQuestions.md) -* [Avoiding Crashes](http://java-native-access.github.io/jna/5.8.0/javadoc/overview-summary.html#crash-protection) +* [Avoiding Crashes](http://java-native-access.github.io/jna/5.9.0/javadoc/overview-summary.html#crash-protection) Primary Documentation (JavaDoc) =============================== -The definitive JNA reference is in the [JavaDoc](http://java-native-access.github.io/jna/5.8.0/javadoc/). +The definitive JNA reference is in the [JavaDoc](http://java-native-access.github.io/jna/5.9.0/javadoc/). Developers ========== diff --git a/appveyor.yml b/appveyor.yml index 1d83ac9b63..9c70df44d6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,14 +8,14 @@ environment: matrix: - TARGET_ARCH: x86_64 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - CYGWIN_PACKAGES: git,make,automake,libtool,mingw64-x86_64-gcc-g++,mingw64-x86_64-gcc-core + CYGWIN_PACKAGES: git,make,automake,libtool,mingw64-x86_64-gcc-g++,mingw64-x86_64-gcc-core,perl CHOCO_PACKAGES: ant cygwin CYGWIN_SETUP: cygwinsetup.exe # from choco JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - TARGET_ARCH: x86 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - CYGWIN_PACKAGES: git,make,automake,libtool,mingw64-i686-gcc-g++,mingw64-i686-gcc-core + CYGWIN_PACKAGES: git,make,automake,libtool,mingw64-i686-gcc-g++,mingw64-i686-gcc-core,perl CHOCO_PACKAGES: ant cygwin CYGWIN_SETUP: cygwinsetup.exe # from choco JAVA_HOME: C:\Program Files (x86)\Java\jdk1.8.0 # 32-bit diff --git a/build.xml b/build.xml index df60753685..99fec09dc6 100644 --- a/build.xml +++ b/build.xml @@ -63,7 +63,7 @@ - + @@ -1615,7 +1615,7 @@ cd .. - + diff --git a/contrib/platform/build.xml b/contrib/platform/build.xml index 51d54e1688..47fa8ed330 100644 --- a/contrib/platform/build.xml +++ b/contrib/platform/build.xml @@ -206,9 +206,9 @@ com.sun.jna.platform.wince;version=${osgi.version} - - - + + + 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ValueMeaning
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.