Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add SetThreadUILanguage, SetThreadPreferredUILanguages and GetThreadUILanguage in c.s.j.p.win32.Kernel32 #1514

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -7,6 +7,7 @@ Next Release (5.14.0)

Features
--------
* [#1514](https://github.com/java-native-access/jna/pull/1514): Add `SetThreadUILanguage`, `SetThreadPreferredUILanguages` and `GetThreadUILanguage` in `c.s.j.p.win32.Kernel32` - [@overpathz](https://github.com/overpathz).

Bug Fixes
---------
Expand Down
75 changes: 73 additions & 2 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Expand Up @@ -26,8 +26,6 @@
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;
Expand Down Expand Up @@ -4387,4 +4385,77 @@ Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize,
* </p>
*/
boolean VirtualUnlock(Pointer lpAddress, SIZE_T dwSize);

/**
* Sets the user interface language for the current thread.
*
* <p>
* Windows Vista and later: This function cannot clear the thread preferred UI languages list. Your MUI application
* should call SetThreadPreferredUILanguages to clear the language list.
* </p>
* <p>
* Windows XP: This function is limited to allowing the operating system to identify and set a value that is safe
* to use on the Windows console.
* </p>
*
* <p><strong>Remarks</strong></p>
* <p>
overpathz marked this conversation as resolved.
Show resolved Hide resolved
* When a thread is created, the thread user interface language setting is empty and the user interface for
* the thread is displayed in the user-selected language. This function enables the application to change
* the user interface language for the current running thread.
* </p>
* <p>
* Windows Vista and later: Calling this function and specifying 0 for the language identifier is identical
* to calling SetThreadPreferredUILanguages with the MUI_CONSOLE_FILTER flag set. If the application specifies
* a valid nonzero language identifier, the function sets a particular user interface language for the thread.
* </p>
*
* @param LangId Language identifier for the user interface language for the thread.
*
* @return Returns the input language identifier if successful.
* If the input identifier is nonzero, the function returns that value.
* If the language identifier is 0, the function always succeeds and returns
* the identifier of the language that best supports the Windows console.
*
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-setthreaduilanguage">SetThreadUILanguage</a>
*/
int SetThreadUILanguage(int LangId);

/**
* Sets the thread preferred UI languages for the current thread.
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/intl/user-interface-language-management">User Interface Language Management</a>
*
* @param dwFlags Flags identifying format and filtering for the languages to set.
*
* <p>
* The following format flags specify the language format to use for the thread preferred UI languages.
* The flags are mutually exclusive, and the default is MUI_LANGUAGE_NAME.
* </p>
* <p>
* We recommend that you use MUI_LANGUAGE_NAME instead of MUI_LANGUAGE_ID.
* </p>
*
* @param pwszLanguagesBuffer Pointer to a double null-terminated multi-string buffer that contains an ordered,
* null-delimited list, in the format specified by dwFlags.
* <p>
* To clear the thread preferred UI languages list, an application sets this parameter to a null string or an empty
* double null-terminated string. If an application clears a language list, it should specify either a format flag
* or 0 for the dwFlags parameter.
* </p>
*
* @param pulNumLanguages Pointer to the number of languages that the function has set in the thread preferred UI languages list.
* When the application specifies one of the filtering flags, the function must set this parameter to NULL.
*
* @return Returns {@code true} if the function succeeds or {@code false} otherwise.
*/
boolean SetThreadPreferredUILanguages(int dwFlags, String[] pwszLanguagesBuffer, IntByReference pulNumLanguages);

/**
* Returns the language identifier of the first user interface language for the current thread.
*
* @return Returns the identifier for a language explicitly associated with the thread by SetThreadUILanguage or
* SetThreadPreferredUILanguages. Alternatively, if no language has been explicitly associated with the
* current thread, the identifier can indicate a user or system user interface language.
*/
int GetThreadUILanguage();
}
12 changes: 12 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Expand Up @@ -299,6 +299,18 @@ public static String getLastErrorMessage(int primaryLangId, int sublangId) {
.GetLastError(), primaryLangId, sublangId);
}

/**
* Sets the thread preferred UI languages for the current thread.
*
* @param languages String array of preferred languages to set.
*
* @return Returns TRUE if the function succeeds or FALSE otherwise.
overpathz marked this conversation as resolved.
Show resolved Hide resolved
*/
public static boolean setThreadPreferredUILanguages(String[] languages) {
IntByReference pulNumLanguages = new IntByReference(languages.length);
return Kernel32.INSTANCE.SetThreadPreferredUILanguages(0, languages, pulNumLanguages);
}

/**
* Return the path designated for temporary files.
*
Expand Down
29 changes: 29 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
Expand Up @@ -63,6 +63,7 @@
import com.sun.jna.NativeMappedConverter;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;

import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTRByReference;
Expand Down Expand Up @@ -2099,4 +2100,32 @@ public void testVirtualLockUnlock() {
// Unlocking an unlocked region should fail
assertFalse(Kernel32.INSTANCE.VirtualUnlock(mem, new SIZE_T(4096)));
}

public void testSetThreadUILanguage() {
int langId = 0x0409; // English (United States)
int result = Kernel32.INSTANCE.SetThreadUILanguage(langId);
if (result == 0) {
int errorCode = Kernel32.INSTANCE.GetLastError();
fail("SetThreadUILanguage failed with error code " + errorCode);
}
assertEquals(langId, result);
}

public void testSetThreadPreferredUILanguages() {
String[] languages = {};
IntByReference pulNumLanguages = new IntByReference(languages.length);
boolean result = Kernel32.INSTANCE.SetThreadPreferredUILanguages(0, languages, pulNumLanguages);
assertTrue(result);
}

public void testGetThreadUILanguage() {
int langId = 0x0409; // English (United States)
int result = Kernel32.INSTANCE.SetThreadUILanguage(langId);
if (result == 0) {
int errorCode = Kernel32.INSTANCE.GetLastError();
fail("SetThreadUILanguage failed with error code " + errorCode);
}
int uiLangId = Kernel32.INSTANCE.GetThreadUILanguage();
assertEquals(langId, uiLangId);
}
}
Expand Up @@ -171,6 +171,12 @@ public void testFormatMessageFromErrorCodeWithNonEnglishLocale() {
}
}

public void testSetThreadPreferredUILanguages() {
String[] languages = {};
boolean result = Kernel32Util.setThreadPreferredUILanguages(languages);
assertTrue(result);
}

public void testGetTempPath() {
assertTrue(Kernel32Util.getTempPath().length() > 0);
}
Expand Down