xref: /reactos/dll/cpl/intl/advanced.c (revision 11345aed)
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         PrintErrorMsgBox(IDS_ERROR_UNICODE);
320     }
321 
322     SetupCloseInfFile(hFontInf);
323 }
324 
325 
326 static
327 VOID
328 SaveFontLinkingSettings(
329     HWND hwnd,
330     PGLOBALDATA pGlobalData)
331 {
332     /* TODO */
333 }
334 
335 
336 static
337 VOID
338 SaveSystemSettings(
339     PGLOBALDATA pGlobalData)
340 {
341     WCHAR ACPPage[9];
342     WCHAR OEMPage[9];
343     HKEY langKey;
344     DWORD ret;
345     WCHAR value[5];
346     DWORD valuesize;
347 
348     ret = GetLocaleInfoW(MAKELCID(pGlobalData->SystemLCID, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, OEMPage, sizeof(OEMPage)/sizeof(WCHAR));
349     if (ret == 0)
350     {
351         PrintErrorMsgBox(IDS_ERROR_OEM_CODE_PAGE);
352         return;
353     }
354 
355     ret = GetLocaleInfoW(MAKELCID(pGlobalData->SystemLCID, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, ACPPage, sizeof(ACPPage)/sizeof(WCHAR));
356     if (ret == 0)
357     {
358         PrintErrorMsgBox(IDS_ERROR_ANSI_CODE_PAGE);
359         return;
360     }
361 
362     /* Set codepages */
363     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage", &langKey);
364     if (ret != ERROR_SUCCESS)
365     {
366         PrintErrorMsgBox(IDS_ERROR_NLS_CODE_REG);
367         return;
368     }
369 
370     RegSetValueExW(langKey, L"OEMCP", 0, REG_SZ, (BYTE *)OEMPage, (wcslen(OEMPage) +1 ) * sizeof(WCHAR));
371     RegSetValueExW(langKey, L"ACP", 0, REG_SZ, (BYTE *)ACPPage, (wcslen(ACPPage) +1 ) * sizeof(WCHAR));
372 
373     RegCloseKey(langKey);
374 
375 
376     wsprintf(value, L"%04hX", LANGIDFROMLCID(pGlobalData->SystemLCID));
377     valuesize = (wcslen(value) + 1) * sizeof(WCHAR);
378 
379     /* Set language */
380     ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language", &langKey);
381     if (ret != ERROR_SUCCESS)
382     {
383         PrintErrorMsgBox(IDS_ERROR_NLS_KEY_REG);
384         return;
385     }
386 
387     RegSetValueExW(langKey, L"Default", 0, REG_SZ, (BYTE *)value, valuesize);
388     RegCloseKey(langKey);
389 }
390 
391 
392 LRESULT
393 ListViewCustomDraw(
394     LPARAM lParam)
395 {
396     LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
397 
398     switch (lplvcd->nmcd.dwDrawStage)
399     {
400         case CDDS_PREPAINT:
401             return CDRF_NOTIFYITEMDRAW;
402 
403         case CDDS_ITEMPREPAINT:
404             if (((PCPAGE)lplvcd->nmcd.lItemlParam)->Flags & CODEPAGE_NOT_REMOVEABLE)
405             {
406                 lplvcd->clrText = GetSysColor(COLOR_GRAYTEXT);
407             }
408             else
409             {
410                 lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT);
411             }
412             lplvcd->clrTextBk = GetSysColor(COLOR_WINDOW);
413             return CDRF_NEWFONT;
414     }
415 
416     return CDRF_DODEFAULT;
417 }
418 
419 
420 /* Property page dialog callback */
421 INT_PTR CALLBACK
422 AdvancedPageProc(HWND hwndDlg,
423                  UINT uMsg,
424                  WPARAM wParam,
425                  LPARAM lParam)
426 {
427     PGLOBALDATA pGlobalData;
428 
429     pGlobalData = (PGLOBALDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
430 
431     switch (uMsg)
432     {
433         case WM_INITDIALOG:
434             pGlobalData = (PGLOBALDATA)((LPPROPSHEETPAGE)lParam)->lParam;
435             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
436 
437             InitLanguagesList(hwndDlg, pGlobalData);
438             InitCodePagesList(hwndDlg);
439             break;
440 
441         case WM_COMMAND:
442             switch (LOWORD(wParam))
443             {
444                 case IDC_LANGUAGE_COMBO:
445                     if (HIWORD(wParam) == CBN_SELCHANGE)
446                     {
447                         LCID lcid;
448                         INT iIndex;
449 
450                         iIndex = SendMessage(hLangList, CB_GETCURSEL, 0, 0);
451                         if (iIndex == CB_ERR)
452                             break;
453 
454                         lcid = SendMessage(hLangList, CB_GETITEMDATA, iIndex, 0);
455                         if (lcid == (LCID)CB_ERR)
456                             break;
457 
458                         pGlobalData->SystemLCID = lcid;
459 
460                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
461                     }
462                     break;
463 
464                 case IDC_APPLY_CUR_USER_DEF_PROFILE:
465                     if (HIWORD(wParam) == BN_CLICKED)
466                     {
467                         if (SendDlgItemMessageW(hwndDlg, IDC_APPLY_CUR_USER_DEF_PROFILE, BM_GETCHECK, 0, 0))
468                         {
469                             ResourceMessageBox(hwndDlg,
470                                                MB_OK | MB_ICONWARNING,
471                                                IDS_APPLY_DEFAULT_TITLE,
472                                                IDS_APPLY_DEFAULT_TEXT);
473                             pGlobalData->bApplyToDefaultUser = TRUE;
474                         }
475                         else
476                         {
477                             pGlobalData->bApplyToDefaultUser = FALSE;
478                         }
479 
480                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
481                     }
482                     break;
483             }
484             break;
485 
486         case WM_NOTIFY:
487             if (((LPNMHDR)lParam)->code == PSN_APPLY)
488             {
489                 PropSheet_UnChanged(GetParent(hwndDlg), hwndDlg);
490 
491                 SaveSystemSettings(pGlobalData);
492                 SaveFontSubstitutionSettings(hwndDlg, pGlobalData);
493                 SaveFontLinkingSettings(hwndDlg, pGlobalData);
494             }
495             else if (((LPNMHDR)lParam)->idFrom == IDC_CONV_TABLES &&
496                      ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
497             {
498                 SetWindowLongPtr(hwndDlg,
499                                  DWLP_MSGRESULT,
500                                  (LONG_PTR)ListViewCustomDraw(lParam));
501                 return TRUE;
502             }
503             break;
504     }
505 
506     return FALSE;
507 }
508 
509 /* EOF */
510