Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> C/C++ -> Мини-практикум по C++

Иван ГАВРИЛЮК ivg@hotbox.ru

Хранитель экрана, который мы сегодня вместе с вами сделаем, будет работать в фоновом режиме, при этом, естественно, он не должен мешать работе других приложений и потреблять минимум ресурсов. Технически хранитель экрана является обычным исполняемым файлом Windows (*.exe) полностью управляемым сообщениями ОС, но переименованным в *.scr.

При разработке будет использоваться среда Microsoft Visual C++, так как автор статьи довольно долго с ней работает. Вместе с тем, для нашей задачи вполне можно было использовать любой другой компилятор, например, Borland C++ Builder или Watcom C++. Для уменьшения объема исполняемого файла в описанной программе не используется библиотека высокого уровня MFC или CLX(VCL), вся работа выполняется только средствами Win32 API. Также не используются объектно-ориентированные расширения языка. В результате размер программы удается уменьшить приблизительно до 35 Kб.

Для создания хранителей экрана в комплект Visual C++ входит заголовочный файл scrnsave.h (D:\Program Files\Microsoft Visual Studio\VC98\Include\scrnsave.h), в котором находятся определения всех констант и функций, необходимых для работы screensaver'а в среде Windows 9x/NT, а также статическая библиотека scrnsave.lib. Точка входа в программу (функция WinMain) находится в самой scrnsave.lib, что очень сильно облегчает нам жизнь. Наш хранитель пишется ориентировочно для Windows NT (другого у меня нету), хотя должен работать на всех платформах. Различие состоит в том, что для Windows 9x приходится писать еще одну функцию, отвечающую за смену пароля. В NT и выше эту роль выполняет системный процесс Winlogon. Если ключ HKEY_CURRENT_USER\Control Panel\Desktop\ScreenSaverIsSecure в системном реестре Windows не равен нулю, то Winlogon будет запрашивать пароль перед выходом из скринсейвера. Хотя без этой функции можно и обойтись.

Итак, приступим к написанию самого кода. Загружаем среду Visual C++ (я использую 6.0). Создаем проект Win32 Application (File > New > Projects > Win32 Application). В Project Name вводим ssaver, в Location выбираем папку, где будет хранится наш проект, у меня это D:\PROJECTS\). Жмем OK. Появится окошко Win32 Application - Step 1 of 1. Оставляем все без изменений, жмем Fisnish. Имеем пустой проект. Добавляем новый файл исходного кода в проект (меню File > New > Files > C++ source files). В File name пишем ssaver, жмем ОК. Итак, имеем файл ssaver.cpp. Перед Вами откроется пустое окно, в котором, собственно, и будет писаться программа. Настраиваем среду. В меню Build >Set active configuration выбираем ssaver - Win32 Release, ОК. Подключаем библиотеку scrnsave.lib к проекту: меню Project > Settings, вкладка Link. Здесь в строке Object library/modules перечислены библиотеки, подключаемые по умолчанию к Вашему проекту, нам надо лишь дописать scrnsave.lib (Рис. 1 Рис. 1).

Для работы хранителя необходимо написать всего 3 функции (фактически только одну):

1. LRESULT WINAPI ScreenSaverProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - является <функцией окна> хранителя. Она получает все сообщения системы (аналог функции WinMain в чистом Windows-приложении). Первый параметр hWnd - идентификатор окна нашего хранителя, message - код сообщения, которое получил хранитель от системы, wParam и lParam - параметры сообщения. В данной функции программист должен перехватить все интересующие его сообщения, а неперехваченные передать на обработку функции LRESULT WINAPI DefScreenSaverProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

2. BOOL WINAPI ScreenSaverConfigureDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - функция вызывается системой всякий раз, когда пользователь нажимает кнопку <настройка...> в окне настройки хранителей экрана (Пуск >Настройка >Панель управления >Экран >Заставка).

3. BOOL WINAPI RegisterDialogClasses (HANDLE hInst); - вызывается системой для регистрации в ней дополнительных классов (мы ее не будем использовать).

