Россия |
Опубликован: 15.11.2010 | Уровень: для всех | Доступ: платный
Лекция 9:
Ввод-вывод с использованием WinAPI
9.7. Приложение № IV
/* Файл INIT.CPP */ /********************************************************** * Каркас приложений Windows, * на основе которого можно строить более * сложные приложения MS WINDOWS. * Каркас использует правила для написани * программ на платформе Turbo C++ 3.1 * 16-ти разрядных версий Windows. * * Более подробную информацию о "низкоуровневом" написании * программ для Microsoft Windows смотри А.В. Фролов, Г.В. * Фролов, "Операционная система Microsoft Windows 3.1. * для программиста". -- М. "ДИАЛОГ-МИФИ", 1994 г. и др. * книги этих авторов. **********************************************************/ #define STRICT #include <windows.h> #include <mem.h> // Прототипы функций // Первая функция - для инициализации // приложения Windows, вторая функция - // для обработки системных сообщений. BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); /* Значения класса и заголовка впоследствии нужно заменить */ // Имя класса окна char const szClassName[] = "WindowAppClass"; // Заголовок окна char const szWindowTitle[] = "Window Application"; // ===================================== /*************************************** * Функция WinMain * Получает управление при запуске * приложени ***************************************/ // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, // идентификатор текущей // копии приложени HINSTANCE hPrevInstance, // идентификатор предыдущей // копии приложени LPSTR lpszCmdLine, // указатель на командную строку int nCmdShow) // способ отображения главного // окна приложени { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложени // Проверяем, не запускалось ли это приложение ранее // if(!hPrevInstance) // { // Если не запускалось, вызываем функцию InitApp // для инициализации приложения. /***************************************************** * Вызываем функцию InitApp * для инициализации приложения. * Если инициализацию выполнить не удалось, * завершаем приложение *****************************************************/ if(!InitApp(hInstance)) return FALSE; // } /**************************************************** * После успешной инициализации приложения создаём * главное окно приложени ****************************************************/ hwnd = CreateWindow( szClassName, // имя класса окна (см. Выше ) szWindowTitle, // заголовок окна (см. Выше) WS_OVERLAPPEDWINDOW, // стиль окна /**************************************************** * В данном случае это перекрывающееся окно, но эту * опцию можно изменить для других типов окон *****************************************************/ CW_USEDEFAULT, // задаём размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, // идентификатор родительского окна // Для главного окна его менять нельз 0, // идентификатор меню /********************************************************** * В случае если у окна необходимо создать меню, вместо * нуля сюда вставляется идентификатор меню (тип HMENU), * созданный с помощью функции LoadMenu. * * Если меню подключается как ресурс приложения в функции * InitApp, в этом поле также нужно оставить 0 **********************************************************/ hInstance, // идентификатор приложени NULL); // указатель на дополнительные // параметры /********************************************************** * Далее код лучше не менять * **********************************************************/ // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE; /********************************************************** * В случае если Вам не нужно рисовать главное окно * приложения (например, Вы пишете программу-мастер) * две нижеперечисленные функции: ShowWindow и * UpdateWindow, указывать не надо **********************************************************/ // Рисуем окно. Для этого после функции ShowWindow, рисующей // окно, вызываем функцию UpdateWindows, посылающую // сообщение WM_PAINT в функцию окна ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); /********************************************************** * Далее до конца функции код лучше не менять * **********************************************************/ // Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } // Возвращаем значение WParam, переданное // в качестве параметра функции PostQuitMessage // в процессе инициирования завершения работы // приложения из функции окна. // Затем завершаем работу приложени return msg.wParam; } /* Конец функции WinMain *| // ===================================== /********************************************************** * Функция InitApp * Вызывается из функции WinMain дл * инициализации приложения. * Выполняет регистрацию класса окна **********************************************************/ // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем нулевые значения во все поля структуры memset(&wc, 0, sizeof(wc)); // Стиль окна /********************************************************** * Поле style задаёт стиль класса окна и задаётся в виде * констант, описанных в файле <windows.h>. Описани * констант стилей начинается с префикса CS_. Стиль окна * задаёт реакцию окна на изменения его размера, на * выполнения в окне операции двойного щелчка мышью, а * также задаёт другие характеристики окна. * Если в главное окно предполагается вывод информации, * необходимо указать, по крайней мере: * wc.style = CS_HREDRAW | CS_REDRAW; * в противном случае записать: * wc.style = 0; **********************************************************/ wc.style = 0; // Указатель на функцию окна, обрабатывающую // сообщения, предназначенные для всех окон, // созданных на основе данного класса /* Желательно не менять! */ wc.lpfnWndProc = (WNDPROC) WndProc; // Размер дополнительной области данных, // зарезервированной в описании класса окна /* Желательно не менять! */ wc.cbClsExtra = 0; // Размер дополнительной области данных, // зарезервированной для каждого окна, // созданного на основе данного класса /* Желательно не менять! */ wc.cbWndExtra = 0; // Идентификатор приложения, которое // создало данный класс /* Желательно не менять! */ wc.hInstance = hInstance; // Идентификатор пиктограммы, используемой // для окно данного класса /********************************************************** * Иконки создаются или "подгружаются" из специальных * файлов с "ресурсами", с помощью команды LoadIcon. * Первый параметр функции содержит идентификатор * приложения, в котором ищется иконка (значение NULL дл * системных областей), второй параметр задаёт имя ресурса- * пиктограммы. Если Вы не уверены, то этот параметр * менять не нужно. **********************************************************/ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Идентификатор курсора, используемого // для окно данного класса /********************************************************** * Курсоры создаются или "подгружаются" из специальных * файлов с "ресурсами", с помощью команды LoadCursor. * Первый параметр функции содержит идентификатор * приложения, в котором ищется курсор (значение NULL дл * системных областей), второй параметр задаёт имя ресурса- * курсора. Если Вы не уверены, то этот параметр менять * не нужно (оставляем стандартный курсор в виде стрелки). **********************************************************/ wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Цвет фона окна /* Желательно не менять, оставить системный цвет */ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Идентификатор меню /********************************************************** * В случае если у окна необходимо создать меню, в это * поле нужно указать адрес текстовой строки, содержащей * имя шаблона меню в файле ресурсов. Все перекрывающиеся и * временные окна, созданные на базе этого класса, будут * иметь меню, определённое данным шаблоном. Пример: * wc.lpszMenuName = "APP_MENU"; * Если для идентификации шаблона использовать целые * числа, необходимо использовать макрокоманду * MAKEINTRESOURCE. Например, в файле описания ресурсов и в * файле исходного приложения определена константа: * #define APP_MENU 123 * В этом случае строка примет вид: * wc.lpszMenuName = MAKEINTRESOURCE( APP_MENU ); * Если в окне меню не нужно, оставьте параметр без * изменения. **********************************************************/ wc.lpszMenuName = (LPSTR)NULL; /* Желательно не менять остальные операторы до конца функции */ // Имя, которое присваивается создаваемому // классу и используется при создании // окон данного класса wc.lpszClassName = (LPSTR)szClassName; // Регистрация класса aWndClass = RegisterClass(&wc); // Возвращаем результат регистрации класса return (aWndClass != 0); } /* Файл TEXTW.CPP */ /********************************************************** * Функция WndProc **********************************************************/ #define STRICT #include <windows.h> #include <stdio.h> #include <string.h> // Задание максимальной длины символьного буфера строки // для вывода в окно #ifndef SCREEN_BUFSIZE #define SCREEN_BUFSIZE 80 #endif // Прототип функции для печати строки символов void Print(HDC, char *, int); void PrintLn(void); /********************************************************** * cxChar -- значение ширины для самой широкой литеры * cyChar -- max высота литеры с учётом междустрочного * интервала. * cxCurrentPosition -- текущая гориз. позиция вывода текста * cyCurrentPosition -- текущая верт. позиция вывода текста **********************************************************/ static int cxChar, cyChar; static int cxCurrentPosition; static int cyCurrentPosition; LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; // индекс контекста устройства PAINTSTRUCT ps; // структура для рисовани static TEXTMETRIC tm; // структура для записи метрик // шрифта switch (msg) { case WM_CREATE: { // Получаем контекст отображения, // необходимый для определения метрик шрифта hdc = GetDC(hwnd); // Заполняем структуру информацией // о метрике шрифта, выбранного в // контекст отображени GetTextMetrics(hdc, &tm); // Запоминаем значение ширины дл // самого широкого символа cxChar = tm.tmMaxCharWidth; // Запоминаем значение высоты букв с // учётом межстрочного интервала cyChar = tm.tmHeight + tm.tmExternalLeading; // Инициализируем текущую позицию // вывода текста cxCurrentPosition = cxChar; cyCurrentPosition = cyChar; // Освобождаем контекст ReleaseDC(hwnd, hdc); return 0; } case WM_PAINT: { // Инициализируем текущую позицию // вывода текста cxCurrentPosition = cxChar; cyCurrentPosition = cyChar; hdc = BeginPaint(hwnd, &ps); // Выводим последовательно строки: Print(hdc, "Первая строка", 0); PrintLn(); Print(hdc, "Вторая строка", 0); PrintLn(); Print(hdc, "Третья строка( смещённая )", 10); PrintLn(); EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: { PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); } /********************************************************** * Функция Print * Функция предназначена для вывода текста * в окно. * * ВХОДНЫЕ ЗНАЧЕНИЯ: * HDC hdc -- индекс контекста устройства; * char *str -- указатель на выводимую строку; * int iOFFSET -- смещение горизонтальной позиции * вывода текста в окно, указанное в символах; * * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ: * cxChar -- значение ширины для самой широкой литеры * cyChar -- max высота литеры с учётом междустрочного * интервала. * cxCurrentPosition -- текущая гориз. позиция вывода текста * cyCurrentPosition -- текущая верт. позиция вывода текста * * ФУНКЦИЯ ВОЗВРАЩАЕТ: * Возвращаемых значений нет. * * ПРИМЕЧАНИЕ: * Эта функция может быть переписана Вами под Ваши * нужды для вывода не только текста, но и числовых * значений, а также для форматирования в строке вывода. * **********************************************************/ void Print(HDC hdc, char *str, int iOFFSET ) { char buf[SCREEN_BUFSIZE]; int i; /* Проверяем смещение на неравенство единице и корректируем его */ if( iOFFSET < 0 ) iOFFSET = 0; // Подготавливаем в рабочем буфере i = strlen(str); // Проверка, что строка умещается в буфере if( i < SCREEN_BUFSIZE - 1 ) // и выводим строку в зависимости от проверки sprintf(buf, "%s", str); else sprintf(buf, "%.*s", SCREEN_BUFSIZE-1, str); // Выводим текст в окно, начиная с текущей позиции // вывода текста + смещение в максимальном // количестве символов TextOut(hdc, cxCurrentPosition + iOFFSET * cxChar, cyCurrentPosition, buf, i); } /********************************************************** * Функция PrintLn * Функция предназначена для перевода на новую строку * при выводе в окно. * * ВХОДНЫЕ ЗНАЧЕНИЯ: * Не имеет. * * ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ: * cxChar -- значение ширины для самой широкой литеры * cyChar -- max высота литеры с учётом междустрочного * интервала. * cxCurrentPosition -- текущая гориз. позиция вывода текста * cyCurrentPosition -- текущая верт. позиция вывода текста * * ФУНКЦИЯ ВОЗВРАЩАЕТ: * Возвращаемых значений нет. * * ПРИМЕЧАНИЕ: * Эта функция может быть переписана Вами под Ваши * нужды для вывода не только текста, но и числовых * значений, а также для форматирования в строке вывода. * **********************************************************/ void PrintLn( void ) { // Увеличиваем текущую позицию по // вертикали на высоту символа cyCurrentPosition += cyChar; } /* Файл TEXTWN.DEF*/ ; ============================= ; Файл определения модул ; ============================= ; Имя приложени NAME TEXTWIN ; Описание приложени DESCRIPTION 'Приложение WINDOW, (C) 1994, Frolov A.V.' ; Определение типа загрузочного модуля как ; приложения Windows EXETYPE windows ; Программа, которая будет записана в начало файла ; приложения. Эта программа получит управление ; при попытке запуска приложения в среде MS-DOS STUB 'winstub.exe' ; Размер стека в байтах STACKSIZE 5120 ; Размер локальной кучи памяти приложения в байтах HEAPSIZE 1024 ; Атрибуты сегмента кода CODE preload moveable discardable ; Атрибуты сегмента данных DATA preload moveable multiple