1/*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23/*
24 *
25 *
26 * A simple tool to output all the installed locales on a Windows machine, and
27 * corresponding Java default locale/file.encoding using PrintDefaultLocale
28 *
29 * WARNING:  This tool directly modifies the locale info in the Windows registry.
30 * It may not work with the Windows versions after Windows XP SP2.  Also,
31 * if the test did not complete or was manually killed, you will need to reset
32 * the user default locale in the Control Panel manually. This executable has
33 * to be run with the "Administrator" privilege.
34 *
35 * Usage: "deflocale.exe <java launcher> PrintDefaultLocale
36 *
37 * How to compile: "cl -DUNICODE -D_UNICODE deflocale.c user32.lib advapi32.lib"
38 */
39#include <windows.h>
40#include <stdio.h>
41#include <memory.h>
42
43wchar_t* launcher;
44wchar_t szBuffer[MAX_PATH];
45LCID LCIDArray[1024];
46int numLCIDs = 0;
47BOOL isWin7orUp = FALSE;
48
49// for Windows 7
50BOOL (WINAPI * pfnEnumSystemLocalesEx)(LPVOID, DWORD, LPARAM, LPVOID);
51BOOL (WINAPI * pfnEnumUILanguages)(LPVOID, DWORD, LPARAM);
52LCID (WINAPI * pfnLocaleNameToLCID)(LPCWSTR, DWORD);
53int (WINAPI * pfnLCIDToLocaleName)(LCID, LPWSTR, int, DWORD);
54wchar_t* LocaleNamesArray[1024];
55wchar_t* UILangNamesArray[1024];
56int numLocaleNames = 0;
57int numUILangNames = 0;
58
59void launchAndWait() {
60    STARTUPINFO si;
61    PROCESS_INFORMATION pi;
62
63    ZeroMemory(&si, sizeof(si));
64    si.cb = sizeof(si);
65    ZeroMemory(&pi, sizeof(pi));
66    if (CreateProcess(NULL, launcher, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)==0) {
67        wprintf(L"CreateProcess failed with the error code: %x\n", GetLastError());
68    }
69
70    WaitForSingleObject( pi.hProcess, INFINITE );
71}
72
73void testLocale(int anLCID, wchar_t* pName) {
74    HKEY hk;
75
76    if (pName != NULL && wcslen(pName) == 2) {
77        // ignore language only locale.
78        return;
79    }
80
81    wprintf(L"\n");
82    wprintf(L"OS Locale (lcid: %x", anLCID);
83    if (pName != NULL) {
84        wprintf(L", name: %s", pName);
85    }
86    GetLocaleInfo(anLCID, LOCALE_SENGLANGUAGE, szBuffer, MAX_PATH);
87    wprintf(L"): %s (", szBuffer);
88    GetLocaleInfo(anLCID, LOCALE_SENGCOUNTRY, szBuffer, MAX_PATH);
89    wprintf(L"%s) - ", szBuffer);
90    GetLocaleInfo(anLCID, LOCALE_IDEFAULTANSICODEPAGE, szBuffer, MAX_PATH);
91    wprintf(L"%s\n", szBuffer);
92    fflush(0);
93
94    if (RegOpenKeyEx(HKEY_CURRENT_USER, L"Control Panel\\International", 0, KEY_READ | KEY_WRITE, &hk) == ERROR_SUCCESS) {
95        wchar_t originalLocale[16];
96        wchar_t testLocale[16];
97        wchar_t* pKeyName;
98        DWORD cb = sizeof(originalLocale);
99        DWORD cbTest;
100
101        if (isWin7orUp) {
102            pKeyName = L"LocaleName";
103            wcscpy(testLocale, pName);
104            cbTest = wcslen(pName) * sizeof(wchar_t);
105        } else {
106            pKeyName = L"Locale";
107            swprintf(testLocale, L"%08x", anLCID);
108            cbTest = sizeof(wchar_t) * 8;
109        }
110
111        RegQueryValueEx(hk, pKeyName, 0, 0, (LPBYTE)originalLocale, &cb);
112        RegSetValueEx(hk, pKeyName, 0, REG_SZ, (LPBYTE)testLocale, cbTest );
113        launchAndWait();
114        RegSetValueEx(hk, pKeyName, 0, REG_SZ, (LPBYTE)originalLocale, cb);
115        RegCloseKey(hk);
116    }
117}
118
119void testUILang(wchar_t* pName) {
120    HKEY hk;
121
122    wprintf(L"\n");
123    wprintf(L"OS UI Language (name: %s)\n", pName);
124    fflush(0);
125
126    if (RegOpenKeyEx(HKEY_CURRENT_USER, L"Control Panel\\Desktop", 0, KEY_READ | KEY_WRITE, &hk) == ERROR_SUCCESS) {
127        wchar_t originalUILang[16];
128        wchar_t testUILang[16];
129        wchar_t* pKeyName;
130        DWORD cb = sizeof(originalUILang);
131        DWORD cbTest = wcslen(pName) * sizeof(wchar_t);
132
133        pKeyName = L"PreferredUILanguages";
134        wcscpy(testUILang, pName);
135        cbTest = wcslen(pName) * sizeof(wchar_t);
136
137        RegQueryValueEx(hk, pKeyName, 0, 0, (LPBYTE)originalUILang, &cb);
138        RegSetValueEx(hk, pKeyName, 0, REG_SZ, (LPBYTE)testUILang, cbTest);
139        launchAndWait();
140        RegSetValueEx(hk, pKeyName, 0, REG_SZ, (LPBYTE)originalUILang, cb);
141        RegCloseKey(hk);
142    }
143}
144
145BOOL CALLBACK EnumLocalesProc(LPWSTR lpLocaleStr) {
146    swscanf(lpLocaleStr, L"%08x", &LCIDArray[numLCIDs]);
147    numLCIDs ++;
148
149    return TRUE;
150}
151
152BOOL CALLBACK EnumLocalesProcEx(LPWSTR lpLocaleStr, DWORD flags, LPARAM lp) {
153    wchar_t* pName = malloc((wcslen(lpLocaleStr) + 1) * sizeof(wchar_t *));
154    wcscpy(pName, lpLocaleStr);
155    LocaleNamesArray[numLocaleNames] = pName;
156    numLocaleNames ++;
157
158    return TRUE;
159}
160
161BOOL CALLBACK EnumUILanguagesProc(LPWSTR lpUILangStr, LPARAM lp) {
162    wchar_t* pName = malloc((wcslen(lpUILangStr) + 1) * sizeof(wchar_t *));
163    wcscpy(pName, lpUILangStr);
164    UILangNamesArray[numUILangNames] = pName;
165    numUILangNames ++;
166
167    return TRUE;
168}
169
170int sortLCIDs(LCID * pLCID1, LCID * pLCID2) {
171    if (*pLCID1 < *pLCID2) return (-1);
172    if (*pLCID1 == *pLCID2) return 0;
173    return 1;
174}
175
176int sortLocaleNames(wchar_t** ppName1, wchar_t** ppName2) {
177    LCID l1 = pfnLocaleNameToLCID(*ppName1, 0);
178    LCID l2 = pfnLocaleNameToLCID(*ppName2, 0);
179    return sortLCIDs(&l1, &l2);
180}
181
182int main(int argc, char** argv) {
183    OSVERSIONINFO osvi;
184    LPWSTR commandline = GetCommandLine();
185    int i;
186
187    osvi.dwOSVersionInfoSize = sizeof(osvi);
188    GetVersionEx(&osvi);
189    wprintf(L"# OSVersionInfo\n");
190    wprintf(L"# MajorVersion: %d\n", osvi.dwMajorVersion);
191    wprintf(L"# MinorVersion: %d\n", osvi.dwMinorVersion);
192    wprintf(L"# BuildNumber: %d\n", osvi.dwBuildNumber);
193    wprintf(L"# CSDVersion: %s\n", osvi.szCSDVersion);
194    wprintf(L"\n");
195    fflush(0);
196
197    launcher = wcschr(commandline, L' ')+1;
198    while (*launcher == L' ') {
199        launcher++;
200    }
201
202    isWin7orUp = (osvi.dwMajorVersion > 6) ||
203                 (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 1);
204
205    if (!isWin7orUp) {
206        // Enumerate locales
207        EnumSystemLocales(EnumLocalesProc, LCID_INSTALLED);
208
209        // Sort LCIDs
210        qsort(LCIDArray, numLCIDs, sizeof(LCID), (void *)sortLCIDs);
211    } else {
212        // For Windows 7, use "LocaleName" registry key for the user locale
213        // as they seem to switch from "Locale".
214        HMODULE hmod = GetModuleHandle(L"kernel32");
215        *(FARPROC*)&pfnEnumSystemLocalesEx =
216            GetProcAddress(hmod, "EnumSystemLocalesEx");
217        *(FARPROC*)&pfnEnumUILanguages =
218            GetProcAddress(hmod, "EnumUILanguagesW");
219        *(FARPROC*)&pfnLocaleNameToLCID =
220            GetProcAddress(hmod, "LocaleNameToLCID");
221        *(FARPROC*)&pfnLCIDToLocaleName =
222            GetProcAddress(hmod, "LCIDToLocaleName");
223        if (pfnEnumSystemLocalesEx != NULL &&
224            pfnEnumUILanguages != NULL &&
225            pfnLocaleNameToLCID != NULL &&
226            pfnLCIDToLocaleName != NULL) {
227            // Enumerate locales
228            pfnEnumSystemLocalesEx(EnumLocalesProcEx,
229                    1, // LOCALE_WINDOWS
230                    (LPARAM)NULL, NULL);
231            // Enumerate UI Languages.
232            pfnEnumUILanguages(EnumUILanguagesProc,
233                    0x8, // MUI_LANGUAGE_NAME
234                    (LPARAM)NULL);
235        } else {
236            wprintf(L"Could not get needed entry points. quitting.\n");
237            exit(-1);
238        }
239
240        // Sort LocaleNames
241        qsort(LocaleNamesArray, numLocaleNames,
242              sizeof(wchar_t*), (void *)sortLocaleNames);
243        qsort(UILangNamesArray, numUILangNames,
244              sizeof(wchar_t*), (void *)sortLocaleNames);
245    }
246
247    // Execute enumeration of Java default locales
248    if (isWin7orUp) {
249        for (i = 0; i < numLocaleNames; i ++) {
250            testLocale(pfnLocaleNameToLCID(LocaleNamesArray[i], 0),
251                                     LocaleNamesArray[i]);
252        }
253        for (i = 0; i < numUILangNames; i ++) {
254            testUILang(UILangNamesArray[i]);
255        }
256    } else {
257        for (i = 0; i < numLCIDs; i ++) {
258            testLocale(LCIDArray[i], NULL);
259        }
260    }
261}
262