Итак, в новом ранее созданном окне пишем следующий код:

В первых двух строках подключаются заголовочные файлы с прототипами функций (windows.h - объявления Win32 API, scrnsave.h - функции для работы с хранителем экрана). Далее объявляются 3 основных функции, которые и обеспечивают работу хранителя экрана. Сейчас у нас ScreenSaverProc ничего не делает (будем постепенно ее наращивать). Так как мы не используем никаких специальных настроек, то втор ая функция тоже пуста. Нам не нужно создавать дополнительных системных классов, поэтому третья функция должна возвратить true. Жмем F7, среда Visual C++ скомпилирует программу, и если не было ошибок, мы получим полноценный хранитель экрана - правда, он у нас пока ничего не Рис. 2делает. Зайдите в папку с Вашим проектом, а затем в папку Release. Переименуйте ssaver.exe в ssaver.scr. Теперь поместите ssaver.scr в системную папку Windows (В NT/2000 это C:\WINNT\System32, в 9x - С:\WINDOWS\SYSTEM). Зайдите на панель управления, запустите апплет Экран, дальше вкладка Заставка. В списке появится наш хранитель под именем aver (Рис. 2). Если файл начинается с ss, то эти две буквы не показываются.

При нажатии кнопки Просмотр ничего не происходит - так и должно быть, ведь функция ScreenSaverProc пуста. Наш хранитель запускается и тут же завершает свою работу. Давайте наполним эту функцию каким-нибудь полезным кодом. Впишем, например, в нее код, рисующий два вложенных квадрата, вращающихся в противоположные стороны. Для этого подключим еще один заголовочный файл math.h для работы с математикой: #include <math.h>. В начале файла после директив #include определим глобально число pi, а заодно 2*pi и pi/2, чтобы каждый раз их не вычислять:

Функцию ScreenSaverProc наполним следующим содержанием:

А теперь подробно что делает каждая строчка кода. В первых семи определяются переменные для дальнейшего использования. ps - экземпляр структуры PAINTSTRUCT (рассмотрим далее), hDC - идентификатор контекста дисплея, hPen1 - кисть для рисования, uTimer - идентификатор таймера (используется для анимации квадратов), x_max, y_max - в этих переменных будет храниться разрешение экрана, step, angle - приращение угла поворота и сам угол поворота квадрата, center_x, center_y - координаты центра квадрата. Далее с помощью функции switch() организуется ветвление в зависимости от того, какое сообщение пришло от системы (message).

WM_CREATE - это сообщение приходит один раз при создании приложения. При помощи Win32-API функции GetSystemMetrix получаем разрешение экрана Вашего монитора и помещаем в переменные x_max и y_max. Находим координаты цента экрана обычным делением на 2 предыдущих параметров и помещаем в center_x и center_y. Устанавливаем при помощи функции SetTimer виртуальный таймер в систему. Здесь hWnd - идентефикатор окна, которое будет получать сообщения от таймера. Второй параметр - порядковый номер таймера в нашем приложении (можно установить несколько), третий - время в миллисекундах, через которое приложение должно получать сообщения от таймера; устанавливаем на 10 миллисекунд. Четвертый - функция таймера, она будет получать управление через количество миллисекунд, заданное в третьем параметре. Так как мы написали NULL, то таймер будет извещать окно приложения, посылая ему сообщение WM_TIMER. Осталось разобраться с функцией GetStockObject(). Она извлекает графический объект из стандартного репозитория Windows. В нашем случае мы достаем белую кисть (WHITE_PEN), которой будем рисовать в дальнейшем.

WM_DESTROY приходит тоже один раз, при уничтожении окна нашего приложения. Здесь мы при помощи функции KillTimer() снимаем таймер с нашего окна. hWnd - идентефикатор нашего окна, uTimer - указатель на таймер, полученный функцией SetTimer. Наконец, функцией PostQuitMessage посылаем сообщение системе о выходе из приложения. Если этого не сделать, то окно будет уничтожено, но программа будет продолжать работать.

