// ==================================================
// Приложение SETLOCAL
// Работа с национальными языками
//
// (С) Фролов А.В., 1996
// Email: frolov@glas.apc.org
// ==================================================

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include "resource.h"
#include "afxres.h"

#include "setlocal.h"

HINSTANCE hInst;
char szAppName[]  = "SetLocalApp";
char szAppTitle[] = "Set and Get Local Info";

// Количество установленных раскладок клавиатуры
UINT uLayouts;

// Указатель на массив идентификаторов 
// раскладок клавиатуры
HKL * lpList;

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  // Сохраняем идентификатор приложения
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    // Если было, выдвигаем окно приложения на
    // передний план
    if(IsIconic(hWnd))
	    ShowWindow(hWnd, SW_RESTORE);
	  SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Определяем количество установленных
  // раскалдок клавиатуры
  uLayouts = GetKeyboardLayoutList(0, NULL);

  // Заказываем массив для хранения идентификаторов
  // раскладок клавиатуры
  lpList = malloc(uLayouts * sizeof(HKL));

  // Заполнение массива идентификаторов
  // раскладок клавиатуры
  uLayouts = GetKeyboardLayoutList(uLayouts, lpList);
  
  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICONSM), 
    IMAGE_ICON, 16, 16, 0);
  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), 
    IMAGE_ICON, 32, 32, 0);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
  wc.lpszClassName = szAppName;
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, 
     WS_OVERLAPPEDWINDOW, 
     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
     NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно и запускаем цикл 
  // обработки сообщений
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  // Перед завершением работы приложения освобождаем
  // память, полученную для хранения идентификаторов
  // раскладок клавиатуры
  free(lpList);
 
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, 
        LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_COMMAND, WndProc_OnCommand);
    HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy);

	  default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  PostQuitMessage(0);
  return 0L;
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  char szBuf[1024];
  char szBuf1[1024];
  char szKbLayoutName[KL_NAMELENGTH];
  BOOL fRc;
  
  switch (id)
  {
    case ID_FILE_EXIT:  
    {
	    // Завершаем работу приложения
      PostQuitMessage(0);
	    return 0L;
	    break;
    }
	  
    // Установка набора национальных параметров для Англии
    case ID_LOCALINFO_SETENGLISH:
    {
      // Выполнение установки для текущей задачи
      fRc = SetThreadLocale(MAKELCID(
        MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), 
        SORT_DEFAULT));
      
      // При возникновении ошибки получаем и отображаем ее код
      if(fRc == FALSE)
      {
        wsprintf(szBuf1,"SetThreadLocale: Error %ld\n", 
          GetLastError());
        MessageBox(hWnd, szBuf1, "Error", MB_OK);
      }
	    break;
    }
    
    // Установка набора национальных параметров для России
    case ID_LOCALINFO_SETRUSSIAN:
    {
      fRc = SetThreadLocale(MAKELCID(
        MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), 
        SORT_DEFAULT));

      if(fRc == FALSE)
      {
        wsprintf(szBuf1,"SetThreadLocale: Error %ld\n", 
          GetLastError());
        MessageBox(hWnd, szBuf1, "Error", MB_OK);
      }
	    break;
    }
    
    // Получение и отображение некоторых 
    // национальных параметров 
    case ID_LOCALINFO_GETLOCALINFO:
    {
      // Отображение полного названия национального языка
      strcpy(szBuf, "LOCALE_SLANGUAGE: ");
      GetLocaleInfo(
        GetThreadLocale(), LOCALE_SLANGUAGE, szBuf1, 512);
      strcat(szBuf, szBuf1);

      // Отображение кода страны
      strcat(szBuf, "\nLOCALE_ICOUNTRY: ");
      GetLocaleInfo(
        GetThreadLocale(), LOCALE_ICOUNTRY, szBuf1, 512);
      strcat(szBuf, szBuf1);

      // Отображение кодовой страницы OEM
      strcat(szBuf, "\nLOCALE_IDEFAULTCODEPAGE: ");
      GetLocaleInfo(
        GetThreadLocale(), LOCALE_IDEFAULTCODEPAGE, szBuf1, 512);
      strcat(szBuf, szBuf1);

      // Отображение кодовой страницы ANSI
      strcat(szBuf, "\nLOCALE_IDEFAULTANSICODEPAGE: ");
      GetLocaleInfo(
        GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE, szBuf1, 512);
      strcat(szBuf, szBuf1);

      MessageBox(hWnd, szBuf, szAppTitle, MB_OK);
	    break;
    }

    // Определение и отображение идентификатора
    // текущей раскладки клавиатуры
    case ID_KEYBOARD_GETLAYOUTID:
    {
      GetKeyboardLayoutName(szKbLayoutName);
      wsprintf(szBuf1,"Layout ID: %s", szKbLayoutName);
      
      MessageBox(hWnd, szBuf1, szAppTitle, MB_OK);
	    break;
    }

    // Установка новой раскладки клавиатуры
    case ID_KEYBOARD_SETLAYOUT:
    {
      // Отображение диалоговой панели для выбора
      // раскладки клавиатуры
      DialogBox(hInst, 
        MAKEINTRESOURCE(IDD_DIALOG_SETLAYOUT), 
        hWnd, DlgProc);

      break;      
    }
    
    // Просмотр текущей даты и времени в формате,
    // принятом для текущей выбранной страны
    case ID_LOCALINFO_GETDATE:
    {
      strcpy(szBuf, "Date: ");

      // Получаем строку даты
      GetDateFormat(
        GetThreadLocale(),
        LOCALE_NOUSEROVERRIDE | DATE_LONGDATE,
        NULL, NULL, szBuf1, 512);
      
      strcat(szBuf, szBuf1);
      strcat(szBuf, "\nTime: ");
      
      // Получаем строку времени
      GetTimeFormat(
        GetThreadLocale(),
        LOCALE_NOUSEROVERRIDE,
        NULL, NULL, szBuf1, 512);
      strcat(szBuf, szBuf1);
      
      // Отображаем время и дату
      MessageBox(hWnd, szBuf, szAppTitle, MB_OK);

      break;      
    }

    case ID_HELP_ABOUT:
    {
      MessageBox(hWnd, 
        "Set and Get Local Information\n"
        "(C) Alexandr Frolov, 1996\n"
        "Email: frolov@glas.apc.org",
        szAppTitle, MB_OK | MB_ICONINFORMATION);
	     return 0L;
	     break;
    }

  	default:
	    break;
  }
  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify,
    DefWindowProc);
}


