- Temporary fix for making locale switches possible. Patch by zebasoftis. Fixes bug...
[reactos.git] / reactos / lib / cpl / intl / locale.c
index 86eecea..8c4692f 100644 (file)
  * PURPOSE:         Locale property page
  * PROGRAMMER:      Eric Kohl
  *                  Klemens Friedl
+ *                  Aleksey Bragin
  */
 
+#define WINVER 0x0501
+
 #include <windows.h>
 #include <commctrl.h>
 #include <cpl.h>
 
+#include <stdio.h>
+
 #include "intl.h"
 #include "resource.h"
 
+HWND hList;
 
-// FIXME:
-//        * change registry function (-> "HKCR\MIME\Database\Rfc1766")
-
-
-
-typedef struct _TZ_INFO
-{
-  LONG Bias;
-  LONG StandardBias;
-  LONG DaylightBias;
-  SYSTEMTIME StandardDate;
-  SYSTEMTIME DaylightDate;
-} TZ_INFO, *PTZ_INFO;
-
-typedef struct _TIMEZONE_ENTRY
+BOOL CALLBACK LocalesEnumProc(
+  LPTSTR lpLocale // locale id
+)
 {
-  struct _TIMEZONE_ENTRY *Prev;
-  struct _TIMEZONE_ENTRY *Next;
-  WCHAR Description[64];   /* 'Display' */
-  WCHAR StandardName[32];  /* 'Std' */
-  WCHAR DaylightName[32];  /* 'Dlt' */
-  TZ_INFO TimezoneInfo;    /* 'TZI' */
-  ULONG Index;             /* 'Index' */
-} TIMEZONE_ENTRY, *PTIMEZONE_ENTRY;
+       LCID lcid;
+       TCHAR lang[255];
+       int index;
 
+       //swscanf(lpLocale, L"%lx", &lcid); // maybe use wcstoul?
+       lcid = wcstoul(lpLocale, NULL, 16);
 
+       GetLocaleInfo(lcid, LOCALE_SLANGUAGE, lang, sizeof(lang));
 
-PTIMEZONE_ENTRY TimeZoneListHead = NULL;
-PTIMEZONE_ENTRY TimeZoneListTail = NULL;
-
-
-
-
-static PTIMEZONE_ENTRY
-GetLargerTimeZoneEntry(DWORD Index)
-{
-  PTIMEZONE_ENTRY Entry;
-
-  Entry = TimeZoneListHead;
-  while (Entry != NULL)
-    {
-      if (Entry->Index >= Index)
-       return Entry;
+    index = SendMessageW(hList,
+                  CB_ADDSTRING,
+                  0,
+                  (LPARAM)lang);
 
-      Entry = Entry->Next;
-    }
+       SendMessageW(hList,
+                  CB_SETITEMDATA,
+                  index,
+                  (LPARAM)lcid);
 
-  return NULL;
+       return TRUE;
 }
 
 
 static VOID
-CreateTimeZoneList(VOID)
+CreateLanguagesList(HWND hwnd)
 {
+       TCHAR langSel[255];
+
+       hList = hwnd;
+       EnumSystemLocalesW(LocalesEnumProc, LCID_SUPPORTED);
+
+       // Select current locale
+       GetLocaleInfo(GetUserDefaultLCID(), LOCALE_SLANGUAGE, langSel, sizeof(langSel)); // or should it be System and not user?
+       
+       SendMessageW(hList,
+                  CB_SELECTSTRING,
+                  -1,
+                  (LPARAM)langSel);
+}
 
-  WCHAR szKeyName[256];
-  DWORD dwIndex;
-  DWORD dwNameSize;
-  DWORD dwValueSize;
-  LONG lError;
-  HKEY hZonesKey;
-  HKEY hZoneKey;
-
-  PTIMEZONE_ENTRY Entry;
-  PTIMEZONE_ENTRY Current;
-
-
-
-  if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                   L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
-                   0,
-                   KEY_ALL_ACCESS,
-                   &hZonesKey))
-    return;
-
-  dwIndex = 0;
-  while (TRUE)
-    {
-      dwNameSize = 256;
-      lError = RegEnumKeyExW(hZonesKey,
-                            dwIndex,
-                            szKeyName,
-                            &dwNameSize,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL);
-      if (lError != ERROR_SUCCESS && lError != ERROR_MORE_DATA)
-       break;
-
-
-      if (RegOpenKeyExW(hZonesKey,
-                       szKeyName,
-                       0,
-                       KEY_ALL_ACCESS,
-                       &hZoneKey))
-       break;
-
-
-      Entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEZONE_ENTRY));
-      if (Entry == NULL)
+// Sets new locale
+void SetNewLocale(LCID lcid)
+{
+       // HKCU\\Control Panel\\International\\Locale = 0409 (type=0)
+       // HKLM,"SYSTEM\CurrentControlSet\Control\NLS\Language","Default",0x00000000,"0409" (type=0)
+       // HKLM,"SYSTEM\CurrentControlSet\Control\NLS\Language","InstallLanguage",0x00000000,"0409" (type=0)
+
+       // Set locale
+       HKEY localeKey;
+       HKEY langKey;
+       DWORD ret;
+       TCHAR value[9];
+       DWORD valuesize;
+       WCHAR ACPPage[9];
+       WCHAR OEMPage[9];
+
+       ret = GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_IDEFAULTCODEPAGE, (WORD*)OEMPage, sizeof(OEMPage));
+       if (ret == 0)
        {
-         RegCloseKey(hZonesKey);
-         break;
+               MessageBoxW(NULL, L"Problem reading OEM code page", L"Big Problem", MB_OK);
+               return;
        }
 
