Skip to content

Commit

Permalink
Set user interface language for current thread
Browse files Browse the repository at this point in the history
- Bind SetThreadUILanguage, SetThreadPreferredUILanguages and GetThreadUILanguage in c.s.j.p.win32.Kernel32
- test is written
- update CHANGES.md
- remove unused imports in Kernel32.java
  • Loading branch information
overpathz committed Mar 29, 2023
1 parent e96f301 commit f9e5f5b
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 2 deletions.
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>
* 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.
*/
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

0 comments on commit f9e5f5b

Please sign in to comment.