В основе системы Windows лежит понятие окна. Окно — это область экрана, которая связывает каждую запускаемую программу с пользователем и используется для управления работой этой программы. Все окна оформляются в одном стиле и ведут себя одинаково.
Каждое окно имеет рамку и заголовок. Рамка служит для определения рабочей области, а так же для изменения размеров окна. Заголовок содержит имя запущенной программы и ряд управляющих кнопок: свернуть, распахнуть на весь экран и закрыть и применяется для изменения местоположения окна на экране.
Рассмотрим как же создать простое приложение выводящее на экран окно в операционной системе Windows с использованием Win API на языке С++:
Как точка входа в программу в оконных приложениях Windows используется функция WinMain. Именно с вызова этой функции и начинает работать наша программа.
Прототип функции выглядит следующим образом:
1 2 3 4 5 6 7 | int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) |
Эту функцию вызывает операционная система при запуске приложения и передает в неё 4 параметра:
hInstance | Дескриптор текущего экземпляра приложения. Так как Windows является многозадачной системой, то очевидно, что одна и та же программа может быть запущена несколько раз. Для того чтобы различать экземпляры программ, каждому экземпляру присваивается условный номер – хэндл (handle). Отмечу, так же, что в Win32 присваиваются хэндлы чему угодно – окну, меню, курсору, иконке и т.д. |
hPrevInctance | Указатель на предыдущий запущенный экземпляр. Всегда равен NULL. В Windows 3.1 hPrevInctance являлся хэндлом предыдущего экземпляра программы. Если запускается первый экземпляр программы, то параметр hPrevInctance был равен нулю. Этот параметр можно было использовать для того, чтобы не позволить системе запускать более одного экземпляра программы. В Win32 hPrevInctance оставлен исключительно для совместимости с предыдущими версиями Windows. |
lpCmdLine | Указатель на командную строку запускаемой программы. Представляет собой указатель на строку параметров, которые были указаны после имени запускаемой программы. При необходимости программа может проанализировать этот аргумент и выполнить некоторые действия. |
nCmdShow | Способ визуализации окна. Определяет, в каком виде создаваемое окно будет появляться на экране. Окно может появиться развернутым на весь экран, свернутым в панель задач, иметь произвольный размер на рабочем столе и другие характеристики. В Win API определяется 11 возможных значений этого параметра. Их идентификаторы начинаются с SW (Show Window). |
Возможные значения параметра nCmdShow приведены ниже:
SW_HIDE | Скрывает окно и активизирует другое окно. |
SW_MAXIMIZE | Распахивает указанное окно на весь экран. |
SW_MINIMIZE | Минимизирует указанное окно и активизирует следующее окно верхнего уровня Z буфера. |
SW_RESTORE | Активизирует и отображает окно. Если окно минимизировано или развернуто, система восстанавливает его в исходное положение и размер. Приложение должно указать этот флаг при восстановлении свернутого окна. |
SW_SHOW | Активирует окно и выводит на экран это в его текущем размере и позиции. |
SW_SHOWMAXIMIZED | Активизирует окно и отображает его как развернутое окно. |
SW_SHOWMINIMIZED | Активизирует окно и отображает его как свернутое окно. |
SW_SHOWMINNOACTIVE | Отображает окно как свернутое окно. Это значение аналогично SW_SHOWMINIMIZED, за исключением того, что окно не активизируется. |
SW_SHOWNA | Отображает окно в его текущем размере и позиции. Это значение аналогично SW_SHOW, за исключением того, что окно не активизируется. |
SW_SHOWNOACTIVATE | Отображает окно в его последнем размер и положение. Это значение аналогично SW_SHOWNORMAL, за исключением того, что окно не активируется. |
SW_SHOWNORMAL | Активизирует и отображает окно. Если окно минимизировано или развернуто, система восстанавливает его в исходное положение и размер. Приложение должно указать этот флаг при показе окна в первый раз. |
Указатель типа int предшествующий названию функции говорит о том, что функция должна вернуть вызывающей её системе целое значение, а характеристика WINAPI – определяет порядок передачи параметров при вызове процедуры. Наименование характеристик говорит само за себя – Windows Application Programming Interface – применяются соглашения о передаче параметров, принятых в системах Windows.
Следующим шагом нужно создать, заполнить и зарегистрировать класс окна. Класс окна представляет собой структуру с именем WNDCLASS.
Прототип структуры WNDCLASS выглядит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 | typedef struct { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS, *PWNDCLASS; |
style | Стиль окна определяется комбинацией нескольких предопределенных констант. Довольно часто он задается равным нулю, что означает «стиль по умолчанию» |
lpfnWndProc | Указатель на оконную процедуру. |
cbClsExtra | Определяет количество дополнительных байт резервируемых структуре класса. |
cbWndExtra | Определяет количество дополнительных байт резервируемых структуре окна. |
hInstance | Дескриптор экземпляра, который содержит оконную процедуру для класса. |
hIcon | Дескриптор иконки. Этот элемент должен содержать дескриптор ресурса иконки. Если этот элемент имеет значение NULL, система устанавливает значок по умолчанию. |
hCursor | Дескриптор курсора. Этот элемент должен содержать дескриптор ресурса курсора. Если этот элемент имеет значение NULL, приложение должно явно установить формы курсора при перемещении мыши в окне приложения. |
hbrBackground | Дескриптор кисти фона. Этот элемент может быть дескриптором кисти, которая будет использоваться для окраски фона, или это может быть значение цвета. |
lpszMenuName | Указатель на имя ресурса меню. Если этот элемент имеет значение NULL, окна этого класса не имеют меню. |
lpszClassName | Указатель имя только что созданного нами класса окна. Максимальная длина lpszClassName 256. |
Регистрация класса окна осуществляется функцией RegisterClass прототип которой выглядит:
1 2 3 | ATOM RegisterClass( CONST WNDCLASS *lpWndClass ); |
В качестве параметров функция принимает указатель на структуру WNDCLASS созданную нами ранее.
И наконец, функция создания окна — CreteWindow. Вот прототип этой функции:
1 2 3 4 5 6 7 8 9 10 11 12 13 | HWND CreateWindow ( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ); |
lpClassName | Указатель на имя класса окна. |
lpWindowName | Указатель на имя окна. При использовании CreateWindow для создания элементов управления, таких как кнопки, флажки и статические элементы управления, в lpWindowName указывается идентификатор элемента. |
dwStyle | Определяет стиль окна. Этот параметр может быть комбинацией стилей окна. |
x | Задает начальное горизонтальное положение окна. |
у | Задает начальное вертикальное положение окна. |
nWidth | Определяет ширину окна в пикселях. |
nHeight | Определяет высоту окна в пикселях. |
hWndParent | Дескриптор родителя(владельца) создаваемого окна. |
hMenu | Дескриптор меню. |
hInstance | Хэндл экземпляра окна. |
lpParam | Мы пока использовать не будем. |
При успешном выполнении функция возвращает дескриптор созданного окна, при ошибке NULL.
Для того чтобы корректно отобразить окно на экране, следует выполнить ещё две функции ShowWindow и UpdateWindow.
1 2 3 4 | BOOL ShowWindow( HWND hWnd, int nCmdShow ) |
Функция ShowWindow отображает окно на экране. Первый параметр – дискриптор окна, второй – режим отображения. В качестве этого параметра обычно используют параметр nWinMode функции WinMain.
1 2 3 | BOOL UpdateWindow( HWND hWnd ) |
Вызов данной функции приводит к немедленной перерисовке окна и посылке функции окна сообщения WM_PAINT.
Описанных выше действий вполне достаточно для создания простейшего приложения Windows выводящего на экран пустое окно, но наше приложение должно как то взаимодействовать с пользователем. Именно для взаимодействия с пользователем и существует цикл обработки сообщений.
Центральным понятием программирования в среде Windows является сообщение. Система посылает сообщение приложению, а то, в свою очередь, должно правильно отреагировать на него. Получателями сообщений являются функции окон приложения, на программирование которых и уходит большая часть времени при разработке API-приложений.
Цикл обработки сообщений присутствует во всех приложениях Windows. Правда, не всегда этот цикл представлен явно в программе.
Выглядит он следующим образом:
1 2 3 4 5 | while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } |
В цикле обработки сообщений присутствует три функции. Эти функции есть там всегда, но кроме них в цикле могут быть и другие. Функция GetMessage выбирает из очереди сообщений приложения очередное приложение. Вместо этой функции используют так же функции PostMessage и PeekMessage.
Функция TransleteMessage преобразует сообщения WM_KEYDOWN и WM_KEYUP в WM_CHAR. Функция DispatchMessage просто переправляет сообщение оконной процедуре.
Во всех трех функциях присутствует указатель на строку MSG. Разберём её:
1 2 3 4 5 6 7 8 9 | typedef struct tag MSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; }MSG; |
hwnd | Дескриптор окна. |
message | код сообщения. |
wParam | дополнительный параметр. |
lParam | дополнительный параметр. |
time | время посылки сообщения. |
pt | положение курсора мыши. |
Оконная процедура — еще один компонент, отвечающий за обработку сообщений окна. Эта функция вызывается системой и имеет четыре параметра, совпадающих с первыми четырьмя членами структуры MSG. Искусство API-программирования заключается в основном в написании оконных функций.
Вот прототип оконной функции:
1 2 3 4 5 6 7 8 9 | LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { ... } |
Далее я покажу код приложения создающего простое окно Windows, которое обладает основными элементами: заголовок, кнопки минимизации, распахивания на весь экран и закрытия окна, а так же свойствами: перемещение по экрану, изменение ширины и высоты, завершения работы приложения при нажатии на кнопку завершения приложения (крестик).
Для удобства код был разделен на две части, в первой из которых описан код создания окна (CreateWindow.cpp), а во второй — код оконной функции (WinProc.h), который подключается к файлу CreateWindow.cpp при помощи инструкции #include.
WinProc.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT PS; switch(message) { case WM_CREATE: break; case WM_DESTROY: PostQuitMessage(0); break; case WM_PAINT: BeginPaint(hWnd, &PS); EndPaint(hWnd, &PS); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } |
CreateWindow.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <Windows.h> #include "WinProc.h" //Точка входа в программу int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //Создаем класс окна WNDCLASS WindowClass; //Заполняем структуру WindowClass.style = 0; WindowClass.lpfnWndProc = (WNDPROC)WndProc; WindowClass.cbClsExtra = 0; WindowClass.cbWndExtra = 0; WindowClass.hInstance = hInstance; WindowClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_APPLICATION); WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW); WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); WindowClass.lpszMenuName = 0; WindowClass.lpszClassName = TEXT("Class"); //Зарегистируем класс окна RegisterClass(&WindowClass); //Создаем переменную, в которой поместим идентификатор окна HWND hWnd; hWnd = CreateWindow(TEXT("Class"), TEXT("Заголовок окна"), WS_OVERLAPPEDWINDOW, 0, 0, 500, 300, NULL, NULL, hInstance, NULL); //показать окно ShowWindow(hWnd, nCmdShow); //обновить содержимое окна UpdateWindow(hWnd); //Создадим переменную для храненния сообщений MSG msg; //Создадим цикл обработки сообщений while(GetMessage(&msg, NULL,0 ,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } |
Приветствую! не могу разобраться. Знаю PHP, решил подружиться с WinAPI. Создал в VS 2012 проект Win32. А дальше пропасть, днище… Создаю отдельный файл main.cpp, например, дальше, я так понимаю нужно в нём за инкудить #include и что дальше? Напишите самый примитивный код, который создаёт окно, даёт ему название, а то сложно сразу съесть тонны неясного… Благодарю.
P.S. По WP вопросы будут-обращайтесь на блог.
http://windowsapi.ru/files/CreateWindow.zip
Это проект в котором как раз и создается окно.
После нажатия отладки (F5) Пишет вот это! Почему?
1>—— Построение начато: проект: CreateWindow, Конфигурация: Debug Win32 ——
1>LINK : fatal error LNK1123: сбой при преобразовании в COFF: файл недопустим или поврежден
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========
тут вроде как есть решение: http://www.cyberforum.ru/visual-cpp/thread630181.html
посмотри тут: http://www.cyberforum.ru/cpp-beginners/thread637174.html
или тут: https://www.google.ru/search?q=LINK+%3A+fatal+error+LNK1123%3A+%D1%81%D0%B1%D0%BE%D0%B9+%D0%BF%D1%80%D0%B8+%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B8+%D0%B2+COFF%3A&oq=LINK+%3A+fatal+error+LNK1123%3A+%D1%81%D0%B1%D0%BE%D0%B9+%D0%BF%D1%80%D0%B8+%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B8+%D0%B2+COFF%3A&aqs=chrome.0.57j0l2j62l3.644j0&sourceid=chrome&ie=UTF-8