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

Provide multilingual support of Kernel32Util.formatMessage() #1482

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Features
* [#1459](https://github.com/java-native-access/jna/pull/1459): Add `VirtualLock` and `VirtualUnlock` in `c.s.j.p.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#1471](https://github.com/java-native-access/jna/pull/1471): Add `c.s.j.p.win32.Advapi32Util#isCurrentProcessElevated` and associated Types - [@dbwiddis](https://github.com/dbwiddis).
* [#1474](https://github.com/java-native-access/jna/pull/1474): Add `c.s.j.p.win32.WbemCli#IWbemClassObject.IWbemQualifierSet`, `IWbemServices.GetObject`, `IWbemContext.SetValue` and associated methods - [@rchateauneu](https://github.com/rchateauneu).
* [#1482](https://github.com/java-native-access/jna/pull/1482): Add multilingual support of `Kernel32Util.formatMessage` - [@overpathz](https://github.com/overpathz).

Bug Fixes
---------
Expand Down
72 changes: 66 additions & 6 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,43 @@ public static void closeHandle(HANDLE h) {
}
}

/**
* Format a message from a code.
*
* @param code The error code
* @return Formatted message in the default locale.
*/
public static String formatMessage(int code) {
return formatMessage(code, 0, 0);
}

/**
* Format a message from the value obtained from
* {@link Kernel32#GetLastError()} or {@link Native#getLastError()}.
*
* <p>If you pass in zero, FormatMessage looks for a message for LANGIDs in the following order:</p>
* <ol>
* <li>Language neutral</li>
* <li>Thread LANGID, based on the thread's locale value</li>
* <li>User default LANGID, based on the user's default locale value</li>
* <li>System default LANGID, based on the system default locale value</li>
* <li>US English</li>
* </ol>
*
* @param code The error code
* @return Formatted message.
* @param primaryLangId The primary language identifier
* @param sublangId The sublanguage identifier
* @return Formatted message in the specified locale.
*/
public static String formatMessage(int code) {
public static String formatMessage(int code, int primaryLangId, int sublangId) {
PointerByReference buffer = new PointerByReference();
int nLen = Kernel32.INSTANCE.FormatMessage(
WinBase.FORMAT_MESSAGE_ALLOCATE_BUFFER
| WinBase.FORMAT_MESSAGE_FROM_SYSTEM
| WinBase.FORMAT_MESSAGE_IGNORE_INSERTS,
null,
code,
0, // TODO: // MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
WinNT.LocaleMacros.MAKELANGID(primaryLangId, sublangId),
buffer, 0, null);
if (nLen == 0) {
throw new LastErrorException(Native.getLastError());
Expand All @@ -213,32 +234,71 @@ public static String formatMessage(int code) {
*
* @param code
* HRESULT
* @return Formatted message.
* @return Formatted message in the default locale.
*/
public static String formatMessage(HRESULT code) {
return formatMessage(code.intValue());
}

/**
* Format a message from an HRESULT.
*
* @param code
* HRESULT
* @param primaryLangId
* The primary language identifier
* @param sublangId
* The primary language identifier
* @return Formatted message in the specified locale.
*/
public static String formatMessage(HRESULT code, int primaryLangId, int sublangId) {
return formatMessage(code.intValue(), primaryLangId, sublangId);
}

/**
* Format a system message from an error code.
*
* @param code
* Error code, typically a result of GetLastError.
* @return Formatted message.
* @return Formatted message in the default locale.
*/
public static String formatMessageFromLastErrorCode(int code) {
return formatMessage(W32Errors.HRESULT_FROM_WIN32(code));
}

/**
* Format a system message from an error code.
*
* @param code
* Error code, typically a result of GetLastError.
* @param primaryLangId
* The primary language identifier
* @param sublangId
* The primary language identifier
* @return Formatted message in the specified locale.
*/
public static String formatMessageFromLastErrorCode(int code, int primaryLangId, int sublangId) {
return formatMessage(W32Errors.HRESULT_FROM_WIN32(code), primaryLangId, sublangId);
}

/**
* @return Obtains the human-readable error message text from the last error
* that occurred by invocating {@code Kernel32.GetLastError()}.
* that occurred by invocating {@code Kernel32.GetLastError()} in the default locale.
*/
public static String getLastErrorMessage() {
return Kernel32Util.formatMessageFromLastErrorCode(Kernel32.INSTANCE
.GetLastError());
}

/**
* @return Obtains the human-readable error message text from the last error
* that occurred by invocating {@code Kernel32.GetLastError()} in the specified locale.
*/
public static String getLastErrorMessage(int primaryLangId, int sublangId) {
return Kernel32Util.formatMessageFromLastErrorCode(Kernel32.INSTANCE
.GetLastError(), primaryLangId, sublangId);
}

/**
* Return the path designated for temporary files.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ public void testFormatMessageFromHR() {
}
}

public void testFormatMessageFromErrorCodeWithNonEnglishLocale() {
int errorCode = W32Errors.S_OK.intValue();
String formattedMsgInDefaultLocale = Kernel32Util.formatMessage(errorCode);
// primary and sub languages id's of the english locale, because it is present on most machines
String formattedMsgInEnglishLocale = Kernel32Util.formatMessage(errorCode, 9, 1);
if(AbstractWin32TestSupport.isEnglishLocale) {
assertEquals(formattedMsgInDefaultLocale, formattedMsgInEnglishLocale);
} else {
assertNotSame(formattedMsgInDefaultLocale, formattedMsgInEnglishLocale);
}
}

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