-      dwValueSize = 64 * sizeof(WCHAR);
-      if (RegQueryValueExW(hZonesKey,
-                          L"Display",
-                          NULL,
-                          NULL,
-                          (LPBYTE)&Entry->Description,
-                          &dwValueSize))
+       GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, (WORD*)ACPPage, sizeof(ACPPage));
+       if (ret == 0)
        {
-         RegCloseKey(hZonesKey);
-         break;
+               MessageBoxW(NULL, L"Problem reading ANSI code page", L"Big Problem", MB_OK);
+               return;
        }
 
-      dwValueSize = 32 * sizeof(WCHAR);
-      if (RegQueryValueExW(hZonesKey,
-                          L"Std",
-                          NULL,
-                          NULL,
-                          (LPBYTE)&Entry->StandardName,
-                          &dwValueSize))
-       {
-         RegCloseKey(hZonesKey);
-         break;
-       }
+       ret = RegOpenKeyW(HKEY_CURRENT_USER, L"Control Panel\\International", &localeKey);
 
-      dwValueSize = 32 * sizeof(WCHAR);
-      if (RegQueryValueExW(hZonesKey,
-                          L"Dlt",
-                          NULL,
-                          NULL,
-                          (LPBYTE)&Entry->DaylightName,
-                          &dwValueSize))
+       if (ret != ERROR_SUCCESS)
        {
-         RegCloseKey(hZonesKey);
-         break;
+               // some serious error
+               MessageBoxW(NULL, L"Problem opening HKCU\\Control Panel\\International key", L"Big Problem", MB_OK);
+               return;
        }
 
-      dwValueSize = sizeof(DWORD);
-      if (RegQueryValueExW(hZonesKey,
-                          L"Index",
-                          NULL,
-                          NULL,
-                          (LPBYTE)&Entry->Index,
-                          &dwValueSize))
-       {
-         RegCloseKey(hZonesKey);
-         break;
-       }
+       wsprintf(value, L"%04X", (DWORD)lcid);
+       valuesize = (wcslen(value) + 1) * sizeof(WCHAR);
 
-      dwValueSize = sizeof(TZ_INFO);
-      if (RegQueryValueExW(hZonesKey,
-                          L"TZI",
-                          NULL,
-                          NULL,
-                          (LPBYTE)&Entry->TimezoneInfo,
-                          &dwValueSize))
-       {
-         RegCloseKey(hZonesKey);
-         break;
-       }
+       RegSetValueExW(localeKey, L"Locale", 0, REG_SZ, (BYTE *)value, valuesize);
+       RegCloseKey(localeKey);
 
-      RegCloseKey(hZoneKey);
+       ret = RegOpenKeyW(HKEY_USERS, L".DEFAULT\\Control Panel\\International", &localeKey);
 
-      if (TimeZoneListHead == NULL &&
-         TimeZoneListTail == NULL)
+       if (ret != ERROR_SUCCESS)
        {
-         Entry->Prev = NULL;
-         Entry->Next = NULL;
-         TimeZoneListHead = Entry;
-         TimeZoneListTail = Entry;
-       }
-      else
-       {
-         Current = GetLargerTimeZoneEntry(Entry->Index);
-         if (Current != NULL)
-           {
-             if (Current == TimeZoneListHead)
-               {
-                 /* Prepend to head */
-                 Entry->Prev = NULL;
-                 Entry->Next = TimeZoneListHead;
-                 TimeZoneListHead->Prev = Entry;
-                 TimeZoneListHead = Entry;
-               }
-             else
-               {
-                 /* Insert before current */
-                 Entry->Prev = Current->Prev;
-                 Entry->Next = Current;
-                 Current->Prev->Next = Entry;
-                 Current->Prev = Entry;
-               }
-           }
-         else
-           {
-             /* Append to tail */
-             Entry->Prev = TimeZoneListTail;
-             Entry->Next = NULL;
-             TimeZoneListTail->Next = Entry;
-             TimeZoneListTail = Entry;
-           }
+               // some serious error
+               MessageBoxW(NULL, L"Problem opening HKU\\.DEFAULT\\Control Panel\\International key", L"Big Problem", MB_OK);
+               return;
        }
 
