windows: add Get*PreferredUILanguages
This commit adds the following MUI functions:
- GetUserPreferredUILanguages
- GetSystemPreferredUILanguages
- GetThreadPreferredUILanguages
- GetProcessPreferredUILanguages
Change-Id: I44f1c07245ab814935778c6b910b224d24cc753c
Reviewed-on: https://go-review.googlesource.com/c/sys/+/207860
Reviewed-by: Simon Rozman <simon@rozman.si>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go
index fe8e42c..79ce915 100644
--- a/windows/syscall_windows.go
+++ b/windows/syscall_windows.go
@@ -313,6 +313,10 @@
//sys CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
+//sys getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetProcessPreferredUILanguages
+//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
+//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
+//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
// Process Status API (PSAPI)
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
@@ -1378,3 +1382,54 @@
buildNumber &= 0xffff
return
}
+
+// GetProcessPreferredUILanguages retrieves the process preferred UI languages.
+func GetProcessPreferredUILanguages(flags uint32) ([]string, error) {
+ return getUILanguages(flags, getProcessPreferredUILanguages)
+}
+
+// GetThreadPreferredUILanguages retrieves the thread preferred UI languages for the current thread.
+func GetThreadPreferredUILanguages(flags uint32) ([]string, error) {
+ return getUILanguages(flags, getThreadPreferredUILanguages)
+}
+
+// GetUserPreferredUILanguages retrieves information about the user preferred UI languages.
+func GetUserPreferredUILanguages(flags uint32) ([]string, error) {
+ return getUILanguages(flags, getUserPreferredUILanguages)
+}
+
+// GetSystemPreferredUILanguages retrieves the system preferred UI languages.
+func GetSystemPreferredUILanguages(flags uint32) ([]string, error) {
+ return getUILanguages(flags, getSystemPreferredUILanguages)
+}
+
+func getUILanguages(flags uint32, f func(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) error) ([]string, error) {
+ size := uint32(128)
+ for {
+ var numLanguages uint32
+ buf := make([]uint16, size)
+ err := f(flags, &numLanguages, &buf[0], &size)
+ if err == ERROR_INSUFFICIENT_BUFFER {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ buf = buf[:size]
+ if numLanguages == 0 || len(buf) == 0 { // GetProcessPreferredUILanguages may return numLanguages==0 with "\0\0"
+ return []string{}, nil
+ }
+ if buf[len(buf)-1] == 0 {
+ buf = buf[:len(buf)-1] // remove terminating null
+ }
+ languages := make([]string, 0, numLanguages)
+ from := 0
+ for i, c := range buf {
+ if c == 0 {
+ languages = append(languages, string(utf16.Decode(buf[from:i])))
+ from = i + 1
+ }
+ }
+ return languages, nil
+ }
+}
diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go
index 7f23216..86d0d7b 100644
--- a/windows/syscall_windows_test.go
+++ b/windows/syscall_windows_test.go
@@ -10,6 +10,7 @@
"os"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"syscall"
"testing"
@@ -377,3 +378,29 @@
t.Errorf("totalNumberOfFreeBytes: got 0; want > 0")
}
}
+
+func TestGetPreferredUILanguages(t *testing.T) {
+ tab := map[string]func(flags uint32) ([]string, error){
+ "GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages,
+ "GetThreadPreferredUILanguages": windows.GetThreadPreferredUILanguages,
+ "GetUserPreferredUILanguages": windows.GetUserPreferredUILanguages,
+ "GetSystemPreferredUILanguages": windows.GetSystemPreferredUILanguages,
+ }
+ for fName, f := range tab {
+ lang, err := f(windows.MUI_LANGUAGE_ID)
+ if err != nil {
+ t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err)
+ }
+ for _, l := range lang {
+ _, err := strconv.ParseUint(l, 16, 16)
+ if err != nil {
+ t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l)
+ }
+ }
+
+ lang, err = f(windows.MUI_LANGUAGE_NAME)
+ if err != nil {
+ t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err)
+ }
+ }
+}
diff --git a/windows/types_windows.go b/windows/types_windows.go
index 7f178bb..8dd95a0 100644
--- a/windows/types_windows.go
+++ b/windows/types_windows.go
@@ -1742,3 +1742,36 @@
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4
)
+
+// MUI function flag values
+const (
+ MUI_LANGUAGE_ID = 0x4
+ MUI_LANGUAGE_NAME = 0x8
+ MUI_MERGE_SYSTEM_FALLBACK = 0x10
+ MUI_MERGE_USER_FALLBACK = 0x20
+ MUI_UI_FALLBACK = MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK
+ MUI_THREAD_LANGUAGES = 0x40
+ MUI_CONSOLE_FILTER = 0x100
+ MUI_COMPLEX_SCRIPT_FILTER = 0x200
+ MUI_RESET_FILTERS = 0x001
+ MUI_USER_PREFERRED_UI_LANGUAGES = 0x10
+ MUI_USE_INSTALLED_LANGUAGES = 0x20
+ MUI_USE_SEARCH_ALL_LANGUAGES = 0x40
+ MUI_LANG_NEUTRAL_PE_FILE = 0x100
+ MUI_NON_LANG_NEUTRAL_FILE = 0x200
+ MUI_MACHINE_LANGUAGE_SETTINGS = 0x400
+ MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL = 0x001
+ MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN = 0x002
+ MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI = 0x004
+ MUI_QUERY_TYPE = 0x001
+ MUI_QUERY_CHECKSUM = 0x002
+ MUI_QUERY_LANGUAGE_NAME = 0x004
+ MUI_QUERY_RESOURCE_TYPES = 0x008
+ MUI_FILEINFO_VERSION = 0x001
+
+ MUI_FULL_LANGUAGE = 0x01
+ MUI_PARTIAL_LANGUAGE = 0x02
+ MUI_LIP_LANGUAGE = 0x04
+ MUI_LANGUAGE_INSTALLED = 0x20
+ MUI_LANGUAGE_LICENSED = 0x40
+)
diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go
index 6658ccd..7bed68b 100644
--- a/windows/zsyscall_windows.go
+++ b/windows/zsyscall_windows.go
@@ -248,6 +248,10 @@
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree")
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers")
+ procGetProcessPreferredUILanguages = modkernel32.NewProc("GetProcessPreferredUILanguages")
+ procGetThreadPreferredUILanguages = modkernel32.NewProc("GetThreadPreferredUILanguages")
+ procGetUserPreferredUILanguages = modkernel32.NewProc("GetUserPreferredUILanguages")
+ procGetSystemPreferredUILanguages = modkernel32.NewProc("GetSystemPreferredUILanguages")
procEnumProcesses = modpsapi.NewProc("EnumProcesses")
procWSAStartup = modws2_32.NewProc("WSAStartup")
procWSACleanup = modws2_32.NewProc("WSACleanup")
@@ -2760,6 +2764,54 @@
return
}
+func getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetProcessPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetThreadPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetUserPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetSystemPreferredUILanguages.Addr(), 4, uintptr(flags), uintptr(unsafe.Pointer(numLanguages)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(bufSize)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) {
var _p0 *uint32
if len(processIds) > 0 {