Программирование для Windows NT© Александр Фролов, Григорий ФроловТом 27, часть 2, М.: Диалог-МИФИ, 1996, 272 стр. Приложение SETLOCALВ приложении SETLOCAL мы демонстрируем использование функций, предназначенных для работы с наборами национальных параметров, для переключения клавиатурных раскладок и получения форматированных текстовых строк времени и даты. Главное окно приложения SETLOCAL показано на рис. 4.1. Рис. 4.1. Главное окно приложения SETLOCAL Если из меню Keyboard выбрать строку Set Layout, на экране появится диалоговая панель Set Keyboard Layout, показанная на рис. 4.2. С помощью этой диалоговой панели вы можете изменить клавиатурную раскладку. Рис. 4.2. Диалоговая панель Set Keyboard Layout С помощью списка Keyboard layouts вы можете выбрать одну из установленных в системе клавиатурных раскладок. Если после выбора раскладки нажать кнопку Set layout или OK, выбранная раскладка станет активной. В поле Enter text to test layout вы можете вводить символы для проверки выбранной раскладки клавиатуры. При этом удобно пользоваться кнопкой Set layout, нажатие на которую не приводит к закрытию диалоговой панели. Кнопка Cancel позволяет отменить изменение текущей раскладки клавиатуры. Если из меню Keyboard выбрать строку Get Layout ID, на экране появится диалоговая панель с идентификатором текущей раскладки клавиатуры. На рис. 4.3 и 4.4 это сообщение показано для американской и русской раскладки клавиатуры. Рис. 4.3. Идентификатор американской раскладки клавиатуры Рис. 4.4. Идентификатор русской раскладки клавиатуры С помощью строк меню Local Info (рис. 4.5) вы можете просмотреть отдельные национальные параметры и изменить текущий набор национальных параметров. Рис. 4.5. Меню Local Info Выбирая строки Set English и Set Russian, вы можете выбирать либо американский, либо русский набор национальных параметров. Заметим, что возможность динамического изменения набора национальных параметров отсутствует в операционной системе Microsoft Windows 95. Там вы можете изменить этот набор только при помощи приложения Control Panel с последующей перезагрузкой компьютера. Для просмотра значений некоторых национальных параметров вы должны выбрать из меню Local Info строку Get Local Info. При этом на экране появится диалоговая панель Set and Get Local Info. На рис. 4.6 и 4.7 мы показали эту диалоговую панель для американского и русского набора параметров, соответственно. Рис. 4.6. Значения некоторых параметров для американского набора национальных параметров Рис. 4.7. Значения некоторых параметров для русского набора национальных параметров Здесь мы отображаем название языка, код страны, номер кодовой страницы OEM и номер кодовой страницы ANSI. Если из меню Local Info выбрать строку Get Date and Time, на экране появится диалоговая панель, отображающая строки даты и времени в формате, соответствующем текущему набору национальных параметров. На рис. 4.8 и 4.9 эти строки показаны для американского и русского набора параметров. Рис. 4.8. Строка даты и времени для американского набора параметров Рис. 4.9 Строка даты и времени для русского набора параметров Исходные тексты приложения SETLOCALГлавный файл исходных текстов приложения SETLOCAL приведен в листинге 4.1. Листинг 4.1. Файл setlocal\setlocal.c // ================================================== // Приложение 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; } Файл setlocal.h (листинг 4.2) содержит прототипы функций, определенных в приложении SETLOCAL. Листинг 4.2. Файл setlocal\setlocal.h // ----------------------------------------------------- // Описание функций // ----------------------------------------------------- LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void WndProc_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify); void WndProc_OnDestroy(HWND hWnd); LRESULT WINAPI DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam); void DlgProc_OnCommand(HWND hdlg, int id, HWND hwndCtl, UINT codeNotify); В файле resource.h (листинг 4.3), который создается автоматически системой разработки приложений Microsoft Visual C++, находятся определения констант для файла описания ресурсов. Листинг 4.3. Файл setlocal\resource.h //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by setlocal.rc // #define IDR_MENU1 101 #define IDR_APPMENU 101 #define IDI_APPICON 102 #define IDI_APPICONSM 103 #define IDD_DIALOG_SETLAYOUT 104 #define IDC_COMBO1 1003 #define IDC_EDIT1 1004 #define IDC_BUTTON1 1005 #define ID_FILE_EXIT 40001 #define ID_HELP_ABOUT 40002 #define ID_KEYBOARD_SETLAYOUT 40004 #define ID_KEYBOARD_GETLAYOUTID 40005 #define ID_LOCALINFO_GETLOCALINFO 40006 #define ID_LOCALINFO_SETENGLISH 40007 #define ID_LOCALINFO_SETRUSSIAN 40008 #define ID_LOCALINFO_GETDATE 40009 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 105 #define _APS_NEXT_COMMAND_VALUE 40010 #define _APS_NEXT_CONTROL_VALUE 1006 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif Файл описания ресурсов приложения setlocal.rc приведен в листинге 4.4. В нем определены меню, диалоговая панель, пиктограммы и текстовые строки. Листинг 4.4. Файл setlocal\setlocal.rc //Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // Russian resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) #ifdef _WIN32 LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT #pragma code_page(1251) #endif //_WIN32 ////////////////////////////////////////////////////////////// // // Menu // IDR_APPMENU MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Keyboard" BEGIN MENUITEM "&Set Layout", ID_KEYBOARD_SETLAYOUT MENUITEM "&Get Layout ID", ID_KEYBOARD_GETLAYOUTID END POPUP "Local Info" BEGIN MENUITEM "&Get Local Info", ID_LOCALINFO_GETLOCALINFO MENUITEM "Get &Date and Time", ID_LOCALINFO_GETDATE MENUITEM SEPARATOR MENUITEM "Set &English", ID_LOCALINFO_SETENGLISH MENUITEM "Set &Russian", ID_LOCALINFO_SETRUSSIAN END POPUP "&Help" BEGIN MENUITEM "&About...", ID_HELP_ABOUT END END #ifdef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure // application icon // remains consistent on all systems. IDI_APPICON ICON DISCARDABLE "setlocal.ico" IDI_APPICONSM ICON DISCARDABLE "setlocsm.ico" ////////////////////////////////////////////////////////////// // // Dialog // IDD_DIALOG_SETLAYOUT DIALOG DISCARDABLE 0, 0, 248, 143 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Set Keyboard Layout" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,191,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,191,24,50,14 COMBOBOX IDC_COMBO1,14,65,102,64,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP EDITTEXT IDC_EDIT1,14,28,150,14,ES_AUTOHSCROLL LTEXT "Keyboard layouts:",IDC_STATIC,14,51,57,8 LTEXT "Enter text to test layout:", IDC_STATIC,14,14,75,8 PUSHBUTTON "Set layout",IDC_BUTTON1,191,64,50,14 END ////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_DIALOG_SETLAYOUT, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 241 TOPMARGIN, 7 BOTTOMMARGIN, 136 END END #endif // APSTUDIO_INVOKED #endif // Russian resources ////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED Описание функцийПриведем краткое описание наиболее важных функций приложения SETLOCAL. Функция WinMainПомимо выполнения обычных действий, необходимых для создания главного окна приложения, функция WinMain получает список установленных раскладок клавиатуры, сохраняя его в глобальном массиве lpList. Память для этого массива заказывается динамически, поэтому перед завершением работы приложения мы освобождаем эту память явным образом. Для определения размера списка и для получения самого списка раскладок клавиатуры мы используем функцию GetKeyboardLayoutList: UINT uLayouts; HKL * lpList; uLayouts = GetKeyboardLayoutList(0, NULL); lpList = malloc(uLayouts * sizeof(HKL)); uLayouts = GetKeyboardLayoutList(uLayouts, lpList); Функция WndProc_OnCommandФункция WndProc_OnCommand обрабатывает сообщение WM_COMMAND, поступающее в функцию главного окна приложения от меню. Для установки текущего набора национальных символов в этой функции используется описанная нами ранее функция SetThreadLocale, а также макрокоманды MAKELCID и MAKELANGID: fRc = SetThreadLocale(MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), SORT_DEFAULT)); Для получения значений отдельных национальных параметров мы вызываем функцию GetLocaleInfo: GetLocaleInfo(GetThreadLocale(), LOCALE_SLANGUAGE, szBuf1, 512); В качестве идентификатора набора национальных параметров мы указываем идентификатор текущего набора параметров для основной задачи приложения, полученный от функции GetThreadLocale. Имя текущей раскладки клавиатуры определяется при помощи функции GetKeyboardLayoutName: GetKeyboardLayoutName(szKbLayoutName); Для получения форматированной текстовой строки даты и времени мы вызываем функции GetDateFormat и GetTimeFormat: GetDateFormat(GetThreadLocale(), LOCALE_NOUSEROVERRIDE | DATE_LONGDATE, NULL, NULL, szBuf1, 512); GetTimeFormat(GetThreadLocale(), LOCALE_NOUSEROVERRIDE, NULL, NULL, szBuf1, 512); Эта функция выполняет инициализацию списка типа COMBOBOX, расположенного в диалоговой панели выбора новой раскладки клавиатуры. В процессе инициализации в список записываются называния национальных языков, соответствующие установленным раскладкам клавиатуры. Функция DlgProc_OnCommandФункция DlgProc_OnCommand обрабатывает сообщения от органов управления, расположенных в диалоговой панели выбора новой раскладки клавиатуры. После определения выбранной раскладки она активизируется при помощи функции ActivateKeyboardLayout, как это показано ниже: uSelectedItem = SendMessage( GetDlgItem(hdlg, IDC_COMBO1), CB_GETCURSEL, 0, 0); ActivateKeyboardLayout(*(lpList + uSelectedItem), 0); |