xref: /reactos/dll/cpl/intl/advanced.c (revision 80774a2f)
1 #include "intl.h"
2 #include <wingdi.h>
3 
4 #include <debug.h>
5 
6 typedef struct CPStruct
7 {
8     UINT CodePage;
9     DWORD Flags;
10     WCHAR Name[MAX_PATH];
11     struct CPStruct *NextItem;
12 } CPAGE, *PCPAGE;
13 
14 #define CODEPAGE_INSTALLED      0x00000001
15 #define CODEPAGE_NOT_REMOVEABLE 0x00000002
16 #define CODEPAGE_INSTALL        0x00000004
17 #define CODEPAGE_REMOVE         0x00000008
18 
19 static PCPAGE PCPage = NULL;
20 static BOOL bSpain = FALSE;
21 static HWND hLangList;
22 
23 static BOOL
24 GetSupportedCP(
25     HINF hInf)
26 {
27     WCHAR szSection[MAX_PATH];
28     INFCONTEXT Context, Context2;
29     PCPAGE pCodePage;
30     CPINFOEX cpInfEx;
31     UINT uiCodePage;
32 
33     if (!SetupFindFirstLine(hInf,
34                             L"CodePages",
35                             NULL,
36                             &Context))
37         return FALSE;
38 
39     for (;;)
40     {
41         if (SetupGetIntField(&Context, 0, (PINT)&uiCodePage))
42         {
43             pCodePage = HeapAlloc(GetProcessHeap(), 0, sizeof(CPAGE));
44             if (pCodePage == NULL)
45                 return FALSE;
46 
47             pCodePage->CodePage = uiCodePage;
48             pCodePage->Flags = 0;
49             (pCodePage->Name)[0] = UNICODE_NULL;
50 
51             if (GetCPInfoExW(uiCodePage, 0, &cpInfEx))
52             {
53                 wcscpy(pCodePage->Name, cpInfEx.CodePageName);
54             }
55             else
56             {
57                 SetupGetStringFieldW(&Context, 1, pCodePage->Name, MAX_PATH, NULL);
58             }
59 
60             if (wcslen(pCodePage->Name) != 0)
61             {
62                 pCodePage->NextItem = PCPage;
63                 PCPage = pCodePage;
64 
65                 wsprintf(szSection, L"CODEPAGE_REMOVE_%d", uiCodePage);
66 
67                 if ((uiCodePage == GetACP()) ||
68                     (uiCodePage == GetOEMCP()) ||
69                     (!SetupFindFirstLineW(hInf, szSection, L"AddReg", &Context2)))
70                 {
71                     pCodePage->Flags |= CODEPAGE_NOT_REMOVEABLE;
72                 }
73             }
74             else
75             {
76                 HeapFree(GetProcessHeap(), 0, pCodePage);
77             }
78         }
79 
80         if (!SetupFindNextLine(&Context, &Context))
81             break;
82     }
83 
84     return TRUE;
85 }
86 
87 static BOOL CALLBACK
88 InstalledCPProc(PWSTR lpStr)
89 {
90     PCPAGE lpCP;
91     UINT uiCP;
92 
93     lpCP = PCPage;
94     uiCP = _wtol(lpStr);
95 
96     for (;;)
97     {
98         if (!lpCP)
99             break;
100 
101         if (lpCP->CodePage == uiCP)
102         {
103             lpCP->Flags |= CODEPAGE_INSTALLED;
104             break;
105         }
106 
107         lpCP = lpCP->NextItem;
108     }
109 
110     return TRUE;
111 }
112 
113 static VOID
114 InitCodePagesList(HWND hwndDlg)
115 {
116     PCPAGE pCodePage;
117     INT ItemIndex;
118     HWND hList;
119     LV_COLUMN column;
120     LV_ITEM item;
121     RECT ListRect;
122     HINF hIntlInf;
123 
124     hIntlInf = SetupOpenInfFileW(L"intl.inf", NULL, INF_STYLE_WIN4, NULL);
125     if (hIntlInf == INVALID_HANDLE_VALUE)
126         return;
127 
128     if (!SetupOpenAppendInfFile(NULL, hIntlInf, NULL))
129     {
130         SetupCloseInfFile(hIntlInf);
131         hIntlInf = NULL;
132         return;
133     }
134 
135     if (!GetSupportedCP(hIntlInf))
136         return;
137 
138     SetupCloseInfFile(hIntlInf);
139 
140     if (!EnumSystemCodePagesW(InstalledCPProc, CP_INSTALLED))
141     {
142         /* Hack: EnumSystemCodePages returns FALSE on successful completion! */
143         /* return; */
144     }
145 
146     hList = GetDlgItem(hwndDlg, IDC_CONV_TABLES);
147 
148     ZeroMemory(&column, sizeof(LV_COLUMN));
149     column.mask = LVCF_FMT | LVCF_WIDTH;
150     column.fmt = LVCFMT_LEFT;
151     GetClientRect(hList, &ListRect);
152     column.cx = ListRect.right - GetSystemMetrics(SM_CYHSCROLL);
153     ListView_InsertColumn(hList, 0, &column);
154 
155     (VOID) ListView_SetExtendedListViewStyle(hList, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
156 
157     pCodePage = PCPage;
158 
159     for (;;)
160     {
161         if (pCodePage == NULL)
162             break;
163 
164         ZeroMemory(&item, sizeof(LV_ITEM));
165         item.mask      = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
166         item.state     = 0;
167         item.stateMask = LVIS_STATEIMAGEMASK;
168         item.pszText   = pCodePage->Name;
169         item.lParam    = (LPARAM)pCodePage;
170 
171         ItemIndex = ListView_InsertItem(hList, &item);
172         if (ItemIndex != -1)
173         {
174             if (pCodePage->Flags & CODEPAGE_INSTALLED)
175             {
176                 ListView_SetItemState(hList, ItemIndex,
177                                       INDEXTOSTATEIMAGEMASK(LVIS_SELECTED),
178                                       LVIS_STATEIMAGEMASK);
179             }
180             else
181             {
182                 ListView_SetItemState(hList, ItemIndex,
183                                       INDEXTOSTATEIMAGEMASK(LVIS_FOCUSED),
184                                       LVIS_STATEIMAGEMASK);
185             }
186         }
187 
188         pCodePage = pCodePage->NextItem;
189     }
190 }
191 
192 static BOOL CALLBACK
193 LocalesEnumProc(PWSTR lpLocale)
194 {
195     LCID lcid;
196     WCHAR lang[255];
197     INT index;
198     BOOL bNoShow = FALSE;
199 
200     lcid = wcstoul(lpLocale, NULL, 16);
201 
202     if (lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) ||
203         lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT))
204     {
205         if (bSpain == FALSE)
206         {
207             LoadStringW(hApplet, IDS_SPAIN, lang, 255);
208             bSpain = TRUE;
209         }
210         else
211         {
212             bNoShow = TRUE;
213         }
214     }
215     else
216     {
217         GetLocaleInfoW(lcid, LOCALE_SLANGUAGE, lang, sizeof(lang)/sizeof(WCHAR));
218     }
219 
220     if (bNoShow == FALSE)
221     {
222         index = SendMessageW(hLangList,
223                              CB_ADDSTRING,
224                              0,
225                              (LPARAM)lang);
226 
227         SendMessageW(hLangList,
228                      CB_SETITEMDATA,
229                      index,
230                      (LPARAM)lcid);
231     }
232 
233     return TRUE;
234 }
235 
236 static VOID
237 InitLanguagesList(
238     HWND hwndDlg,
239     PGLOBALDATA pGlobalData)
240 {
241     WCHAR langSel[255];
242 
243     hLangList = GetDlgItem(hwndDlg, IDC_LANGUAGE_COMBO);
244 
245     bSpain = FALSE;
246     EnumSystemLocalesW(LocalesEnumProc, LCID_SUPPORTED);
247 
248     /* Select current locale */
249     GetLocaleInfoW(pGlobalData->SystemLCID, LOCALE_SLANGUAGE, langSel, sizeof(langSel)/sizeof(WCHAR));
250 
251     SendMessageW(hLangList, CB_SELECTSTRING, -1, (LPARAM)langSel);
252 }
253 
254 static VOID
255 GetCurrentDPI(LPTSTR szDPI)
256 {
257     DWORD dwType, dwSize, dwDPI, dwDefDPI = 0x00000060; // Default 96 DPI
258     HKEY hKey;
259 
260     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI", 0, NULL,
261                         REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) != ERROR_SUCCESS)
262     {
263         wcscpy(szDPI, L"96");
264         return;
265     }
266 
267     dwType = REG_DWORD;
268     dwSize = sizeof(DWORD);
269 
270     if (RegQueryValueExW(hKey, L"LogPixels", NULL, &dwType, (LPBYTE)&dwDPI, &dwSize) != ERROR_SUCCESS)
271     {
272         if (RegSetValueExW(hKey, L"LogPixels", 0, REG_DWORD, (LPBYTE)&dwDefDPI, sizeof(DWORD)) == ERROR_SUCCESS)
273         {
274             wcscpy(szDPI, L"96");
275             RegCloseKey(hKey);
276             return;
277         }
278     }
279     else
280     {
281         wsprintf(szDPI, L"%d", dwDPI);
282     }
283 
284     RegCloseKey(hKey);
285 }
286 
287 static
288 VOID
289 SaveFontSubstitutionSettings(
290     HWND hwnd,
291     PGLOBALDATA pGlobalData)
292 {
293     WCHAR szDefCP[5 + 1], szSection[MAX_PATH], szDPI[3 + 1];
294     HINF hFontInf;
295     UINT Count;
296 
297     GetLocaleInfoW(MAKELCID(pGlobalData->SystemLCID, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, szDefCP, sizeof(szDefCP) / sizeof(WCHAR));
298     GetCurrentDPI(szDPI);
299 
300     wsprintf(szSection, L"Font.CP%s.%s", szDefCP, szDPI);
301 
302     hFontInf = SetupOpenInfFileW(L"font.inf", NULL, INF_STYLE_WIN4, NULL);
303     if (hFontInf == INVALID_HANDLE_VALUE)
304         return;
305 
306     if (!SetupOpenAppendInfFile(NULL, hFontInf, NULL))
307     {
308         SetupCloseInfFile(hFontInf);
309         return;
310     }
311 
312     Count = (UINT)SetupGetLineCount(hFontInf, szSection);
313     if (Count <= 0)
314         return;
315 
316     if (!SetupInstallFromInfSectionW(hwnd, hFontInf, szSection, SPINST_REGISTRY & ~SPINST_FILES,
317                                      NULL, NULL, 0, NULL, NULL, NULL, NULL))
318     {
319         MessageBoxW(hwnd, L"Unable to install a new language for programs don't support unicode!",
320                    NULL, MB_ICONERROR | MB_OK);
321     }
322 
323     SetupCloseInfFile(hFontInf);
324 }
325 
326 
327 static
328 VOID
329 SaveFontLinkingSettings(
330     HWND hwnd,
331     PGLOBALDATA pGlobalData)
332 {
333     /* TODO */
334 }
335 
336 
337 static
338 VOID
339 SaveSystemSettings(
340     PGLOBALDATA pGlobalData)
341 {
342     WCHAR ACPPage[9];
343     WCHAR OEMPage[9];
344     HKEY langKey;
345     DWORD ret;
346     WCHAR value[5];
347     DWORD valuesize;
348 
349     ret = GetLocaleInfoW(MAKELCID(pGlobalData->SystemLCID, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, OEMPage, sizeof(OEMPage)/sizeof(WCHAR));
350     if (ret == 0)
351     {
352         PrintErrorMsgBox(IDS_ERROR_OEM_CODE_PAGE);
353         return;
354     }
355 
356     ret = GetLocaleInfoW(MAKELCID(pGlobalData->SystemLCID, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, ACPPage, sizeof(ACPPage)/sizeof(WCHAR));
357     if (ret == 0)
358     {
359         PrintErrorMsgBox(IDS_ERROR_ANSI_CODE_PAGE);
360         return;
361     }
362 
363     /* Set codepages */
364     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage", &langKey);
365     if (ret != ERROR_SUCCESS)
366     {
367         PrintErrorMsgBox(IDS_ERROR_NLS_CODE_REG);
368         return;
369     }
370 
371     RegSetValueExW(langKey, L"OEMCP", 0, REG_SZ, (BYTE *)OEMPage, (wcslen(OEMPage) +1 ) * sizeof(WCHAR));
372     RegSetValueExW(langKey, L"ACP", 0, REG_SZ, (BYTE *)ACPPage, (wcslen(ACPPage) +1 ) * sizeof(WCHAR));
373 
374     RegCloseKey(langKey);
375 
376 
377     wsprintf(value, L"%04hX", LANGIDFROMLCID(pGlobalData->SystemLCID));
378     valuesize = (wcslen(value) + 1) * sizeof(WCHAR);
379 
380     /* Set language */
381     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language", &langKey);
382     if (ret != ERROR_SUCCESS)
383     {
384         PrintErrorMsgBox(IDS_ERROR_NLS_KEY_REG);
385         return;
386     }
387 
388     RegSetValueExW(langKey, L"Default", 0, REG_SZ, (BYTE *)value, valuesize);
389     RegCloseKey(langKey);
390 }
391 
392 
393 LRESULT
394 ListViewCustomDraw(
395     LPARAM lParam)
396 {
397     LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
398 
399     switch (lplvcd->nmcd.dwDrawStage)
400     {
401         case CDDS_PREPAINT:
402             return CDRF_NOTIFYITEMDRAW;
403 
404         case CDDS_ITEMPREPAINT:
405             if (((PCPAGE)lplvcd->nmcd.lItemlParam)->Flags & CODEPAGE_NOT_REMOVEABLE)
406             {
407                 lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT);
408             }
409             else
410             {
411                 lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT);
412             }
413             lplvcd->clrTextBk = GetSysColor(COLOR_WINDOW);
414             return CDRF_NEWFONT;
415     }
416 
417     return CDRF_DODEFAULT;
418 }
419 
420 
421 /* Property page dialog callback */
422 INT_PTR CALLBACK
423 AdvancedPageProc(HWND hwndDlg,
424                  UINT uMsg,
425                  WPARAM wParam,
426                  LPARAM lParam)
427 {
428     PGLOBALDATA pGlobalData;
429 
430     pGlobalData = (PGLOBALDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
431 
432     switch (uMsg)
433     {
434         case WM_INITDIALOG:
435             pGlobalData = (PGLOBALDATA)((LPPROPSHEETPAGE)lParam)->lParam;
436             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
437 
438             InitLanguagesList(hwndDlg, pGlobalData);
439             InitCodePagesList(hwndDlg);
440             break;
441 
442         case WM_COMMAND:
443             switch (LOWORD(wParam))
444             {
445                 case IDC_LANGUAGE_COMBO:
446                     if (HIWORD(wParam) == CBN_SELCHANGE)
447                     {
448                         LCID lcid;
449                         INT iIndex;
450 
451                         iIndex = SendMessage(hLangList, CB_GETCURSEL, 0, 0);
452                         if (iIndex == CB_ERR)
453                             break;
454 
455                         lcid = SendMessage(hLangList, CB_GETITEMDATA, iIndex, 0);
456                         if (lcid == (LCID)CB_ERR)
457                             break;
458 
459                         pGlobalData->SystemLCID = lcid;
460 
461                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
462                     }
463                     break;
464 
465                 case IDC_APPLY_CUR_USER_DEF_PROFILE:
466                     if (HIWORD(wParam) == BN_CLICKED)
467                     {
468                         if (SendDlgItemMessageW(hwndDlg, IDC_APPLY_CUR_USER_DEF_PROFILE, BM_GETCHECK, 0, 0))
469                         {
470                             ResourceMessageBox(hwndDlg,
471                                                MB_OK | MB_ICONWARNING,
472                                                IDS_APPLY_DEFAULT_TITLE,
473                                                IDS_APPLY_DEFAULT_TEXT);
474                             pGlobalData->bApplyToDefaultUser = TRUE;
475                         }
476                         else
477                         {
478                             pGlobalData->bApplyToDefaultUser = FALSE;
479                         }
480 
481                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
482                     }
483                     break;
484             }
485             break;
486 
487         case WM_NOTIFY:
488             if (((LPNMHDR)lParam)->code == PSN_APPLY)
489             {
490                 PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
491 
492                 SaveSystemSettings(pGlobalData);
493                 SaveFontSubstitutionSettings(hwndDlg, pGlobalData);
494                 SaveFontLinkingSettings(hwndDlg, pGlobalData);
495             }
496             else if (((LPNMHDR)lParam)->idFrom == IDC_CONV_TABLES &&
497                      ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
498             {
499                 SetWindowLong(hwndDlg,
500                               DWL_MSGRESULT,
501                               (LONG)ListViewCustomDraw(lParam));
502                 return TRUE;
503             }
504             break;
505     }
506 
507     return FALSE;
508 }
509 
510 /* EOF */
511