-      dwIndex++;
-    }
+       wsprintf(value, L"%04X", (DWORD)lcid);
+       valuesize = (wcslen(value) + 1) * sizeof(WCHAR);
 
-  RegCloseKey(hZonesKey);
+       RegSetValueExW(localeKey, L"Locale", 0, REG_SZ, (BYTE *)value, valuesize);
+       RegCloseKey(localeKey);
 
-}
+       // Set language
+       ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\Language", &langKey);
 
+       if (ret != ERROR_SUCCESS)
+       {
+               MessageBoxW(NULL, L"Problem opening HKLM\\SYSTEM\\CurrentControlSet\\Control\\NLS\\Language key", L"Big Problem", MB_OK);
+               return;
+       }
 
-static VOID
-ShowTimeZoneList(HWND hwnd)
-{
-  TIME_ZONE_INFORMATION TimeZoneInfo;
-  PTIMEZONE_ENTRY Entry;
-  DWORD dwIndex;
-  DWORD i;
-
-  GetTimeZoneInformation(&TimeZoneInfo);
-
-  dwIndex = 0;
-  i = 0;
-  Entry = TimeZoneListHead;
-  while (Entry != NULL)
-    {
-      SendMessageW(hwnd,
-                  CB_ADDSTRING,
-                  0,
-                  (LPARAM)Entry->Description);
+       RegSetValueExW(langKey, L"Default", 0, REG_SZ, (BYTE *)value, valuesize );
+       RegSetValueExW(langKey, L"InstallLanguage", 0, REG_SZ, (BYTE *)value, valuesize );
 
-      if (!wcscmp(Entry->StandardName, TimeZoneInfo.StandardName))
-       dwIndex = i;
+       RegCloseKey(langKey);
 
-      i++;
-      Entry = Entry->Next;
-    }
 
-  SendMessageW(hwnd,
-              CB_SETCURSEL,
-              (WPARAM)dwIndex,
-              0);
-}
+       // Set language
+       ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage", &langKey);
 
+       if (ret != ERROR_SUCCESS)
+       {
+               MessageBoxW(NULL, L"Problem opening HKLM\\SYSTEM\\CurrentControlSet\\Control\\NLS\\CodePage key", L"Big Problem", MB_OK);
+               return;
+       }
+
+       RegSetValueExW(langKey, L"OEMCP", 0, REG_SZ, (BYTE *)OEMPage, (wcslen(OEMPage) +1 ) * sizeof(WCHAR) );
+       RegSetValueExW(langKey, L"ACP", 0, REG_SZ, (BYTE *)ACPPage, (wcslen(ACPPage) +1 ) * sizeof(WCHAR) );
 
+       RegCloseKey(langKey);
 
+}
 
 /* Property page dialog callback */
 INT_PTR CALLBACK
@@ -292,16 +181,56 @@ LocalePageProc(HWND hwndDlg,
               WPARAM wParam,
               LPARAM lParam)
 {
-  switch(uMsg)
-  {
-    case WM_INITDIALOG:
-
-      CreateTimeZoneList();
-      ShowTimeZoneList(GetDlgItem(hwndDlg, IDC_LANGUAGELIST));
+       switch(uMsg)
+       {
+       case WM_INITDIALOG:
+               CreateLanguagesList(GetDlgItem(hwndDlg, IDC_LANGUAGELIST));
+               break;
+       case WM_COMMAND:
+               switch (LOWORD(wParam))
+               {
+               case IDC_LANGUAGELIST:
+                       if (HIWORD(wParam) == CBN_SELCHANGE)
+                       {
+                               PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+                       }
+                       break;
+               }
+               break;
 
-      break;
-  }
-  return FALSE;
+       case WM_NOTIFY:
+               {
+                       LPNMHDR lpnm = (LPNMHDR)lParam;
+                       if (lpnm->code == (UINT)PSN_APPLY)
+                       {
+                               // Apply changes
+                               LCID NewLcid;
+                               int iCurSel;
+
+                               // Acquire new value
+                               iCurSel = SendMessageW(hList,
+                                       CB_GETCURSEL,
+                                       0,
+                                       0);
+                               if (iCurSel == CB_ERR)
+                                       break;
+
+                               NewLcid = SendMessageW(hList,
+                                       CB_GETITEMDATA,
+                                       iCurSel,
+                                       0);
+
+                               if (NewLcid == (LCID)CB_ERR)
+                                       break;
+                
+                
+                               // Actually set new locale
+                               SetNewLocale(NewLcid);
+                       }
+               }
+               break;
+       }
+       return FALSE;
 }