// -----------------------------------------------------
// Функция DlgProc
// -----------------------------------------------------
LRESULT WINAPI
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, 
        LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc_OnInitDialog);
    HANDLE_MSG(hdlg, WM_COMMAND,    DlgProc_OnCommand);

	default:
    return FALSE;
  }
}

// -----------------------------------------------------
// Функция DlgProc_OnInitDialog
// -----------------------------------------------------

BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, 
                          LPARAM lParam)
{
  UINT i;
  HKL hklCurrent;
  char szBuf[256];

  // При инициализации диалоговой панели получаем в цикле
  // идентификаторы установленных раскладок клавиатуры
  // и заполняем названиями соответствующих национальных
  // языков список типа COMBOBOX, расположенный в 
  // диалоговой панели
  for(i=0; i<uLayouts; i++)
  {
    // Берем очередной идентификатор раскладки 
    hklCurrent = *(lpList + i);

    // Получаем название национального языка 
    GetLocaleInfo(
      MAKELCID(((UINT)hklCurrent & 0xffffffff), 
      SORT_DEFAULT),
      LOCALE_SLANGUAGE, szBuf, 512);

    // Вставляем название национального языка в список
    // типа COMBOBOX
    SendMessage(GetDlgItem(hdlg, IDC_COMBO1),
      CB_ADDSTRING, 0, (LPARAM)(LPSTR)szBuf);
  }

  return TRUE;
}

// -----------------------------------------------------
// Функция DlgProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void DlgProc_OnCommand(HWND hdlg, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  // Номер выбранной строки в списке типа COMBOBOX
  LRESULT uSelectedItem;

  switch (id)
  {
    // Когда пользователь нажимает клавишу OK, 
    // устанавливаем выбранную раскладку клавиатуры
    // и завершаем работу диалоговой панели
    case IDOK:
    {
      // Определяем номер выбранной в списке строки
      uSelectedItem = SendMessage(
        GetDlgItem(hdlg, IDC_COMBO1),
        CB_GETCURSEL, 0, 0);

      // Активизируем выбранную раскладку клавиатуры
      ActivateKeyboardLayout(*(lpList + uSelectedItem), 0);

      // Завершаем работу диалоговой панели
      EndDialog(hdlg, 1);
      return TRUE;
    }

    // Когда пользователь нажимает клавишу Set layout, 
    // устанавливаем выбранную раскладку клавиатуры,
    // не завершая работы диалоговой панели
    case IDC_BUTTON1:
    {
      uSelectedItem = SendMessage(
        GetDlgItem(hdlg, IDC_COMBO1),
        CB_GETCURSEL, 0, 0);

      ActivateKeyboardLayout(*(lpList + uSelectedItem), 0);

      return TRUE;
    }

    // Если пользователь нажал кнопку Cancel, отменяем
    // смену расклдаки клавиатуры, завершая 
    // работу диалоговой панели
    case IDCANCEL:
    {
      EndDialog(hdlg, 0);
      return TRUE;
    }
  	default:
	    break;
  }
  return FALSE;
}