WM_TIMER - это сообщение будет приходить от установленного нами виртуального таймера каждые 10 миллисекунд. Здесь мы увеличиваем угол поворота наших квадратов на step, проверяя, не больше ли он, чем 2*pi (полный оборот) - если да, то обнуляем. Затем мы посылаем сообщение нашему приложению при помощи функции InvalidateRect() о необходимости перерисовать область окна, размеры которого задаются во втором параметре (структурой lpr), предварительно проинициализировав ее. Обновляется квадратная область размером Рис. 3204x204 в центе экрана. Третий параметр в функции InvalidateRect() указывает на необходимость очищать область перед обновлением (true - да, false - нет). hWnd - указатель на окно, которое нужно обновлять.

WM_PAINT - это сообщение происходит при перерисовке окна. Первыми 4 строками мы опять же узнаем разрешение экрана и высчитываем центр. Далее вызываем функцию BeginPaint(). Она подготавливает определенное окно для рисования (hWnd), заполняет структуру типа PAINTSTRUCT (ps) информацией о рисовании и возвращает в hDC указатель на контекст устройства, в нашем случае дисплея. В условном операторе определяем, находимся ли мы в режиме просмотра, или окно развернуто на полный экран; это можно проверить при помощи флага fChildPreview (true - просмотр). Если в режиме просмотра, то выводим текстовую строку <Мой хранитель :-)>. Для этого сначала функцией SetBkColor() устанавливаем цвет фона для нашего контекста устройства (hDC), макрос RGB(r, g, b) преобразует интенсивность красного (r), зеленого (g) и желтого (b) цветов в тип COLORREF, переменную такого типа принимает в качестве второго параметра функция SetBkColor(). Аналогично функцией SetTextColor() устанавливаем цвет текста. Наконец, выводим строку szPreview при помощи TextOut() на дисплей. Она принимает в качестве параметров указатель контекста, координаты строки, саму строку и ее длину (вычисляем при помощи встроенной функции strlen()). У Вас должна получиться картинка, представленная на Рис. 3.

Теперь обрабатываем случай, когда окно развернуто на весь экран (после else). Первые две строчки Вам знакомы - установка цвета фона и текста. SelectObject() выбирает в контекст дисплея (hDC) белую кисть hPen1, которую мы достали, когда приходило сообщение WM_CREATE. Далее используем стандартные GDI-функции ядра Windows для вывода наших вложенных квадратов, повернутых на угол angle. Здесь используются две функции: MoveToEx и LineTo. Первая служит для перемещения графического курсора на контексте, заданном в первом параметре, в точку с координатами во втором и третьем параметрах. Четвертый параметр обычно не используется (NULL). По умолчанию ось OX проходит слева направо, OY - сверху вниз, а отсчет ведется в пикселях. LineTo() рисует линию на контексте hDC из текущей позиции курсора в точку, заданную вторым и третьим параметрами текущей кистью (у нас она белая), дополнительно передвигая графический курсор. Одна вершина квадрата вычисляется по формулам x = cos(angle), y = sin(angle), остальные поворачиваются на углы pi/2, pi, 3*pi/2 относительно нее, тем самым они оказываются в вершинах квадрата. И сдвигаем центр поворота из начала координат в центр экрана. Вершины второго квадрата вычисляются аналогично, но поворачиваются на -angle, чтобы он вращался в противоположную сторону. angle изменяется от 0 до 2*pi, Рис. 4пробегая при этом полную окружность. B конце выводим строку в нижней части экрана. Вот и все. Осталось сообщить системе, что мы закончили рисовать - это делается при помощи функции EndPaint(), она принимает параметры, аналогичные BeginPaint().

Теперь компилируйте проект (F7), переименовывайте ssaver.exe в ssaver.scr, пихайте в системную папку Windows и наслаждайтесь :-). Должно получиться что-то вроде представленного на Рис. 4.

Готовый проект можно взять здесь: http://www.nap2k.narod.ru/ssaver/sssource.exe (9.1 Кб), откомпилированный - здесь: http://www.nap2k.narod.ru/ssaver/ssaver.scr (36.8 Кб).

 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.