PROgrammist, №9

Page 1


ПРО

граммист

СОДЕРЖАНИЕ

№9 (декабрь) 2010

Издается с марта 2010. Выходит ежемесячно №9, декабрь 2010 г.

Редакция: Выпускающий редактор Сергей Бадло Литературный редактор Utkin Редакторы JTG, Василий Мединцев, ZvEr_HaCkEr, Алексей Шульга, Егор Горохов Редактор-корректор Yan Liplavskiy

Дизайн и верстка:

Егор Горохов, ZvEr_HaCkEr, Сергей Бадло

Авторский состав:

Дарья Устюгова, Алексей Шишкин, Вадим Буренков, Вячеслав Мовила, Виталий Белик, Руслан Аблязов, Сергей Бадло

Официальный сайт журнала: www.procoder.info

Контакты:

Авторские статьи направляйте на maindatacentr@gmail.com Вопросы и предложения для редакции reddatacentr@gmail.com Вопросы и предложения администратору info@procoder.info

ТЕМА НОМЕРА

Новый год на носу .............................................. с.3 НЕВЕРОЯТНО, НО ФАКТ

Любопытные факты ............................................... с.4 ОБЩИЕ ВОПРОСЫ

О правильном составлении ТЗ. Часть 2 ........................... с.9 ОТДЕЛ ТЕСТИРОВАНИЯ

Быстрое написание программ на WinAPI ........................... с.15 2D ГРАФИКА

Делаем динамические тени на OpenGL. Часть 2 .................... с.18 ЛАБОРАТОРИЯ

WMI. Wладение Mагической Iнформацией. Часть 2 .................. с.28 mRTOS. Мини-операционная система для МК AVR .................... с.36 АРХИВ

Запись дисков в Delphi средствами IMAPI ........................ с.39 Близкие контакты третьего вида с Visual Foxpro ................. с.44 ЮМОР

Чего только не бывает .......................................... с.55

Информационная поддержка:

Международная Академия Информатизации (МАИН) РК www.academy.kz Журнал «Радиолюбитель» www.radioliga.com V.K. сайт... www.kotoff.info Free Legal Soft Group www.flsoft.ru AirNet-Berdyansk www.airnet.sytes.net

Примечание:

Издание некоммерческое. Все материалы, товарные знаки, торговые марки и логотипы, упомянутые в журнале, принадлежат их владельцам. Статьи, поступающие в редакцию, рецензируются. Мнение авторов не всегда совпадает с мнением редакции. Перепечатка материалов журнала и использование их в любой форме, в том числе в электронных СМИ, возможны только с разрешения редакции. Тираж неограничен. Формат A4, 57 стр.

Идея создания журнала: Алексей Шульга

Обложка номера:

Дизайн ZvEr_HaCkEr, Savva-Paladin

архив номеров журнала ^


ПРО

НОВЫЙ ГОД НАФАКТЫ НОСУ ЛЮБОПЫТНЫЕ

№9 (декабрь) 2010

граммист

От редактора. Здравствуйте, уважаемые читатели журнала «ПРОграммист». За относительно непродолжительный период «ПРОграммист» стал содержательным, востребованным и узнаваемым изданием... А декабрь-месяц напоминает нам, что близится Новый Год – год белого кота. Несомненно, кот – любимое домашнее животное не только среди программистов, но и радиоинженеров. Как известно, кот – консервативен, спокоен и невозмутим. И будем надеяться, что в предстоящем году радиокот или котэпрограммист принесет нам побольше счастья, крепкого здоровья, удачных проектов и разработок, интересных и полезных статей и, само-собой, морально-материальное удолетворение, а все жизненные неурядицы и баги обойдут стороной. С наступающим праздником Вас, друзья! В этом выпуске...

Рубрики журнала (плавающие)

Дарья Устюгова расскажет «что и как» нужно

Новости программирования

рубрику «Общие вопросы».

Общие вопросы (правовое использование)

писать в первых четырех частях ТЗ. Читайте Нюансами быстрого и качественного написания

программ на WinAPI продолжит делиться Алексей Шишкин в рубрике «Отдел тестирования». В

рубрике

«Графика»

Вадим

Буренков

представляет новый материал по использованию OpenGL для создания динамических теней. В

рубрике

«Лаборатория»

Виталий

Белик

завершает магический цикл по использованию WMI.

Многие

«программисты-железячники»

из

собственного опыта знают, что при разработке относительно

больших

микроконтроллерах

удобнее

проектов

на

использовать

• • • • • • • • У

и

управления

ими.

В

рубрике

«Архив»

мы

тему

использования IMAPI применительно к записи дисков

в

Delphi.

Об

этом

и

многом

поделится ретами ния

провайдера

Visual Foxpro.

ТЕМА НОМЕРА

своего для

нет

категоричных

требований

к

свободное

труда

ПО

«SCRIBUS»)

и

редакторов,

есть

некоторый

статья должна иметь выраженную структуру с разделами

и

содержать

название

статьи,

авторах, экскурс или введение, об

используемых

теоретическую

средствах

и/или

практическую часть, заключение и ресурсы к

сек-

написа-

нас

разработки,

Белик

Юмор (специфические хохмы программеров)

информацию

А

Виталий

Архив (по материалам клуба и форума)

сведения об

Аблязов.

Лаборатория

желательный минимум:

другом

расскажет Руслан

Wi-Fi сети

облегчения

Прототип

подняли

Разработка (проекты от этапа ТЗ до сдачи)

(используется

подобной мини-операционной системы для AVR разработал наш автор – Вячеслав Мовила.

Переводные материалы

оформлению, но в связи с особенностями верстки

этом встает вопрос коммуникации этих модулей собой

Алгоритмы

Общие требования к материалам

разделение программы на несколько модулей. При между

Отдел тестирования

По

статье;

текст статьи без табуляции в формате MS Word, VK WordPad или обычным текстовым файлом, шрифт Arial 10;

все рисунки, таблицы должны быть подписаны и иметь упоминание в тексте;

рисунки к статье должны прилагаться в виде отдельных файлов в формате PNG, TIF;

разделы статьи отделять двумя <ENTER>. присланным

рецензию

и

материалам

корректирует

автор

статью

получает

согласно

замечаниям. Шаблон для написания статьи можно взять тут.

С уважением, Редакция

СОДЕРЖАНИЕ

3


ПРО

ЛЮБОПЫТНЫЕ ФАКТЫ

№9 (декабрь) 2010

граммист

Приветствую, дорогой читатель. Сделав очередной обзор по последним новостям техники, технологий и электроники, каждый раз убеждаешся, что последние имеют свойство устаревать. Но, некоторые не теряют своей актуальности с течением времени. К примеру, именно нестандартные решения по использованию самых обычных предметов дают неожиданный и эффективный результат. Сегодня в рубрике речь пойдет именно о таких вещах и... не только об этом. Приступим... Сергей Бадло

by raxp http://raxp.radioliga.com 40

ведущих

мировых ученых получили от

Минобрнауки создание

по

150

миллионов

лабораторий

Решения

о

в

выделении

рублей

российских

средств

на

вузах.

принимается

Советом* по грантам Правительства Российской Федерации научных

для

государственной

исследований,

руководством

ведущих

образовательных

поддержки

проводимых

ученых

в

под

российских

учреждениях

высшего

профессионального образования, состав которого утвержден распоряжением Правительства РФ от 9 апреля 2010 г. № 517. * Cправка. Советом

были

определены

Солнечные батареи из краски разработала компания

университет

Tata

Суонси

Разработчики

области

наук

для

биотехнологии; информационные технологии и вычислительные

автомобильной

астрофизика; атомная энергетика и ядерные технологии; биология; системы; космические исследования и технологии; математика; машиноведение; медицинские науки и технологии; механика и

процессы управления; нанотехнологии; науки о Земле; науки о психология,

когнитивные

исследования;

радиоэлектроника; строительство и архитектура; физика; химия; экология; экономика, международные исследования, социология; энергетика, энергоэффективность и энергосбережение.

Также установлено требование к ведущему ученому, которое российском

необходимость

личного

образовательном

профессионального

образования)

перечисления средств вузам, на базе которых получатель гранта будет

ное Но

вести

науч-

исследование. расходовать

средства

гранта

расширении

воды

на

в

научным

исследованием.

эта

где

производить

водород в

для

топливных

фотоэлементах

для

концентрации света предлагают использовать MIT-research.

волокнистых длиной

и

4

волокон

микрон

около

Нанотрубки 10

из

микрометров

толщиной

позволяют

сконцентрировать в 100 раз больше солнечной

энергии, чем обычный фотоэлемент. Еще одно применение полученных

этой

технологии

интеграция

зданиями

является

недорогих

существующими Тем

водство

и

последнего

элементах.

го ученого, осущесруко-

могут

кислород

экономически

твляющего

возможностей

промышленности,

аккумулирования

вузы смогут только

с согласия ведуще-

специальным

электричество, необходимое для расщепления

ученые

Выделение правительственных грантов будет осуществляться путем

использовать

красители,

автомобиля,

и

календарном году, начиная с 2011 года.

НЕВЕРОЯТНО, НО ФАКТ

корпусу

лабораторией

проводимыми научными исследованиями не менее 4 месяцев в

Великобритания).

светочувствительные краски, распыленные по

Нанотрубки

высшего

и

технология может найти свое применение в

в

учреждении

руководства

При

присутствием

очным

Corus)

образом распыленные на поверхности стальных листов.

определяет

(Уэльс,

фоточувствительные следующие

(прежде

планируют

государственной поддержки научных исследований: астрономия и

материалах;

Steel

солнечных

выгодной,

панелей

с

благодаря

минимальным инвестициям в инфраструктуру. самым

исключаются

расходы

на

приобретение земли, закупку тысяч солнечных батарей

и

электросети.

подключения

их

к

основной

СОДЕРЖАНИЕ

4


ПРО

ЛЮБОПЫТНЫЕ ФАКТЫ

№9 (декабрь) 2010

граммист

Технологию защиты цифровых фонограмм от

базовые

http://www.telesys.ru.

расположенных

подделки

внедряет

исключает

компания

Технология

возможность

«Телесистемы» не

только

фальсификации

аудиозаписи, сделанной в цифровой форме, но и позволяет проверить ее подлинность. В основе новой

разработки

технология

цифровых

«Телесистем» водяных

лежит

знаков.

Она

позволяет внедрять в аудиофайл специальные метки, не воспринимаемые на слух, но видимые компьютером.

Если

помеченная

аудиозапись

была подвергнута редактированию, целостность

водяных знаков будет нарушена. Таким образом, можно

достоверно

фонограммы. цифровых

На

меток

установить

данный

оснащены

факт

момент

монтажа

системой

диктофоны

серий

Edic-mini Tiny 16, Edic-mini PRO и Edic-mini LCD производства «Телесистем». Электронные метки служат

своеобразными

паспортами

этих

устройств. По ним можно определить модель и

изображения

пространства, например

небольшого

за

в

том

вне

углом

окружающего

числе

зоны

прямой

здания,

количества

и

света

за

объектов,

видимости,

счет

вокруг

сбора

сцены,

которая попадает в поле действия луча. Пока картина

получается

не

слишком

четкая

сам

факт,

и,

конечно, ее нельзя сравнить с фото, сделанным на

обычную

камеру,

но

тот

что

технология может сфотографировать нечто, что скрыто за стеной, уже привлекает. В основе

необычной камеры находится фемтосекундный лазер,

обладающий

светочувствительностью. длится

всего

одну

сверхвысокой

Излучение

квадриллионную

лазера долю

секунды, но для картинки этого достаточно. Прежде такие лазеры в основном применялись

химиками для получения статических данных о течении реакций.

серийный номер диктофона, с помощью которого сделана

содержат

фонограмма.

информацию

проведения записи.

Помимо о

дате

этого, и

метки

времени

Камеру, снимающую из-за угла разработали в Массачусетском

технологическом.

Прототип

использует ультракороткие высокоинтенсивные

всплески лазерных лучей для получения сцены. Созданное

устройство

способно

НЕВЕРОЯТНО, НО ФАКТ

создавать

СОДЕРЖАНИЕ

5


ПРО

ЛЮБОПЫТНЫЕ ФАКТЫ

№9 (декабрь) 2010

граммист

Прогноз

космической

погоды

начало

публиковать федеральное космическое агентство России

(Роскосмос)

совместно

с

Физическим

институтом Российской академии наук (ФИАН) на

своем

интернет-сайте

http://www.federalspace.ru. представлена солнечной

Посетителям

будет

последние

сутки,

информация

атмосферы

за

о

состоянии

информация о числе солнечных вспышек за 24 часа,

данные

о

сферы

Земли

за

прогноз

геомагнитной

состоянии

три

активности. будет

каждые

30

данным

адресата в Осло на церемонию вручения премии, которая

состоится

11

злоумышленники

получали

атаки, принадлежат китайскому университета Цзяо Тун. В это году Нобелевская

к недовольству официального Пекина, китайскому правозащитнику

Лю Сяобо (Liu Xiaobo),

по

который

ФИАН

тем,

большинство факторов влияют и

собность этом,

Стоит

о

мира

в

на

как

премии

на

работоспо-

В

При

правила

месту

регистра-

пребывания

жительства

об

космичес-

и

внесены

изменения,

позволя-

ющие осуществлять эту

процедуру через интер-

после начала освоения и

но

ции граждан России по

кой погоды приобретут значительно

остальных

на 11, а на 10 декабря.

особую важность учет и

Луны

как

церемония намечена не

отмечается,

изменениях

в

номинациях,

человека,

предупреждение

что

премию

действительно

Стокгольме,

негативно

техники.

строя.

вручают в Осло, а не в

что

как

отметить,

Нобелевскую

указанных

самочувствие так

сударственного

ведомстве

пояснили

удер-

попытку свержения го-

публи-

погоде

российском

сейчас

живается в тюрьме за

urces/rk/rk_rus.png.

космической

премия

мира была присуждена,

обновляться

данных

возможность

адреса, использованные хакерами в ходе этой

http://tesis.lebedev.ru/reso

кации

письму

управлять им удаленно. Установлено, что IP-

Информа-

Необходимость

К

открытия «троянец» инфицировал компьютер, и

дня,

минут

декабря.

прилагался зараженный PDF-файл. После его

магнито-

последние ция

Тор Халворссен (Thor Halvorssen) приглашает

нет.

Марса,

Об

этом

заявил

премьер-министр

менее

Рос-

сии Владимир Путин на

защищенных от внешних факторов, чем Земля.

заседании президиума правительства. По словам

Под

регистрации.

видом

приглашения

на

церемонию

вручения Нобелевской премии мира в Осло по сети распространяется вредоносная программа.

Вредоносные «приглашения» распространялись

по электронной почте. Письма отправлялись от

имени организации «Форум свободы в Осло» (Oslo Freedom Forum), которая не имеет прямой

связи с Нобелевским комитетом. В тексте письма

говорилось, что основатель «Форума свободы»

НЕВЕРОЯТНО, НО ФАКТ

Путина, по интернету можно будет и сняться с Как

пояснил

вице-премьер

РФ

Александр Жуков, такое решение принято в рамках

программы

по

переходу

к

предоставлению госуслуг в электронном виде. Когда

именно

регистрации остается

через

неясным.

московского

услуга

по

К

примеру,

интернет

управления

оформлению

будет

внедрена,

на

сайте

Федеральной

миграционной службы эта услуга отсутствует.

СОДЕРЖАНИЕ

6


ПРО

граммист

ЛЮБОПЫТНЫЕ ФАКТЫ

№9 (декабрь) 2010

В WebMoney Transfer прислушались к жалобам

на сложности регистрации в своей платежной

системе, подумали и сообразили, что оплачивать

товары и услуги в Интернете можно вообще без какой-либо регистрации. Теперь пользователи из

России и Украины, которым лень разбираться во всех этих аттестатах и светить свои паспортные данные,

могут

взять

на

вооружение

сервис

WebMoney Check. Все, что нужно для работы с Смартфон

iPhone

запустили

в

космос:

он

прислал уникальное видео с орбиты. Причем

сделало это не NASA, а группа энтузиастов во

главе с жителем американского городка НьюБург Люком Гейсбюлером и его 7-летним сыном. Запуск был осуществлен с помощью метеозонда. iPhone достиг высоты почти 35 км, после чего целый и невредимый приземлился на парашюте с уникальными

фотографиями

своего путешествия. TP-LINK

представила

и

видеозаписью

всепогодную

точку

доступа TL-WA5210G, позволяющей нескольким пользователям

работать

в

локальной

сети,

интернет, даже если их разделяют километры. Мощность в 27 дбм и неплохая

чувствительность встроенная

приемника,

двунаправленная

антенна с усилением 12 дБи

кошелька как такового нет, в соответствующее поле

нужно

ввести

специальную

пару

лидирующих цифр (для WMR это «07»), после которых

следует

набрать

номер

мобильного

телефона (без «восьмерки»). Таким образом, WMчек

явно

привязывается

к

SIM-карте

и

на

телефон приходит SMS-сообщение с паролем – набором

из

четырех

цифр.

Для

оплаты

в

Интернете необходимо выбрать способ оплаты через

терминал,

поля

(номер

заполнить

телефона

и

соответствующие

пароль), дождаться SMS-ки с одноразовым

подтверждения

кодом

платежа

(8

цифр) и также ввести его в онлайн-форму.

расстоянии до 15 километров.

клеток иммунной системы человека. Эти же

возможна

передача

дистанции до 52 километров.

данных

на

выход в интернет через ADSL или кабельный

режим

для

анализа

так

называемых

Т-клеток

или

клетки отмечают за борьбу организма людей с различными

бактериями

и

вирусами,

попадающими извне. По словам ученых, когда Твырабатываются,

они

модифицируют

собственный ДНК, чтобы успешнее бороться с

WISP

счет

клетки

Поддерживает три рабочих режима:

Единственное отличие в том, что, поскольку WM-

Капля крови установит возраст человека за

При использовании внешней

модем;

платежный терминал в пределах доступности.

позволяет быстро установить

беспроводное соединение на

антенны

этим сервисом – это мобильный телефон, а также

подключения

беспроводным интернет-провайдерам;

внешними факторами и патогенами. В процессе

к

режим точки доступа, включающий функции точки

доступа,

ретранслятора. Всепогодный

корпус

клиента,

моста

TL-WA5210G

WDS

создан

и

для

уличного использования и снабжен защитой от

молний и статического электричества. Точка доступа способна работать в любое время года в диапазоне температур от -30 до 70°C.

НЕВЕРОЯТНО, НО ФАКТ

СОДЕРЖАНИЕ

7


ПРО

ЛЮБОПЫТНЫЕ ФАКТЫ

№9 (декабрь) 2010

граммист

модификации некоторые части ДНК остаются

публичных почтовых сервисов. Истец заявляет,

продолжают существовать, но фактически не

коллективный, так как данное нарушение не

бесполезными

для

используются. цепочек

Т-клеток,

Именно

ДНК

можно

по

причем

количеству

сравнительно

они

таких

точно

установить возраст человека. Созданные сейчас технологии

позволяют

установить

возраст

человека с максимальным отклонением в 9 лет, однако большая часть отклонений не превышает 3-4 лет. Gmail

таки

сканирует

переписку

Житель

роля

говые

обвиняет

фирмы

компанию в том, что она сканирует письма

сказано,

переписки

безопасности

Закон

могла

получить

сообщений.

от

МТС,

владельцем является

менее,

ные

гражданский

«Укртелекомом». сийская

рекламы.

конкурсную

он

не

письме

иссле-

претендентом

«Укртелеком»,

ванной

рынке

к

предпри-

фиксированной

связи.

в микрокорпусе SOT-23 размерами 3х1.3х2 мм

Разностный режим опции DIGIScan:

начала

International

выпускать

Rectifier.

При максимальном напЦифровой пеленгатор DDF190 и мониторинговый приемник вместе

образуют систему радиоконтроля с отличным соотношением цены и

давал

контекстной

на

который

открыто заявил о своем

нем

таргетиро-

«МТС»

вторым

зистор IRLML0060TRPB

характеристик (см. спецификацию на приемник ESMB в ресурсах к

согласия на размещение в

докумен-

Мощный HEXFET тран-

Заявитель отметил, что лично

Фонда

тацию. Таким образом,

Google

в

у

госимущества Украины

Режим прослушивания опции DIGIScan:

дования текста письма и размещения

компания

запросила

собствен-

для

Рос-

ятию – монополисту на

аналитические

алгоритмы

Евтушен-

кова, заинтересовалась

интересе

отличный от Gmail, но не

бизнесмена

Владимира

Rohde&Schwarz,

Панорамный индикатор по ПЧ:

сервис,

использовала

АФК

«Система»

ESMB

стала

использует для работы тем

которой

российская

от

за

Компания

По словам заявителя, он почтовый

долларов

рекламных

Окно обзора:

электрон-

1986 года.

100

размещения

о

коммуникаций

иска

разы больше той прибыли, что компания Google

мониторин-

приемники

заявитель

(по

действиями

нарушает ных

иске

что компания

своими

его

9 кГц до 3 ГГц.

почтовый В

Сам

каждый случай). Очевидно, что данная выплата в

мониторинг в диапазоне от

пользователей,

Gmail.

стоят

и

электронные

работы

сервис

тайны

осуществляющие военный

которые не применяют для

единичным.

требует с Google 10 000 долларов за нарушение

ской службы радиоконт-

штата Техас, некий Кит Данбар

является

На вооружении беларус-

своих

пользователей.

что суду следует рассматривать данный иск как

журналу).

рекламы

и

другой

информации, касающейся содержания письма,

импульсный до 11 А.

ряжении

сток-исток

60В и затвор-исток +10В бен

транзистор

пропускать

спосопосто-

янный ток стока 2.7 А и

тогда как компания сделала это самовольно. В

Новый

принятый

отличается сверхмалым падением напряжения

иске говорится, что это нарушает как ранее принципы,

закон,

так

принятые

и

в

НЕВЕРОЯТНО, НО ФАКТ

общие

среде

этические

владельцев

выпрямительный

NTST30100SG

фирмы

On

диод

Шоттки

Semiconductor

0.39 В при прямом токе 5 A.

СОДЕРЖАНИЕ

8


ПРО

граммист

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

Прежде всего, хочу извиниться перед читателями, за то, что продолжение первой статьи запоздало, простуда подкралась незаметно. Ну вот, уже готова представить вашему вниманию следующую часть рассказа о правильном составлении ТЗ. В прошлой статье я постаралась ответить на вопросы: что такое ТЗ, зачем оно нам необходимо и кто должен его писать. Также постаралась раскрыть возможные последствия отсутствия ТЗ и его неграмотного написания. В этой части постараюсь вам рассказать, что нужно и как нужно писать в первых четырех частях ТЗ. Приятного чтения… Дарья Устюгова

области применяемости программы

by Sparky ustyugova90@mail.ru

Здесь описываем, в какой предметной области

будет применяться наше творение. Для того,

Введение В

чтобы было более понятно, приведу пример из

прошлой

части

материала

я

привела

содержание ТЗ, сложившееся у меня на основе написанных мною ТЗ и прочтенных книгах. Для

того, чтобы не заставлять вас искать содержание в

прошлом

номере

и

сохранить

повествования, приведу его еще раз*.

целостность

Прежде, чем начать разбор того, что же нам писать

в

формальный

ТЗ,

и

хочу

очень

затронуть

еще

важный

один

момент

оформление ТЗ. Касаться моментов оформления

текста ТЗ я не буду, все описано в ГОСТ 19.10678

«Требования

к

программным

документам,

выполненным печатным способом». Что же я

хочу обсудить? Я хочу заострить ваше внимание

на титульном листе. Что же в нем такого важного и ценного? Именно на нем ставятся подписи

разработчика и заказчика. Собственно, только

после того, как мы и заказчик поставим их,

моей

практики:

автоматизации изданий,

программа

учета

применяется

имеющихся

имеющихся

читателей

книжных изданий.

и

для

книжных

выдачи

Сроки исполнения работ Вот мы и подошли к одному из самых сложных

пунктов. Наверное, многие читали байку о том, как программисты строят дом. Для тех, кто не

слышал, обязательно почитайте. Да, я согласна,

ставить перед собой сроки выполнения работ – тяжело. Часто мы не укладываемся в указанные

нами сроки. С чем же это связанно? С тем, что мы не умеем планировать свое время, не можем правильно которые

рассчитать

нам

количество

понадобятся

для

ресурсов,

достижения

поставленной цели. Также нельзя сбрасывать со счетов прочие форс-мажорные обстоятельства.

можно приступать к работе. До этого момента ТЗ

Вообще, советую прочитать такие книги, как:

необходимо вспомнить о плюсе ТЗ: ТЗ документ

не имеет никакого юридического веса. Здесь официальный.

Именно

на

его

основе

будет

решаться, выполнили ли мы все необходимые работы. Как оформить титульный лист описано в

ГОСТ 19.104-78 «Основные надписи». Теперь мы

разберемся с каждым пунктом содержания по отдельности.

данном

банально…

пункте

Мы

все

просто

просто

имя

и

нашей

программы. Ничего сложного, главное – наша фантазия. Краткая

характеристика

ОБЩИЕ ВОПРОСЫ

или

системы;

как

Мифический

создаются

человеко-

программные

Йордан Э., Йордон Эдвард. Путь камикадзе: Как разработчику программного обеспечения выжить в безнадежном проекте.

основе своих проектов довольно сложно. Нужно

довольно

пишем

месяц

Брукс.

Описывать этот пункт в общих чертах и на

Наименование программы В

Фредерик

предметной

помнить, что проекты могут отличаться в корне: сложностью,

количеством

исполнителей,

профессионализмом исполнителей и т.д.

Поэтому просто скажу: читайте про управление проектами,

Management.

в

частности,

про

Project

Time

СОДЕРЖАНИЕ

9


ПРО

граммист

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

заказчика, и не факт что заказчик не поставит

перед нами какие-то свои сроки. Скорее всего,

* Содержание ТЗ:

поставит. Что же нам делать в этом случае? Мы

1. Введение

1.1 Наименование программы

1.2 Краткая характеристика области применения программы 1.3 Сроки исполнения работ

Если

они

совсем

не

длительные сроки, мы соглашаемся. Ни в коем

2.3 Основание для разработки

случае нельзя говорить заказчику: «Что это за гигантские

3. Назначение разработки

3.1 Общая концепция системы

сроки,

мы

справимся

в

2

раза

быстрее». Мы, конечно, теоретически сможем

3.2 Описание функциональности системы

это сделать, а если мы сократим сроки и не

4. Требования к программе

4.1Требованиякинформационнымструктурамиметодамрешения 4.2 Требования к функциональным характеристикам 4.3 Требования к надежности

4.3.1 Требования к обеспечению надёжного функционирования системы

успеем, то останемся в «минусе». Поэтому некий запас во времени никогда не помешает. Мы

рассмотрели оптимальный вариант, но сроки, предложенные меньше.

заказчиком,

Что

же

делать

в

могут

таком

Вариантов немного – всего три...

4.3.2 Типы отказов при работе системой

4.3.3 Время восстановления после отказа

4.3.4 Допустимые потери данных при отказе

4.3.5 Важная информация, которая должна быть защищена от разрушения

4.3.6 Отказы из-за некорректных действий пользователей системы 4.4 Условия эксплуатации

4.4.1 Климатические условия эксплуатации

4.4.2 Требования к квалификации и численности персонала

4.5 Требования к составу и параметрам технических средств 4.5.1 Требования к серверному аппаратному обеспечению

4.5.2 Требования к клиентскому аппаратному обеспечению 4.5.3 Требования к сетевому аппаратному обеспечению

4.6 Требования к информационной и программной совместимости 4.6.1 Требования к исходным кодам и языкам программирования 4.6.2 Требования к программным средствам, используемым программой

оказаться

случае?

Первый вариант: сразу же скажу – он самый наихудший. Почему же? Если сроки чуть меньше

наших, это не смертельно, но довольно опасно. Согласитесь, работать на износ довольно тяжело, но все-таки возможно, вот только неизвестно насколько

это

уменьшит

ли.

уменьшит

самостоятельно,

В

во

общем,

реальные

многом

решать

сроки

и

придется

решение

будет

зависеть от того, насколько вас заинтересует проект и какие риски появятся, если вы не уложитесь в сроки.

Но, если сроки отличаются значительно и мы

4.6.3 Требования к защите информации и программы

беремся за этот проект, проект сразу же можно

4.7 Маркировка и упаковка

записывать

4.8 Транспортировка и хранение

в

безнадежные,

а

нам

готовить

компенсацию заказчику, потому как, зачастую,

4.9 Специальные требования

заказчику недостаточно фразы: «подождите еще

5. Требования к программной документации

месяц

и

все

будет

сделано».

Нет,

конечно,

заказчик может подождать месяц, но вот, если

6. Технико-экономические показатели

нам понадобится второй, заказчик задумается, и все

7. Стадии и этапы разработки 7.1 Стадии разработки

может

закончиться

плачевно

для

нас.

Заказчик сможет наказать нас рублем или еще

7.2 Этапы разработки

хуже – обратиться в суд. Нужно отметить, что

7.3 Содержание работ по этапам

основания для этого у него будут. Также может пострадать наша репутация, а если заказчику

8. Порядок контроля и приемки

понадобится

8.1 Виды испытаний

8.2 Общие требования к приемке работ

пишем

еще

какая-либо

программа,

то

вероятно, что к нам он уже не обратится, да еще и отговорит своих партнеров и просто знакомых.

9. Порядок корректировки Технического задания

ОБЩИЕ ВОПРОСЫ

отличаться.

различаются или заказчик предлагает более

2.2 Исполнитель

мы

самостоятельно. Дальше все будет зависеть от будут

2.1 Заказчик

программу

или навязанные заказчиком и рассчитываем их

того, насколько наши сроки и сроки заказчика

2. Основания для разработки

Но

на время забываем про сроки, предложенные

для

конкретного

Тут мы снова подошли к мысли о том, что ТЗ

СОДЕРЖАНИЕ

10


ПРО

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

документ официальный. И если там написано, что

мы

должны

завершить

свою

12.12.2010, то мы должны это сделать. Второй

вариант:

этого проекта.

отказаться

от

работу

не

факт,

что

это

выполнения

устроит

заказчика.

Необходимо ему объяснить, что уложиться в

сроки, предложенные им – нереально. Сделать это нужно в

доступной для его понимания

форме.

В данном пункте нет ничего нетривиального, просто пишем, кто является нашим родным и любимым заказчиком.

наше детище не может родиться быстрее определенного нами срока.

не требуется глубокий анализ, все это ждет нас впереди. Просто описываем, зачем же наше

творение создается, и какой же от него будет толк.

Приведу

пример:

организовать

работу

система

позволяет

библиотекаря,

систематизировать информацию об имеющихся

книжных изданиях, студентах, преподавателях и

одна особенность: если мы работаем в команде, упомянуть

(указывать

обо

одного

всех

себя

участниках

любимого

недостаточно). Нет, конечно, это можно сделать, но в таком случае за все косяки будете отвечать

самостоятельно. Заказчику все равно, что это ошибка Васи, которого он никогда не видел, и ранее о нем не слышал.

пунктов. Именно в этом пункте описываются требования

к

приложению.

довольно

нам претензии, это будет, чуть ли не первый пункт

проверки

написанию

стоит

экспертов.

уделить

что

от

нас

хочет

пункт.

В

особое

заказчик.

его

внимание.

Но

не

нужно

забывать, что в половине случаев, заказчик сам не совсем понимает, что же его душе хочется

увидеть в нашем творении, и мы должны, какимто образом, это из него вытянуть. Как уже писала в предыдущей статье – это отдельное Договоримся,

функциональные

важный

Поэтому

Именно здесь в большей степени описывается то,

искусство.

Основание для разработки один

Вот мы и подошли к одному из самых важных

Если вдруг случится так, что заказчик предъявит

Данный пункт похож на предыдущий, но есть необходимо

Описание функциональности системы

функциональные

Исполнитель

Еще

3-го варианта.

сотрудниках использующих библиотеку.

Заказчик

проекта

Хочу заметить, что начинать нужно именно с

Заказчик тоже человек, и если грамотно аргументировать, почему

Третий вариант: самый наилучший** для нас, но

** Комментарий автора.

требования

что

все

были

сформулированы и осталось их записать в ТЗ.

большинстве случаев, помимо ТЗ, заказчик и

Как

подробностями обращаемся к гражданскому и

пользователей, мы должны это отразить. Кроме

исполнитель

заключают

договор

(за

трудовому кодексам). В ТЗ указывается, что был подписан

договор

на

указание

услуги

по

созданию программного продукта, указывается

номер договора. Если договора нет, этот пункт будет отсутствовать.

Для

того,

необходимо: области

чтобы

для

программа,

написать

провести которой

определить

анализ

этот

пункт,

предметной

наша

бизнес-задачи

будут решать с ее помощью. Но в данном пункте

ОБЩИЕ ВОПРОСЫ

сделать?

Если

в

несколько

системе

категорий

того, все функции нужно разделить между этими

категориями. Если такого разделения нет, то просто перечисляем функции, которые будет выполнять наше приложение. небольшой

добавляет

предназначена какие

это

представлено

Есть

Общая концепция системы

же

скобках

нюанс,

(изменяет)

необходимо

если

какие-либо

написать

приложение данные,

какие

в

именно

данные добавляются (изменяются). В противном

случае, при сдаче программы в эксплуатацию, заказчик скажет: «А почему в этой табличке нет поля

телефон».

Мы

не

сможем

ему

аргументировано возразить. А в случае, если мы

СОДЕРЖАНИЕ

11


ПРО

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

укажем, какие именно поля содержит таблица, мы просто показываем заказчику документ, в котором

написано,

должно.

что

этого

поля

быть

не

Требования к информационным структурам и методам решения

Название данного пункта звучит страшно, но на самом деле ничего страшного и непонятного в

нем нет. Просто описываем, какие технологии будут

применяться

Приведу

еще

реализована

в

пример:

согласно

нашем

приложении.

система

должна

технологии

быть

«клиент-

клиентами, а также ошибки при работе с базой данных системы);

отказы,

вызванные

технических факторами);

отказы,

сбоем

средств

(иными

вызванные

внешними

неисправностью

технических средств;

электропитания

отказы, вызванные не фатальным сбоем (не крахом) операционной системы;

отказы, вызванные фатальным сбоем (крахом) операционной системы.

Время восстановления после отказа

сервер». В качестве сервера используется СУБД –

Этот пункт напрямую связан с предыдущим. Мы

частей системы должно осуществляться согласно

понадобится на восстановление работы нашего

сервер. Взаимодействие клиентской и серверной протоколу TCP/IP. Требования

характеристикам Этот

пункт

к

функциональным

дублирует

функциональности

системы,

пункт

только

Описание в

более

литературной форме. Также здесь описывается, каким образом реализуется взаимодействие с пользователем, например, при помощи набора первичный и вторичных форм. Требования

к

обеспечению

надежного

функционирования системы

Вот мы и добрались до формальных пунктов, которые пишутся по шаблону. В данном пункте описывается, заказчик работала

для

что

должен

того,

надежно.

чтобы

предпринимать

наша

Просмотрев

программа большое

просто указываем, какое количество времени

приложения при возникновении сбоев (типы, которых описаны выше). Причем конкретное

время, в минутах, указывать не обязательно. Допустим, если произошел отказ, вызванный фатальным

сбоем

должно

превышать

приложение,

сбои

в

соединениями

(ошибки,

с

сетевыми

связанные

с

передачей информации между сервером и

ОБЩИЕ ВОПРОСЫ

и

работе

пункт. Мы, конечно же, можем написать, что при

сбое данные потеряны не будут. К сожалению, Надежное (устойчивое) функционирование программы должно быть выполнением

приведен ниже:

работы

работе

же ему ждать после сбоя, как раз и пишется этот

организационно-технических

подсистеме

его

возможны. Для того, чтобы заказчик знал чего

Заказчиком

мероприятий,

совокупности

перечень

которых

организацией бесперебойного питания технических средств;

регулярным выполнением рекомендаций Министерства труда

использованием лицензионного программного обеспечения;

и социального развития РФ, изложенных в Постановлении от 23 июля 1998 г. «Об утверждении межотраслевых типовых

случаться отказы следующих типов: сбои

в

операционной системы и технических средствах

возможны. В процессе работы системы могут •

на

Каким бы надежным приложением не было наше

обеспечено

Здесь мы просто описываем, какие типы сбоев

требуемого

Допустимые потери данных при отказе

приведу его ниже***.

Следующий пункт, текст которого не меняется.

времени,

и переустановки программных средств.

*** Комментарий автора.

Типы отказов

системы,

устранение неисправностей технических средств

количество ТЗ, я пришла к выводу, что текст

данного пункта везде одинаков, поэтому просто

операционной

достаточно написать: время восстановления не

норм времени на работы по сервисному обслуживанию ПЭВМ •

и оргтехники и сопровождению программных средств»;

регулярным выполнением требований ГОСТ 51188-98. Защита информации. Испытания программных средств на наличие компьютерных вирусов.

СОДЕРЖАНИЕ

12


ПРО

это

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

вариант

утопический.

противоположность

этому

Полная

варианту,

данные

будут потеряны полностью. Но это не устроит

нашего любимого заказчика. Думаю, это никого не

устроит,

механизмами

тем

более,

когда

резервного

транзакциями,

копирования

и

восстановления никого не удивишь. Думаю, для

того, чтобы стало понятно, я приведу пример: при

сбое

в

подсистеме

работы

с

сетевыми

соединениями допускается потеря информации, относящейся к тому справочнику или к той читательской карточке, о которой информация

передавалась по каналу связи в момент сбоя. Главным

допустимых

критерием потерь

перечисленных

при

информации

компонентах

определении

при

сбое

в

является

сохранение целостности данных системы.

Важная информация, которая должна быть защищена от разрушения

Почти в каждом приложении есть информация, которая всегда должна оставаться целостной. Данный пункт предназначен для того, чтобы

зафиксировать, что именно относится к наиболее важной

информации,

необходимо

какие

обезопасить

в

именно

данные

первую

очередь.

Допустим, что наше приложение работает с

какой-либо БД, то, прежде всего, необходимо обеспечить целостность этой БД. Отказы

из-за

некорректных

действий

пользователей системы

Всегда нужно помнить о том, что пользователи бывают

половина

разные. из

них

Исходя «с

из

личного

компьютером

на

опыта, Вы».

Следовательно, наше творение должно терпеть

все нападки таких пользователей и не падать. Поэтому, срочно вспоминаем про try catch. Нет, конечно

можно

не

обрабатывать

данном

пункте

пишем,

ошибочные

ситуации, но это – неправильно. Поэтому, в что

невозможны и реализуем это.

такие

отказы

Климатические условия эксплуатации технические

климатических

климатические

средства

условиях.

условия

ОБЩИЕ ВОПРОСЫ

в

Поэтому

должны

данных

пишем

эксплуатации,

при

обеспечиваться

заданные

характеристики, удовлетворяющие требованиям, предъявляемым

к

техническим

части условий их эксплуатации.

средствам

в

Требования к квалификации и численности персонала Здесь

указываем

минимальное

количество

персонала, который будет работать с нашей программой

и

описываем

квалификации.

требования

Также,

для

к

их

каждого

пользователя, указываем, какие задачи он будет решать, используя наше приложение. Требования

к

составу

и

технических средств

параметрам

Все мы хотя бы раз играли в компьютерные

игры, держали коробочку от диска на которой пишут:

обладать

какими

характеристиками

компьютер,

чтобы

мы

должен могли

насладиться игрой. Вот замечательный пример, иллюстрирующий данный пункт ТЗ.

Требования к исходным кодам и языкам программирования

Данный пункт предназначен для отображения прихотей

очень

разбирающихся

в

привередливых языках

заказчиков,

программирования.

Если, по каким-то причинам, заказчик просит

или требует, чтобы приложение было написано на конкретном языке, именно это отмечаем в

данном пункте. Также здесь отмечаем, хочет-ли получить заказчик исходники программы. Требования

к

программным

используемым программой Здесь

описываем,

необходимо

для

что

из

работы

средствам,

стороннего

нашей

софта

программы,

начиная с операционной системы и заканчивая каким-нибудь ODBC-драйвером. Требования

Работа программы зависит от того, сможет-ли работать

которых

программы

к

защите

информации

и

Нам может несказанно «повезти» и заказчик скажет,

что

в

его

приложении

будет

обрабатываться коммерческая тайна или еще

СОДЕРЖАНИЕ

13


ПРО

О ПРАВИЛЬНОМ СОСТАВЛЕНИИ ТЗ. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

хуже персональные данные или государственная

принципу будут нумероваться версии данной

реализовывать требования различных ФЗ****. А в

носителях программа будет распространяться.

тайна. В таком случае, нам придется читать и ТЗ

необходимо

требования

отметить,

по

защите

какие

информации

именно были

выполнены. Однако, все может быть проще в том случае,

если

заказчик

попросту

попросит

предъявляет

никаких

сделать авторизацию или что-то подобное. Если

же

заказчик

не

требований к защите информации, мы должны не

забыть указать это, чтобы исключить какие-либо вопросы при сдаче проекта.

данном

пункте

Также

указывается,

на

каких

Транспортировка и хранение Увидев этот пункт впервые, я улыбнулась, так как непонятно, что в нем писать. До сих пор

данный пункт остается загадкой, поэтому просто

приведу, если можно так выразить свою отписку: специальных требований к транспортировке и хранению не предъявляется. Специальные требования

Маркировка и упаковка В

программы.

описывается,

по

какому

Для чего нужен данный пункт? Поясню, если у заказчика остались требования, которые мы не сможем включить ни в один из предыдущих пунктов,

**** Справка.

27 июля 2006 г. в России был принят Федеральный Закон № 152-ФЗ

«О персональных данных» для обеспечения защиты прав и свобод человека и гражданина при обработке его персональных данных

(ПДн), в том числе защиты прав на неприкосновенность частной

то

записываем

их

сюда.

Зачем

их

вообще записывать? Не забываем, что именно ТЗ определяет «все ли мы сделали» и в нем должны быть указаны все требования заказчика.

жизни, личную и семейную тайну. Одной из причин принятия

Вместо заключения

персональных

Вот я и рассказала вам о первых четырех главах

данного

закона

послужили

данных

в

многочисленные

государственных

структурах, их повсеместная продажа.

факты и

краж

баз

коммерческих

Информационные системы, обрабатывающие ПДн, должны быть приведены в соответствие с требованиями Федерального закона не позднее 1 января 2010 года. Согласно принятому законопроекту «О внесении изменений в статьи 19 и 25 Федерального закона «О

ТЗ. Надеюсь, что вам после прочтения уже не страшно при упоминании ТЗ и вы уже имеете представление о том, «что и как» в нем писать. В дальнейшем, расскажу об оставшихся моментах.

персональных данных» данный срок перенесен на 1 год – до 1 января

2011

года.

персональных уголовная

За

невыполнение

данных»

предусмотрена

соответствии

со

требований

статьями

Закона

административная КоАП

и

УК

и

РФ)

ответственность. Ответственность может быть наложена как на юридические (организации), так и на физические лица: рядовых сотрудников

и

руководителей

предприятия.

Продолжение следует…

«О

Деятельность

Источники •

организации по обработке ПДн также может быть приостановлена по требованию Роскомнадзора. Конфиденциальность соблюдения

персональным

персональных

оператором данным

или

лицом

данных

иным

обязательное

получившим

требование

не

доступ

для

допускать

к

иного

государственный муниципальный юридическое лицо,

законного

или

орган,

персональных

орган,

физическое

организующие

осуществляющие

основания

данных,

(ФЗ-152).

персональных

• •

также

определяющие цели и содержание обработки

Оператор

и(или)

обработку а

(ФЗ-152).

данных

ОБЩИЕ ВОПРОСЫ

19.201-78.

требования

к

Техническое

содержанию

и

задание,

оформлению

http://www.nist.ru/hr/doc/gost/19201-78.htm

ГОСТ 19.106-78. Требования к программным документам, способом

их

распространение без согласия субъекта персональных данных или наличия

ГОСТ

78.htm

выполненным

печатным

http://www.nist.ru/hr/doc/gost/19106-

Н. Дубова. В круге разработки. – Открытые системы, 2003, №9 http://citforum.ru/SE/ project/circle

Единая система программной документации (ЕСПД) http://www.philosoft.ru/espd.zhtml Комплексный

(унифицированный)

разработки ПО http://www.rup-rus.ru Введение

в

управление

http://www.prjman.ru/theory/32

процесс

проектами

СОДЕРЖАНИЕ

14


ПРО

БЫСТРОЕ НАПИСАНИЕ ПРОГРАММ НА WINAPI

№9 (декабрь) 2010

граммист

Все программисты делятся на две группы – oldschool и новую волну. Сыны старой школы помнят историю о 640 килобайтах, помнят о тысяче игр на одной дискете... Новая волна, чаще всего, даже не знает устройство компьютера, но так же считается – программистами. Использование IDE изменило представление о программистах. Посмотрим, что же может дать отказ от визуального программирования. В этой статье я опишу один из способов быстрого написания приложений с использованием функций WinAPI. Алексей Шишкин

by Alex Cones http://flsoft.ru

можете

насиловать

задаться

свой

мозг,

вопросом, если

быстродействие уровне

(быстрее

на

достаточно

получится

высоком

только,

если

писать целиком на ассемблере – то еще

Вступление или «Кому это нужно?» Вы

разница);

удовольствие). зачем

же

давным-давно

И минусы:

прелести

нет визуализации (труднее представить, что

этот вопрос давайте посмотрим на плюсы и

для создания обычного окна потребуется

изобретена

VCL,

MFC

и

прочие

визуального программирования? Для ответа на минусы

визуального

и

программирования. Итак,

рассмотрим

плюсы

программирования: • •

быстрое

низкоуровневого*

написание

программ

визуального

И

следить

помнить

за

о

(создать

и

необходимости

использованием взятием.

Здесь

*.Free не обойдешься. если

минусах

мы

представим,

программирования

склонится

в

что

сторону

на

памяти

обычным

избавились

WinAPI,

о

чаша

низкоуровневого

программирования. Так как же нам от них избавиться?

размер

приложений

приложение на Delphi весит ~300 кБ; огромного

быстродействием

количества

приходится

«пустое»

надстроек

пренебречь,

особенно в плане графики на Canvas. в

кода

Итак,

взглянем

в

сторону

фреймворков, которые это позволяют. За всю

огромный из-за

строк

освобождением,

весов

противоположность,

рассмотрим

плюсы

низкоуровневого программирования на WinAPI: •

необходимо

описывать каждый шаг на низком уровне, не

удобство использования (это удобнее, чем

50

окно, заботиться о всех параметрах);

Но,

И минусы:

процедуры);

нужно заботиться о памяти).

примерно

зарегистрировать само приложение, создать

(достаточно

накидать кнопок на форму и написать их

создать, что уничтожить, что где писать);

малый размер конечных файлов (согласитесь, что между 30 кБ и 300 кБ есть большая * Комментарий автора.

Здесь под низкоуровневым программированием я имею в виду

программирование без использования графических компонентов использование функций WinAPI напрямую для создания окон, работы с графикой и т.д.

ОТДЕЛ ТЕСТИРОВАНИЯ

мою

практику

программирования

на

Delphi

сталкивался с таким только единожды** – APIx 2 (Visual WinAPI). Но данное средство разработки не

предполагает

графики,

только

активное

создание

использование

окон

и

кнопок.

Поэтому я решил создать такую библиотеку, которая позволит не только быстро создавать окна, но и активно использовать графику.

Не хвастаясь особо, сообщу, что мне это удалось. И через три недели разработки GRAY FUR был готов.

WTF… или что это даст? Mon

ami,

заботиться

это о

же

элементарно:

расходе

и

не

приходе

нужно

памяти,

размышлениям о бренности окон. Да, мы по

СОДЕРЖАНИЕ

15


ПРО

граммист

БЫСТРОЕ НАПИСАНИЕ ПРОГРАММ НА WINAPI

№9 (декабрь) 2010

Delphi, используя пакет для разработки под Delphi.

** Комментарий автора.

Не сомневаюсь, что существуют и другие, но они остались вне

моего поля зрения. Хотя я допускаю, что никто просто не думал о

Для начала создадим то, что кнопка должна

таком - все привыкли к визуальному программированию.

прежнему не имеем дела с визуальностью, но,

делать:

согласитесь, что намного удобнее вызвать одну процедуру,

чем

записывать

пару

десятков

// Эту процедуру будем использовать по клику левой кнопки мыши

с

Procedure HideAll(Handle : HWND);

многочисленными параметрами. Так, например

Begin

отрисовать текстуру на экране можно так:

// Эмулируем нажатие клавиши Win Keybd_event(VK_LWIN,0,0,0);

Var

// Эмулируем нажатие клавиши D

Loc

: HDC;

TNum

: Integer;

Keybd_event(VK_D ,0,0,0); // Отпустим D - все окна свернутся

Begin

Keybd_event(VK_D ,0,KEYEVENTF_KEYUP,0);

Loc := CreateCompatibleDC(DC);

// Отпустим Win

SelectObject(Loc, Bitmap);

Keybd_event(VK_LWIN,0,KEYEVENTF_KEYUP,0);

BitBlt(DC,

End;

X, Y,

Так

Width,

приложения:

Height, Loc,

сделаем

процедуру

закрытия

// Процедура жестокого убийства

0, 0,

Procedure KillMe(Handle : HWND);

SRCCOPY);

Begin

DeleteDC(Loc);

// Удалим таймер, созданием которого мы еще займемся

End;

DestroyTimer(ID); // Уничтожим приложение

А можно и так:

DestroyApplication; End;

Draw(Form1, Num, X, Y, FALSE); BufferDraw;

Причем, если мы не подумаем о том, как создать двойную

же

буферизацию

в

первом

случае

изображение будет мерцать при отрисовке. Во втором случае все это уже встроено в систему.

для

полного

счастья

сделаем

кнопка всегда была наверху:

так,

чтобы

Procedure OnTop; Begin SetformOnTop(Form1, TRUE); // Установим её всегда сверху

Panic button Рассмотрим

И

End;

написание

Panic

button

с

использованием нашей системы. Для того, кто еще не читал моей статьи о создании Panic Button на WinAPI [1] поясню, что эта кнопка на экране будет сворачивать все окна по нажатию на нее.

Итак, скачаем FrameWork [2] и посмотрим, как же это делается. По привычке, я буду делать это на Lazarus, но вы так же можете использовать

ОТДЕЛ ТЕСТИРОВАНИЯ

Да, и еще создадим функцию для вычисления вертикальной позиции:

Function CalculateYp : Integer; Var R : Rect; H : Handle; W : Integer; PH : Integer;

СОДЕРЖАНИЕ

16


ПРО

БЫСТРОЕ НАПИСАНИЕ ПРОГРАММ НА WINAPI

№9 (декабрь) 2010

граммист

program Project1;

Begin // Получаем вертикальное разрешение

{$mode delphi}{$H+} // Директивы для Lazarus

W := GetSystemMetrics(SM_CYSCREEN); ZeroMemory(@R, SizeOf(R));

Uses

// Найдем окно панели задач H := FindWindow('Shell_TrayWnd', Nil);

Windows,

// Подключим

Windows

// Его размеры

Scow;

// Подключим модуль-связку проекта

GetWindowRect(H, R); Var

// Вычислим высоту PH := R.Bottom - R.Top;

Form1 : TForm;

// Наше главное окно. Тип описан в Scow

// И получим искомое

ID : Integer;

// ID таймера

Result := W - PH - Form1.Height; End;

Cамо тело программы представлено в листинге справа. Попробуйте поискать многочисленные

работы с памятью и прочими непристойностями – их просто нет. Таким

образом,

минуса

мы

программ

на

избавились

сложности

написания.

сравнению

с

WinAPI И

от

главного

скорости

получили

и

плюсы:

размер проекта на Delphi всего ~20 кБ по ~300

и

39

кБ

в

Lazarus

по

сравнению с ~900 кБ. Также не пострадало и быстродействие: прямая работа с памятью в

операциях с графикой и прямой вызов WinAPI функций в проекте.

использование

более

3-х

// Создаем приложение CreateApplication;

// Назначим событие по левому клику SetApplicationReaction1(HN_LBUTTONDOWN, HideAll); // Назначим событие по правому клику SetApplicationReaction1(HN_RBUTTONDOWN, KillMe);

// Создадим форму FALSE - не показывать на панели задач CreateForm(Form1, FALSE); // Покажем ее на экране

// Назначим размеры

фреймворка

дало

свои

плюсы. Быстрота написания (на это у меня ушло не

begin

ShowForm(Form1, TRUE);

Вместо заключения Итак,

// Здесь находятся процедуры, описанные выше

минут),

малый

размер

и

быстродействие – все это в одном флаконе. Также его можно запросто использовать для обучения

основам управления программой на WinAPI, так как практически все функции имеют понятные

ResizeForm(Form1, 64, 64); // И положение MoveForm(Form1, 0, CalculateYp); // Загрузим текстуру в хранилище (все подробности управления // графикой см. в документации к проекту) LoadTexture(Form1, 'Button.bmp', 'Button'); // Нарисуем текстуру на буфере

названия и параметры. В общем, я надеюсь, что

Draw(Form1, 'Button', 0, 0, FALSE);

массы.

BufferDraw(Form1);

Ссылки

// Создадим таймер для вызова процедуры OnTop

он, повторяя путь развития Паскаля, перейдет в

• •

Алексей

Шишкин.

WinAPI

графика.

Panic

button. – ПРОграммист, Клуб ПРОграммистов, 2010, №8, с.24 http://procoder.info Скачать

проект

http://squary.ru/wiki/index.php

ОТДЕЛ ТЕСТИРОВАНИЯ

GRAY

FUR

// И выведем его на экран

ID := CreateTimer(1000, OnTop); // И организуем цикл сбора сообщений для корректной // работы приложения CollectMessages; end. // That's all, folks!

СОДЕРЖАНИЕ

17


ПРО

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

Здравствуйте. В этой статье мы продолжим разработку движка динамических теней на OpenGL с использованием ZenGL. В первой части была создана основа для движка, описаны некоторые типы данных. Теперь же нам предстоит сделать самое сложное – написать типы объектов, способы их взаимодействия с источниками света, разобраться каким образом обсчитывается вся геометрия. В качестве основы нужно взять код из первой части статьи. Итак, приступим… Вадим Буренков

объектов, количество и цвет источников света.

vadim_burenkov@mail.ru

На рисунке 1 вы можете увидеть объект сложной

формы, освещенный тремя источниками света различного

Создание объектов Сначала нам необходимо сделать тип данных для наших

объектов,

которые

будут

отбрасывать

тени. В первой части я писал, что такими объектами

будут

многоугольники,

но

в

являться

выпуклые

движке

мы

также

предусмотрим создание объектов круглой формы. Приведем

список

данных,

которые

включать такой объект, а именно:

должен

положение;

данные для полигона: локальные координаты

мировые

координаты

количество вершин, угол поворота;

вершин,

обратить

сделать

внимание,

геометрию

что

теней

наша как

задача

можно

реалистичней. Все объекты должны освещаться плавно,

без ограничений на сложность формы

Рис. 1. Освещение объекта

2D ГРАФИКА

объекты

составления

из

простых,

но

из-за

этого

появляется проблема накладывания теней от

составных частей друг на друга (см. рисунок 3). Чтобы этого избежать нам понадобится еще один параметр

группа.

Объекты

с

одинаковой

группой будут обрабатываться как один, то есть их составные части не будут накладывать тени

друг на друга. Но об этом подробно будет ниже.

Напишем

типы

данныx

для

type PPolyShapeData=^TPolyShapeData; TPolyShapeData=record

данные для круга: радиус.

Хочу

разные

хранения форм и параметров объектов:

тип формы (полигон/круг); вершин,

Также

Объекты сложной формы можно сделать путем

написано

• •

цвета.

должны перекрывать друг друга (см. рисунок 2).

base_Verts: array of leVect; // вершины в лок-х коорд-х Verts: array of leVect;

// вершины в глоб-х коорд-х

VertsNum:integer;

// количество вершин

Angle:single;

// угол поворота (в радианах)

Рис. 2. Тень перекрывает часть объекта

СОДЕРЖАНИЕ

18


ПРО

граммист

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

наверняка заметили, что данные для полигонов и кругов

вынесены

в

разные

типы

данных

в

динамической памяти. При создании объекта в зависимости

использоваться

от

PCircleShapeData.

типа

либо

его

формы

PPolyShapeData,

Поэтому

код

часть

будет

либо кода

процедур будет писаться отдельно для полигонов и для кругов следующим образом: if Obj.ShapeType=lePolyShape

then

if Obj.ShapeType=leCircleShape then

// код для полигонов // код для кругов

Для удобства процедур создания будет две: function le_CreateShadowShape(v:array of leVect;vn:integer;p:leVect;group:single):PShadowShape;

Рис. 3. Тени от частей объекта

overload; var t:PShadowShape; Shape:PPolyShapeData;

end;

i:integer; begin

type

new(t);

PCircleShapeData=^TCircleShapeData;

t.Next:= nil;

TCircleShapeData=record radius:single;

t.Prev:= nil;

// радиус

end;

new(Shape); Shape.Angle:=0;

type PShadowShape=^TShadowShap;

// тип объекта

Shape.VertsNum:=vn;

TShadowShape=record

SetLength(Shape.base_Verts,Shape.VertsNum);

ShapeType:(lePolyShape,leCircleShape); // тип объекта

SetLength(Shape.Verts,Shape.VertsNum);

CircleData:PCircleShapeData;

// форма круга

PolyData:PPolyShapeData;

// форма полигона

Position:leVect;

// положение

Group:single;

// группа

for i:=0 to Shape.VertsNum-1 do Shape.base_Verts[i]:=v[i];

t.PolyData:=Shape; t.ShapeType:=lePolyShape;

prev,next:PShadowShape;

t.Position:=p;

end;

Как

t.Group:=group;

и

другие

данные,

объект

части

статьи),

для

хранится

в

двусвязном списке (см. небольшое описание в

t.Next:= le_Shapes;

понадобится

le_Shapes:= t;

первой

хранить

элемент и их количество:

которого

указатель

на

нам

if le_Shapes <> nil then le_Shapes.Prev:= t;

первый

Result:= le_Shapes; inc(le_NumShapes);

Var le_Shapes:PShadowShape;

// список

le_NumShapes:integer;

// количество

Перейдем

к

функции

2D ГРАФИКА

создания

end;

В объекта.

Вы

первую

передается:

массив

вершин,

их

количество, начальное положение объекта и его группа. Далее происходит создание элемента в

СОДЕРЖАНИЕ

19


ПРО

граммист

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

двусвязном

списке,

выделение

памяти

под

данные вершин и их копирование. Аналогично работает

окружности,

и

вторая

только

передается радиус:

функция

вместо

вершин

создания в

нее

t.PolyData.Verts[i] := le_vAdd(t.position, le_vRotate(t.PolyData.base_Verts[i], rot )); end; end;

При

function le_CreateShadowShape(r:single;p:leVect;

повороте

вершин

использовались

дополнительные функции работы с векторами.

group:single):PShadowShape; overload;

Рассмотрим сложение векторов:

var t:PShadowShape; shape:PCircleShapeData;

function le_vAdd(v1,v2:leVect):leVect;

begin

begin

new(t);

result:=le_v(v1.x+v2.x,v1.y+v2.y);

t.Next:= nil;

end;

t.Prev:= nil;

Поворот вектора v1, где v2.x равно синусу, а v2.y косинусу угла:

new(Shape); Shape.radius:=r;

function le_vRotate(v1,v2:leVect):leVect; begin

t.CircleData:=Shape;

Result.x := v1.x*v2.x - v1.y*v2.y;

t.ShapeType:=leCircleShape;

Result.y := v1.x*v2.y + v1.y*v2.x;

t.Position:=p;

end;

t.Group:=group;

Перейдем к процедуре рисования формы:

t.Next:= le_Shapes; if le_Shapes <> nil then le_Shapes.Prev:= t;

procedure le_DrawShadowShape(t:PShadowShape);

le_Shapes:= t;

var i:integer;

Result:= le_Shapes;

angle:single;

inc(le_NumShapes);

begin

end;

if t.ShapeType=lePolyShape then begin

С помощью перегрузки overload обе функции

glBegin(GL_TRIANGLE_FAN);

по

for i:=0 to t.PolyData.VertsNum-1 do

будут иметь одно название, и различаться только передаваемым

объектам можно

параметрам.

понадобится

обрабатывать

Например,

для

Далее

процедура,

какие-либо

полигонов

по

в

нашим

которой

данные.

локальным

координатам и углу поворота будут обновляться мировые координаты:

procedure le_UpdateShadowShape(t:PShadowShape); var i:integer; rot:leVect; begin if t.ShapeType=lePolyShape then begin // вычисляем кос и син угла поворота тела rot := le_v( cos(t.PolyData.Angle), sin(t.PolyData.Angle) ); // находим координаты вершин (мировые) for i := 0 to t.PolyData.VertsNum - 1 do

2D ГРАФИКА

glColor4f(1,1,1,1);

glVertex2f(t.PolyData.verts[i].x, t.PolyData.verts[i].y); glEnd; end;

if t.ShapeType=leCircleShape then begin angle:=0; glBegin(GL_TRIANGLE_FAN); glColor4f(1,1,1,1); glVertex2f(t.position.x,t.position.y); while angle<=Pi*2 do begin glVertex2f(t.CircleData.radius*cos(angle) + t.position.x, t.CircleData.radius*sin(angle) +

СОДЕРЖАНИЕ

20


ПРО

граммист

№9 (декабрь) 2010

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

t.position.y);

t:= le_Shapes;

angle:=angle+((PI*2)/le_numSubdivisions);

while t <> nil do begin

end;

tNext:= t.Next;

glVertex2f(t.position.x+t.CircleData.radius, t.position.y);

p(t);

glEnd();

t:= tNext;

end;

end;

end;

end;

Алгоритм рисования круга тот же, что и в

Теперь проверим весь этот код в действии. Для

удаления:

объект:

процедуре

le_DrawLightSource.

Процедуры

procedure le_FreeShadowShape(t:PShadowShape); var

del: PShadowShape;

begin del:= t; if t.Prev <> nil then t.Prev.Next := t.Next else le_Shapes:= t.Next; if t.Next <> nil then t.Next.Prev := t.Prev;

if del.ShapeType=leCircleShape then dispose(del.CircleData); if del.ShapeType=lePolyShape then dispose(del.PolyData);

Dispose(del);

dec(le_NumShapes); t:=nil; end;

этого добавляем переменные под вершины и

var verts:array of leVect; TempShape: PShadowShape;

В инициализации создаем многоугольник и круг: SetLength(verts,10); // вершины многоугольника в локальных координатах verts[0]:=le_v(-75,-25); verts[1]:=le_v(0,-55); verts[2]:=le_v(75,-25); verts[3]:=le_v(75,25); verts[4]:=le_v(0,55); verts[5]:=le_v(-75,25);

// Создание шестиугольника TempShape:=le_CreateShadowShape(verts,6,le_v(450,440),0);

procedure le_FreeShadowShapes; var

t, tNext: PShadowShape;

begin t:= le_Shapes; while t <> nil do begin tNext:= t.Next; le_FreeShadowShape(t); t:= tNext; end;

// cоздание окружности с радиусом 40 le_CreateShadowShape(40,le_v(580,480),0);

В обработке будем вращать TempShape вокруг своей

оси

(DegToRad

функция

перевода

градусов в радианы из Math.pas) и обновлять его мировые координаты: // поворот объекта TempShape.PolyData.Angle:=TempShape.PolyData.Angle+

end;

DegToRad(0.5);

Обработка каждого элемента списка: procedure le_EachShadowShape(p:le_proc); var

t, tNext: PShadowShape;

begin

2D ГРАФИКА

// обработка объектов le_EachShadowShape(@le_UpdateShadowShape);

В процедуре рисования выводим все объекты на экран

(это

le_FinishRender

должно чтобы

накладывался сверху):

происходить

буфер

с

до

тенями

СОДЕРЖАНИЕ

21


ПРО

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

массиву

В итоге мы получаем следующее (см. рисунок 4). Опорные точки Перейдем движка.

к

Для

полигонов.

сложной

начала

части

напишем

первой

части

нашего

тени

статьи

я

для

уже

описывал алгоритм добавления теней: после того как в альфа-буфере нарисовали источник света, в него

рисуется

Основной

форма

нашей

тени

задачей

черным

будет

цветом.

являться

нахождение точек, по которым должна строиться

тень. Посмотрим на рисунок 5. QUAD тени будут

строиться по четырем вершинам. Две из них – опорные (отмечены красным цветом), которые являются

вершинами

многоугольника.

Две

другие вершины можно найти путем удаления

боковых от источника света (это легко сделать, удлинив вектор от источника света до боковой точки путем умножения на число). Опорные

вершины

алгоритмом.

многоугольник

Для

находятся

начала

обладает

следующим

заметим,

лицевыми

что

(отмечены

зеленым цветом) и задними (отмечены синим

цветом) гранями относительно источника света. Тогда

опорная

вершина

это

та

вершина,

которая лежит между лицевой и задней гранью. Чтобы получить опорные вершины мы в цикле

пройдем по каждой грани, при этом определяя и

записывая ее тип в массив. Далее пройдемся по

Рис. 4. PShadowShape в работе

2D ГРАФИКА

посмотрим,

где

лицевая

грань

точки. Для работы с векторами нам понадобятся следующие функции:

Вычитание векторов

самой

В

и,

сменяется задней – там и будут нужные нам

le_EachShadowShape(@le_DrawShadowShape);

function le_vSub(v1,v2:leVect):leVect; begin result:=le_v(v1.x-v2.x,v1.y-v2.y); end;

Умножение вектора на число function le_vMult(v1:leVect;n:single):leVect; begin result:=le_v(v1.x*n,v1.y*n); end;

Скалярное произведение векторов function le_vScale(v1,v2:leVect):single; begin result:=v1.x*v2.x+v1.y*v2.y; end;

Перпендикуляр к вектору function le_vPerp(v1:leVect):leVect; begin result:=le_v(-v1.y,v1.x) end;

Рис. 5. Типы вершин

СОДЕРЖАНИЕ

22


ПРО

граммист

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

Рис. 6. Векторы Допустим

у

нас

есть

Рис. 7. Касательные к окружности

вершины

v1,

v2

гранью,

тип

многоугольника и точка l источника света (см. рисунок

6).

Вектор

a

является

которой определяется следующим образом: • • •

получаем

перпендикуляр

вектора

* Комментарий автора. Алгоритм

нахождения

касательных

вы

увидите

в

следующей

процедуре, но разбирать его работу в статье я не буду. Вы можете сделать это сами при желании и определенных познаниях в

грани

геометрии.

(cначала получаем вектор a:=le_VSub(v2,v1),

При обработке происходит получение опорных

получаем вектор от вершины к источнику

находятся

а потом перпендикуляр p := le_vPerp(a)); света (вектор b на рисунке 6) b := le_VSub(l,v2); если

скалярное

вершины

к

произведение

вектора

источнику

света

от и

перпендикуляра грани > 0, то эта грань лицевая, а если <0, то задняя.

объектами.

Сделав

как

быть

точки,

поэтому

описаны в комментариях:

с

несколько

круглыми

рисунков,

окружности (см. рисунок 7).

основные

действия

// тип формы получаемый для обработки

// координаты опорных точек

bpf:integer;

// количество найденных боковых точек

Edges: array of integer;

// массив типов граней

k:integer;

// расчеты опорных точек

i:integer;

// счетчик for

begin Shape:=le_Shapes;

Простые тени

// выполнение блока для каждой формы

Теперь вершины можно приступить к написанию

// нахождение опорных точек полигона

for i:=0 to le_NumShapes-1 do begin

процедуры, просчитывающей и рисующей тени. источник

света,

для

которого она обрабатывает и рисует все тени.

2D ГРАФИКА

QUAD.

v1,v2:leVect; // векторы для расчетов, коорд-ы дальних точек

теней будут касательные* от источника света к

принимает

рисуется

procedure le_RenderShadowGeometry(t:PLightSource);

bp1,bp2:leVect;

становится очевидным, что опорными точками

Процедура

и

CurrentPoint,NextPoint:integer; // точки для опред. граней

// грань задняя

подумаем,

непонятной,

Shape:PShadowShape;

if (le_vScale(p, b) > 0 then // грань a лицевая

Теперь

дальние

Процедура достаточно большая и кажется жутко

var

Или все тоже самое, если записать кодом:

else

точек отдельно для каждого типа формы, далее

if Shape.ShapeType=lePolyShape then begin bpf:=0;

СОДЕРЖАНИЕ

23


ПРО

№9 (декабрь) 2010

граммист

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

SetLength(Edges,Shape.PolyData.VertsNum);

if v1.x > Shape.CircleData.radius

then begin

// расчеты // нахождение и занесение типа грани в массив Edges

v1.y := sqrt(sqr(v1.x)-sqr(Shape.CircleData.radius));

for CurrentPoint:=0 to Shape.PolyData.VertsNum-1 do begin

v2.x := arcsin((Shape.Position.x - t.position.x) / v1.x);

// определение номеров вершин

v2.y := arcsin(Shape.CircleData.radius / v1.x);

NextPoint:=CurrentPoint+1; // если точка первая или последняя в массиве

if Shape.Position.y < t.position.y then k := -1

if CurrentPoint=Shape.PolyData.VertsNum-1 then NextPoint:=0;

else k := 1; // определение координат опорных точек

// расчет боковых точек

bp1.x := trunc(t.position.x +

v1.y * sin(v2.x - v2.y));

v1 := le_vPerp(le_VSub(Shape.PolyData.Verts[NextPoint],

bp1.y := trunc(t.position.y + k * v1.y * cos(v2.x - v2.y));

Shape.PolyData.Verts[CurrentPoint])); v2 := le_VSub(t.position, Shape.PolyData.Verts[CurrentPoint]); if le_vScale(v1, v2) > 0 then // в массиве лицевая грань имеет значение 1 а задняя -1

bp2.x := trunc(t.position.x +

v1.y * sin(v2.x + v2.y));

bp2.y := trunc(t.position.y + k * v1.y * cos(v2.x + v2.y)); end; end;

Edges[CurrentPoint]:=1 else Edges[CurrentPoint]:=-1; end;

// нахождение дальних точек // получаем вектор

// определение боковых точек по массиву

v1:=le_vSub(bp1,t.position);

for CurrentPoint:=0 to Shape.PolyData.VertsNum-1 do begin

// умножаем, чтобы точки вышли за радиус света

NextPoint:=CurrentPoint+1;

v1:=le_vAdd(le_vMult(v1,t.radius*10), t.position);

if CurrentPoint=Shape.PolyData.VertsNum-1 then

// получаем вектор

NextPoint:=0;

v2:=le_vSub(bp2,t.position);

// если умножение дает <0,

// умножаем, чтобы точки вышли за радиус света

if Edges[CurrentPoint]*Edges[NextPoint]<0 then begin

v2:=le_vAdd(le_vMult(v2,t.radius*10), t.position);

// то одна грань лицевая, а другая задняя

// отрисовка тени

// сохраняем координаты опорных точек

glBegin(GL_QUADS);

inc(bpf);

glColor3f(0,0,0);

if bpf=1 then

glVertex2f(bp1.x,bp1.y);

bp1:=le_v(Shape.PolyData.Verts[NextPoint].x, Shape.PolyData.Verts[NextPoint].y); if bpf=2 then

glVertex2f(v1.x,v1.y); glVertex2f(v2.x,v2.y); glVertex2f(bp2.x,bp2.y);

bp2:=le_v(Shape.PolyData.Verts[NextPoint].x, Shape.PolyData.Verts[NextPoint].y); end;

glEnd; Shape:=Shape.next; // переход на следующую форму end;

end; end;

end;

// нахождение опорных точек круга if Shape.ShapeType=leCircleShape then begin // длина от O до А v1.x := sqrt(sqr(Shape.Position.X - t.position.X) + sqr(Shape.Position.Y - t.position.Y)); // если вершина внутри круга

2D ГРАФИКА

Убрав закомментированную строку выполнения этой

процедуры

из

le_RenderLight

можно

запустить приложение, и увидеть проблему (см. рисунок

8).

Решить

ее

можно

разными

способами. Например, рисовать объект после

рисования теней или выводить тень с помощью множества

треугольников,

при

этом

обходя

СОДЕРЖАНИЕ

24


ПРО

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

только в зонах с другими группами. То есть, тени не будут ложиться на объекты, которые их отбрасывают, и другие объекты с такой же группой.

Перейдем от теории к коду: pr2d_Rect(0,0,800,600, 0,255,PR2D_FILL);

1) в процедуре le_RenderLight вместо простого заполнения черным прямоугольником: glDepthMask(true);

// включаем запись в буфер глубины

glDepthFunc(GL_ALWAYS);

// запись в любом результате теста

glEnable(GL_DEPTH_TEST); // включение теста

Рис. 8. Залезание тени на объект

glBegin(GL_QUADS);

форму объекта. Я сделал по-другому, так как в первом

случае

объекты

вообще

не

glColor3f(0,0,0);

будут

glVertex3f(0,0,0);

освещаться и их будет видно даже там, где нет

glVertex3f(0,600,0);

света. А во втором случае не получится сделать

glVertex3f(800,600,0);

сложные объекты и окружности, к тому же рисование

тени

производительнее, треугольников.

одним

чем

QUAD

большим

glVertex3f(800,0,0);

намного

glEnd;

количеством

gldisable(GL_DEPTH_TEST); // выключение теста

Zbuffer и группы объектов Проблема решается

залезания

glDepthMask(false);

теней

использования

на

буфера

объект

легко

глубины

(Z-

Buffer) [1, 2]. В нашем случае, буфер будет использоваться

для

хранения

данных

о

том,

может ли тень определенной группы (то есть тень,

отброшенная

объектом

определенной

группы) нарисоваться в определенном месте (то есть на объектах). Для этого будем использовать DEPTH_TEST

с

параметром

GL_NOTEQUAL.

Параметр PShadowShape.group и будет являться

z координатой при рисовании, как объекта, так и тени.

перед рисованием в альфа-буфер происходит

формы

объектов

глубины альфа-буфера;

заносятся

в

буфер

тени объектов рисуются в альфа-буфер с

тестом глубины. При выполнении теста с параметром GL_NOTEQUAL тени рисуются

2D ГРАФИКА

Далее мы рисуем QUAD с записью в буфер глубины, заполняя z координату нулями: 2)

сразу

после

очищения

буфера

занесем в него формы объектов:

глубины

le_EachShadowShape(@le_zDrawShadowShape);

Чтобы занести формы объектов в буфер глубины

понадобится процедура, аналогичная простому рисованию объекта:

var i:integer;

очистка его буфера глубины;

// выключение записи в буфер

procedure le_zDrawShadowShape(t:PShadowShape);

Алгоритм работы следующий:

всех

// рисуем QUAD

angle:single; begin glDepthMask(true); glDepthFunc(GL_ALWAYS); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND);

СОДЕРЖАНИЕ

25


ПРО

граммист

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

if t.ShapeType=lePolyShape then begin

glEnable(GL_DEPTH_TEST);

glBegin(GL_TRIANGLE_FAN);

glBegin(GL_QUADS);

glColor4f(0,0,0,0);

glColor3f(0,0,0);

for i:=0 to t.PolyData.VertsNum-1 do

glVertex3f(bp1.x,bp1.y,Shape.Group);

glVertex3f(t.PolyData.verts[i].x,

glVertex3f(v1.x,v1.y,Shape.Group);

t.PolyData.verts[i].y,t.Group);

glVertex3f(v2.x,v2.y,Shape.Group);

glEnd;

glVertex3f(bp2.x,bp2.y,Shape.Group);

end;

glEnd;

if t.ShapeType = leCircleShape then begin

glDisable(GL_DEPTH_TEST);

angle:=0;

glDepthMask(false);

glBegin(GL_TRIANGLE_FAN);

Сделаем небольшой пример, чтобы проверить,

glColor4f(0,0,0,0);

как все работает:

glVertex3f(t.position.x,t.position.y,t.Group); while angle<=Pi*2 do begin

// вершины для квадрата

glVertex3f(t.CircleData.radius*cos(angle) + t.position.x,

verts[0]:=le_v(-25,-25);

t.CircleData.radius*sin(angle) +

verts[1]:=le_v(25,-25);

t.position.y,t.Group);

verts[2]:=le_v(25,25);

angle:=angle+((PI*2)/le_numSubdivisions);

verts[3]:=le_v(-25,25);

end; glVertex3f(t.position.x+t.CircleData.radius,

le_CreateShadowShape(verts,4,le_v(260,460),0.1);

t.position.y,t.Group);

le_CreateShadowShape(25,le_v(290,490),0.1);

glEnd();

le_CreateShadowShape(verts,4,le_v(320,520),0.1);

end;

le_CreateShadowShape(25,le_v(200,400),0.11); le_CreateShadowShape(verts,4,le_v(130,300),0.12);

glDisable(GL_BLEND);

Видно (см. рисунок 9), что все три объекта

glDisable(GL_DEPTH_TEST);

правильно

glDepthMask(false);

друга.

end;

Отличие

от

le_DrawShadowShape

в

том,

что

рисование идет только в z-buffer и не отражается на цветовой составляющей. 3)

теперь

переделаем

le_RenderShadowGeometry рисовались

с

учетом

тест

глубины,

Непосредственно включаем

перед

рисование так,

теней

в

чтобы

тени

рисованием

тени

буфера

вершины

глубины.

рисуем

с

указанием z координаты (группы объекта) через glVertex3f а после выключаем тест и рисование в zBuffer:

// отрисовка тени glDepthMask(true); glDepthFunc(GL_NOTEQUAL);

2D ГРАФИКА

освещаются

и

перекрывают

друг

Демонстрационная программа Чтобы нагляднее посмотреть результаты трудов, мною были написаны несколько демосцен (см. рисунок 10 и 11). Демки** запускаются из одного приложения. Каждая сцена хранится в своем модуле,

при

этом

процесс

их

добавления

автоматизирован: достаточно прописать модуль со

сценой

в

uses

и

она

автоматически

зарегистрируется в прогамме (путем выполнения кода в блоке initialization). Оптимизации Можно было-бы сказать, что движок освещения готов,

но

для

хорошей

производительности

просто необходимы оптимизации:

СОДЕРЖАНИЕ

26


ПРО

ДЕЛАЕМ ДИНАМИЧЕСКИЕ ТЕНИ НА OPENGL. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

** Комментарий автора.

С самими демками и исходниками к ним можно ознакомиться в ресурсах к статье.

объекта в радиусе источника света (если объект находится слишком далеко то можно не находить вершины

и

не

рисовать

тень,

что

также

значительно увеличит производительность при большом количестве объектов. Самый простой способ

находить

для

каждого

объекта

и

источника света описывающий прямоугольник и проверять их пересечение);

3) источник света рисуется 32-я треугольниками

с различными цветами вершин (можно достичь большей производительности, если использовать

под каждый источник света свой render target, занося в него изображение при создании света

Рис. 9. Группы объектов 1) обработка данных (расчеты опорных и дальних точек)

и

рисование

должны

происходить

в

разных блоках программы (в нашем случае, все

делается в процедуре le_RenderShadowGeometry, которая находится в блоке рисования. Это может значительно особенно

на

повлиять

слабых

на

производительность,

компьютерах.

Решить

проблему просто: перенести получение вершин теней в отдельную процедуру и сохранять их

или изменении его радиуса/цвета).

Проведя оптимизации, вы получите достаточно быстрый

освещения.

то вершины тени для этого объекта можно

ввести

проверку

изменились

положение источника света и объекта: если нет просто не обновлять);

2) необходимо ввести проверку на нахождение

Рис. 10. Демо-1

2D ГРАФИКА

движок

2D

Ресурс википедии http://ru.wikipedia.org/wiki/ Z%D0%B1%D1%83%D1%84%D0%B5%D1%80

%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%

ли

можно

функциональный

Ресурсы

вершины в отдельный массив. При рисовании просто доставать вершины из массива. Также

и

D1%8F

Информация про Zbuffer http://www.game dev.ru/terms/ZBuffer

Англоязычная статья про создание мягких 2d теней http://www.gamedev.net/reference/ programming/features/2dsoftshadow

Рис. 11. Демо-2

СОДЕРЖАНИЕ

27


ПРО

граммист

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

№9 (декабрь) 2010

Здравствуйте, уважаемые читатели! Помните меня? А статью про WMI, где я на двух языках показывал как просто получить власть над Windows посредством... Ктулху? Не-е-е. Читаем дальше? Однозначно, сегодня мы продолжим наши изыскания... Продолжение. Начало смотрите в предыдущем номере журнала… Виталий Белик

TWMIRecord (на Делфи):

by Stilet www.programmersforum.ru

TWMIRecord=class

Ну, да ладно. Мы же пойдем ровным путем,

private // Список полей и их значений

дающим краткое, но четкое представление о том, как будет работать система. Заранее раскрывая

FFields:TStringList;

к записям и полям таблицы будет похоже на

Procedure Enum(Obj:OleVariant);

разумеется. На С++:

Destructor Free;

карты, скажу, что с Делфийском коде обращение

// Процедура получения данных из полей записи

обращение

Constructor Create;

к

ячейкам

массива.

Двумерного

function GetItem(v: Variant): String;

TWMIRecord* TWMI::Item(int i){

public

TWMIRecord *r=0;

Path:String;

// Инициируем итератор для списка

// Функция возвращающая число полей

list<TWMIRecord>::iterator k;

Function HighRecordIndex:Integer;

// Пройдемся циклом по списку пока не дойдем

// Функция, возвращающая имя i-того поля

// до указанной по номеру записи

Function FieldName(i:integer):String; // Свойство получающее значение определенного поля

for(k=RecList.begin();(k!=RecList.end())&&(i>0);k++,i--);

Property Item[v:Variant]:String read GetItem; default;

// Если записть такая нойдена, в том смысле

end;

// что индекс запрошенной записи

Здесь особое внимание должно быть уделено

// не вылезает за пределы списка

процедуре

// то вернем объект из списка if(k!=RecList.end()&&i>=0){

приняв

объект-

свойство Item, объявленное по умолчанию. Оно

}

может

return r;

принимать

как

строку

при

этом

получить значение по имени поля, так и число, чтоб

};

единственный

которая,

полям, выделив ее значения в свой список, и

r=&*k;

Здесь

Enum(),

запись от энумератора записей, прокатится по ее

бок

я

не

знаю,

как

проверить выход за пределы списка указанного номера запрошенной записи, и так же не знаю

другого способа получить по номеру из списка

без прохода циклом. Поэтому я решил просто написать проход циклом по списку, пока не

определенному

значение

номеру.

Это

из

дает

поля

по

серьезную

мобильность, можно в цикле пройтись по полям, а можно просто получить значение по имени поля (на С++): struct sField{ // Имя поля

конец, или пока нужный номер записи в списке

wstring Name;

не достигнут. В принципе это работает, так что

// Значение поля, переведенное в строку

пусть так и остается.

Ладушки. Пора приступать к описанию второго

получить

wstring Value; };

класса, класса отвечающего за обработку записи

ЛАБОРАТОРИЯ

СОДЕРЖАНИЕ

28


ПРО

граммист

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

№9 (декабрь) 2010

class TWMIRecord

FFields.Clear;

{

// Инициализируем энумератор поля

private:

PropEnum:=IEnumVariant(IUnknown(Obj.Properties_._NewEnum)); // Свойство, принимающее значение поля

// и начнем по нему лазить, пока он выбирает записи

VARIANT Prop;

while (PropEnum.Next(1, Obj, i) = S_OK) do begin

// Обьект-записи полученный от провайдера

try

IWbemClassObject *Obj;

// Здесь я прикрутил распознавание типа даты

wstring FString;

// если поле содержит дату, то привести ее в

// Список полей и их значений

// понятный человеку вид

list<sField> FFields;

if obj.CIMType=$00000065 then begin

// Количество полей

s:=Obj.Value;

int CountList;

s:=copy(s,7,2)+'.'+copy(s,5,2)+'.'+copy(s,1,4);

public:

end else TWMIRecord(IWbemClassObject *AObj);

// если же это не дата, то пусть сама программа приводит

~TWMIRecord(void);

// значение к строке. в противном случае в строку

// Метод, получающий поле по имени

// должно писаться значение [NULL], если поле пусто

sField Field(wstring AName);

if VarIsNull(Obj.Value) then s:=WMIValueNull

// Метод получающий поле по номеру

else s:=Obj.Value;

sField Field(int iName);

FFields.Values[Obj.Name]:=s;

// Функция, получающая верхний индекс в списке полей

except end;

int high();

end;

};

end;

Кто-то скажет: «А зачем Field(wstring AName) возвращает структуру, достаточно ведь вернуть значение?». Верно, но вдруг захочется пополнить структуру

еще

какой-нибудь

характеристикой

function TWMIRecord.FieldName(i: integer): String; begin Result:='';

поля, например, типом, так что пусть этот метод

// если номер попадает в список полей, вернем имя

этом нет. Ок. Реализуем этот класс (на Делфи):

if (i>=0)and(i<FFields.Count) then

возвращает всю структуру – ничего пагубного в

// по его номеру

Result:=FFields.Names[i];

{ TWMIRecord }

end;

constructor TWMIRecord.Create;

destructor TWMIRecord.Free;

begin // Создается класс списка полей и их значения FFields:=TStringList.Create; // Здесь я не предполагал хранить ничегокроме имя и значения // поля, так что TString'a вполне хватит end;

// Освободим список, уберем мусор FFields.Free;FFields:=nil; end;

begin

procedure TWMIRecord.Enum(Obj: OleVariant); i:Cardinal; s:string; d:double;

begin // Приготовим список для внесения в него данных

ЛАБОРАТОРИЯ

begin

function TWMIRecord.GetItem(v: Variant): String;

// Метод проходя по полям

var PropEnum:IEnumVariant;

поля

Result:=''; // Если мы хотим получить значение по номеру поля // нужно проверить, не выходит ли указанный индекс // за пределы списка полей if VarIsOrdinal(v)and(v>=0)and(v<FFields.Count) then

СОДЕРЖАНИЕ

29


ПРО

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

№9 (декабрь) 2010

граммист

// И если не выходит - вернуть это поле

field.Value.clear();

Result:=FFields.Values[FFields.Names[v]];

// получим его, преобразовав в строку в зависимости

// если же мы хотим получить значение поля по имени

// от типа

if VarIsStr(v) then

switch(pvtType){

// мы просто передаем имя, и если

case wbemCimtypeBoolean:

// поле с таким именен есть возвращается его значение

field.Value=(pVal.boolVal)?L"TRUE":L"FALSE";

// иначе вернется пустая строка

break;

Result:=FFields.Values[v];

case wbemCimtypeString:

end;

field.Value=wstring(_bstr_t(pVal.bstrVal,false)); break;

function TWMIRecord.HighRecordIndex: Integer;

case wbemCimtypeSint32:

begin

int i=pVal.intVal;

Result:=FFields.Count-1; // Последний индекс в списке полей

char c[30]="";

end;

itoa(i,c,10); for(int i=0;i<10&&c[i]!=0;i++){field.Value+=c[i];}

Что тут добавить еще? Энумератором получаем

break;

поля и их значения, раскладывая в «массив». И

}

даем возможность выбирать из этого массива в

самой программе, любым способом, по индексу

}

WMIValueNull='[NULL]'. На С++:

FFields.push_back(field);

или

по

имени.

И

еще

константа

const

// и внеся новое поле в наш список

// увеличим счетчик количества полей

TWMIRecord::TWMIRecord(IWbemClassObject *AObj)

CountList++;

{

} }

Obj=AObj; HRESULT hres;

}

BSTR pstrName; VARIANT pVal;

int TWMIRecord::high()

CIMTYPE pvtType;

{

sField field;

// Вернем верхний индекс списка полей

// Начинаем перечисление

return CountList-1;

hres=Obj->BeginEnumeration(0);

}

CountList=0; // Если это возможно конечно, проходимся циклом

TWMIRecord::~TWMIRecord(void)

// пока не нарвемся на ошибку, или пока энумератор

{

// не выберет все данные

// Освободим список

while(!FAILED(hres)&&(hres!=WBEM_S_NO_MORE_DATA)){

FFields.clear();

// Получим очередное "следующее" поле

}

hres=Obj->Next(0,&pstrName,&pVal,&pvtType,0); // Если оно удачно получено if(!FAILED(hres)&&(hres!=WBEM_S_NO_MORE_DATA)){

sField TWMIRecord::Field(wstring AName){ FString=L"";

field.Name.clear();

sField res={L"",L""};

// Запишем его имя

// Приготовим итератор для прохода по списку

Field.Name=wstring(_bstr_t(pstrName,false));

list<sField>::iterator i=FFields.begin();

// Если его значение не пусто

// пока не конец списка

if(pVal.vt!=VT_NULL){

for(;i!=FFields.end();i++){

ЛАБОРАТОРИЯ

СОДЕРЖАНИЕ

30


ПРО

граммист

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

№9 (декабрь) 2010

procedure TForm1.FormCreate(Sender: TObject);

// получим очередной элемент

var w:TWMI;i,j:integer; wr:TWMIRecord;

sField ws=*i;

begin

// проверим не совпадает ли имя поля

// Создадим обьект WMI

// полученного элемента с указанным нами

w:=TWMI.Create(nil);

if(ws.Name==AName){ // Если совпадает

// Выкатим ему запрос

- выйдем из цикла

w.SQL:= ‘SELECT caption, CommandLine FROM Win32_Process’;

res=*i;

with StringGrid1 do begin

break;

// Развернем Грид на нужно е количество записей

}

RowCount:=w.HighObject+1;

}

FixedCols:=0;

return res;

// В цикле пройдясь по записям

};

for i:=0 to w.HighObject do begin wr:=w[i];

sField TWMIRecord::Field(int iName){

if ColCount<(wr.HighRecordIndex+1) then

FString=L"";

ColCount:=(wr.HighRecordIndex+1);

sField res;

// впишем значения полей в таблицу

// Приготовим итератор для прохода по списку

for j:=0 to wr.HighRecordIndex do begin

list<sField>::iterator i;

Cells[j,i]:=wr[j];

// пока не конец или не дост.указ. индекс поля

end;

for(i=FFields.begin();(

end;

i!=FFields.end())&&(iName>=0);i++,iName--);

end;

// Если список полей весь пройден,

w.Free;

// а индекс поля еще не достигнут

end;

// вернем пустые строки. if(i!=FFields.end() && iName>=0){

указать

res.Name=L"";res.Value=L"";} // Иначе вернем данные из списка

модулем,

Опять-таки, итерации по списку – в Делфи, дяди

из Борланда дали возможность обращаться к элементам списка как к массиву, как сделано в

STL я не знаю, поэтому банально – прошелся

циклом по list’y. :) Так... Вроде ничего не забыли

описать? Если нет, то пора попробовать эту махину в действии.

работы

uses

где

описаны

классы.

Если

все

проделано правильно после жмака по F9 на экран выкатится форма со списком процессов

(см. рисунок 1). Ну вот. Запрос SELECT caption, CommandLine

FROM

Win32_Process

получил

набор с заголовками запущенных в целевой системе процессов, и путями к файлам этих процессов.

Администратору

сразу

видно,

что

запущено у пользователя, не нужно идти к нему, или использовать платные средства удаленного

Starting Line Начнем, пожалуй, с Делфи. Создадим проект с кинем

StringGrid,

и

в

обработчике создания формы OnCreate напишем такой код (на Делфи). Перед этим не забудем

создать в проекте Unit (назовем его Unit2), и вложить в него код классов, не забыв в нем

ЛАБОРАТОРИЯ

для

классах

Unit2. Теперь код обработчика на форме связан с

};

него

модули

описанный

указать в разделе uses модуля формы этот самый

return res;

на

в

Classes,contnrs,variants,ActiveX,Comobj. Не забыв

else {res=*i;}

формой,

необходимые

механизма

**** Комментарий автора.

Здесь стоит отдельно оговорить – преобразование полученного поля

при проходе по полям в конструкторе. Я ничего другого не

придумал, как банальное использование старой, доброй itoa(), а после преобразования посимвольный внос из массива символов в

юникодовую строку. Надеюсь, все обратили внимание, что в Си я использовал именно юникодовые строки для хранения значений?

СОДЕРЖАНИЕ

31


ПРО

граммист

№9 (декабрь) 2010

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

Рис. 1. Работа программы написанной на Делфи администрирования.

Увы,

не

все

они

могут

показать такую информацию, а иногда это важно для понимания состояния системы. А теперь

тоже самое но на С++. Лукаво не мудрствуя, сделаем это в консоли, это попроще будет: #include "stdafx.h" #include "TWMI.h" #include <locale> #include <iostream> int _tmain(int argc, _TCHAR* argv[])

ЛАБОРАТОРИЯ

{ // Включим русский язык для консоли setlocale(LC_ALL,"russian"); // Создадим класс WMI TWMI *wmi=new TWMI(); // Скормим ему запрос if(wmi->SetQuery("SELECT caption FROM Win32_Process")){ // Если запрос удачно обработал printf("Получили данные\n"); int i=0;

СОДЕРЖАНИЕ

32


ПРО

граммист

№9 (декабрь) 2010

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

Рис. 2. Получение по имени поля // В цикле пройдемся по записям, for(TWMIRecord *r=wmi->Item(i);r;i++,r=wmi->Item(i)){ // И выведем значение поля wcout<<r->Field(L"Caption").Value<<'\n'; } } else {printf("Неудача");} // после чего уберем мусор delete wmi; getchar(); return 0; }

ЛАБОРАТОРИЯ

Рис. 3. Получение нескольких полей Здесь

тоже

Попросил

самое,

только

разве

заголовки

изменен

запрос.

процессов.

Тут

применен метод получения поля по его имени, но с таким же успехом его можно заменить на: for(int i=0;i<r->high();i++){ sField f=r->Field(i); wcout<<f.Name<<'='<<f.Value<<'\n'; } wcout<<'\n';

Где в цикле будет вестись проход по всем полям

по их номеру. Запустим и посмотрим, что же получилось (см. рисунки 2, 3). Запрос на рисунке

2 показывает, что все хорошо прошло. Объект

СОДЕРЖАНИЕ

33


ПРО

граммист

№9 (декабрь) 2010

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

Рис. 4. Информация о пользователях на целевой машине получил

от

провайдера

WMI

программа вывела ее на экран.

информацию

и

На втором же рисунке показана возможность

показа всех полей, одна запись тут разделена пустой строкой. Вообще, я в запросе указал два

поля CommandLine, но провайдер предоставляет, кроме этого, еще несколько, судя по всему, стандартных полей, характеризующих тип самого запроса.

Например,

свойство

ЛАБОРАТОРИЯ

__PROPERTY_COUNT=2

говорит о том, что мы запросили два поля, между прочим, им можно пользоваться, чтоб узнать количество говорит

о

полей.

использовалось.

том,

Мы

А

__CLASS=Win32_Process

какое

хотели

«представление»

получить

список

процессов – вот и получили, соответственно и класс Win32_Process. Ну и, конечно же, в конце данные о тех самых наших полях, которые мы запрашивали,

Caption

работает замечательно.

и

CommandLine.

Все

Теперь можно самостоятельно написать свою

СОДЕРЖАНИЕ

34


ПРО

граммист

WMI. WЛАДЕНИЕ MАГИЧЕСКОЙ IНФОРМАЦИЕЙ. ЧАСТЬ 2

№9 (декабрь) 2010

***** Комментарий автора.

...или предположим, звонит юзер:

– у меня материнка с ума сошла, дайте дрова! – какая у вас материнка?

– пластиковая, из магазина… Да-да. Это не анекдот. Юзеры, иногда в силу своей компьютерной неграмотности, такое откалывают, что Задорнов «плакаль».

Например, если вызвать метод Terminate класса, полученного по запросу на Win32_Process, то можно

потушить

все

процессы

из

запроса.

Порывшись в MSDN, можно даже найти пример

[2]. Если ссылку еще не завалили, посмотрите, как это делается: запросом получается набор

объектов, у которых вызывается метод Terminate, и они тушатся.

В общем, все это очень обнадеживает, и, если

системный администратор владеет этим каратэ –

Рис. 5. Параметры материнской платы «тулзу»

для

удаленного

администрирования.

Учитывая, что классов в WMI много, можно

много чего узнать***** о компьютерах в сети. Например, можно узнать, что за пользователи

описаны в компьютере, выкатив запрос SELECT * FROM Win32_Account (см. рисунок 4). А, запросив

SELECT * FROM Win32_BaseBoard у виндоуса

цены ему нет. Домен свой он будет держать атланту подобно. Так что рекомендую вляпаться в

эти

микрософтовские

пожалеете. Исходники The Чтиво

серийник есть.

5).

Оказывается

Теперь

достаточно

производителя удаленно,

Асус.

запросить

дровишки

RAdmin’ом

для

О!

И

на

даже

сайте

P5GZ-MX

и

проектов

к

не

статье

приложены в виде архива прямо в журнале.

того пользователя можно увидеть, что у него (см. рисунок

тестовых

катакомбы

Ресурс вики http://ru.wikipedia.org/wiki/WMI

MSDN http://msdn.microsoft.com/enus/library/ aa393907%28VS.85%29.aspx

например,

проинсталлировать. Кто-то скажет: «Так, а чего самим РАдмином или типа него не посмотреть где нить в свойствах?» Где? Все знают, где

информация такая лежит? А ну-ка, партизаны:

«шнель шпрехен...». Я лично не знаю, где можно посмотреть такие подробности. А тут раз – и все как на ладони. А тем паче, своя Наташка... Post Scriptum Ну вот. Собственно, на этом можно поставить

точку. А можно и троеточие, ибо WMI помимо получения

информации

позволяет

управлять

компьютером. Опять-таки теми же запросами.

«Тушить процессы» или выключать компьютер удаленно.

ЛАБОРАТОРИЯ

СОДЕРЖАНИЕ

35


ПРО

MRTOS. МИНИ-ОПЕРАЦИОННАЯ СИСТЕМА ДЛЯ МК AVR

№9 (декабрь) 2010

граммист

При разработке практически любого программного обеспечения для микроконтроллеров выясняется, что программа должно состоять из нескольких, сравнительно самостоятельных задач с возможностью коммуникации этих задач между собой. То есть существует потребность в общей управляющей программе по типу мини-операционной системы… Вячеслав Мовила

найденных ОС для компилятора CodeVisionAVR

http://movila.site11.com

ни одна из них не увенчалась полным успехом. Данная

mRTOS. Общие сведения [1...8] mRTOS

является

(micro

Real-Time

ОС

с

System)

приоритетным

планированием. Причины появления этой ОС таковы: •

необходимость контроллеров автора

ОС

AVR.

для

используют

малых

и

Большинство именно

микроконтроллеров;

средних

проектов

такой

тип

ОС для компилятора CodeVisionAVR.

Малые

и

средние

небольшой

объем

контроллеры

внутреннего

AVR

ОЗУ,

цели,

несмотря

Пожалуй,

альтернативой

на

их

единственной, является

имеют

поэтому

преимущества. достойной

кооперативная

ОС

приоритетным планированием. Вообще

для

того,

преимущества

вытесняющих

микроконтроллер кБайт

мелкие

ОЗУ.

МК

чтобы

должен

Из-за

иметь

применяются

с

использовать

(preemptive)

исходной

минимум

ориентации

упрощенные

ОС 4

на и

облегченные решения что, позволило добиться сравнительно

неплохого

Используется

очень

результата.

Хотя

существует

возможность портирования данной ОС на другую

платформу – WinAVR или ICCAVR. WinAVR к тому

же и бесплатен. Вопрос портирования будет разработки

ниже.

данной

Еще

ОС

одной

было

то,

из

что

причин после

длительных поисков и попыток портирования

ЛАБОРАТОРИЯ

где

на

USART,

контролирующая

и

40 разнообразными внешними сообщений и

другой стороны, данная ОС была использована в

малом проекте на микроконтроллере AT90S2313 –

в

приложении

инициировано

3

задачи

(процесса). И в том и другом случае существенно легче

стало

обеспечивать

сопровождение

и

модификацию,

отладку

Понятнее

и

тексты программ.

программного

прозрачнее

стали

Внутреннее устройство На рисунке представлена блок-схема mRTOS, на

которой можно увидеть, что ОС функционально состоит из 3-х программных блоков. Блок

набор

приоритетного функций

и

которые обеспечивают: • •

программирования С версии CodeVisionAVR* с

рассмотрен

проекте,

общей внешней FLASH памятью 20 Мбайт. С

механизм

В качестве языка разработки ОС выбран язык вставками.

в

устройствами, синтезом звуковых

планирования (и вычисления приоритетов).

ассемблерными

управляющая

Контекст

каждой задачи использует всего лишь 3 байта. простой

построенная

обеспечения.

вытесняющие (preemptive) ОС не подходят для этой

используется

существует сеть микроконтроллеров ATMega162,

Operating

кооперативной

ОС

переключения

системных

задач

переменных,

инициализацию задач (процессов) в системе;

управление приоритетом задач (процессов) в системе;

динамическое (процесса);

изменение

статуса

задачи

переключение задач (процессов), согласно текущим приоритетам.

Блок обработки системных событий – набор * Комментарий автора. Среда

разработки

CodeVisionAVR

является

самым

удобным

инструментом для разработки проектов небольшой и средней степени сложности. Т.е. для проектов, в которых как раз и

используются малые и средние контроллеры AVR. Хотя проект средней сложности – это может быть и достаточно серьезный проект.

СОДЕРЖАНИЕ

36


ПРО

MRTOS. МИНИ-ОПЕРАЦИОННАЯ СИСТЕМА ДЛЯ МК AVR

№9 (декабрь) 2010

граммист

Рисунок. Блок-схема mRTOS

кооперативной операционной системы для микроконтроллеров функций

и

системных

обеспечивают:

переменных,

которые

Для применения mRTOS следует скопировать

регистрацию системных событий;

получения состояния системного события.

сервиса

функций

и

системного

системных

обеспечивают: • •

файлы <mrtos.c> и <mrtos.h> в папку проекта и

установку и очистку системных событий;

Блок

времени

переменных,

подсчет тиков системного таймера; получение работы

системного

ОС)

в

виде

системного таймера.

времени

включить

набор

которые

(времени

количества

использовать. Любой, изъявивший желание, может использовать ее

совершенно

бесплатно

как

в

образовательных целях, так и в некоммерческих и коммерческих проектах.

Единственное ограничение – копирайт, но это у нас никому не

мешает. mRTOS поставляется «как есть» (as is), никаких гарантий, естественно, не предоставляется.

ЛАБОРАТОРИЯ

<mrtos.c>

в

состав

проекта

количество пользовательских задач (блоков

TCB) в строке #define APPTASKS N, где N – это количество задач определяемых в данном

тиков

Эта ОС разрабатывалась для себя и для всех желающих ее распространять

файл

приложения. В файле <mrtos.h> определить:

** Соглашение об использовании mRTOS.

и/или

Применение mRTOS в приложениях

приложении;

количество событий (блоков ECB) в строке #define

MAXEVENTS

N,

где

N

это

количество событий определяемых в данном приложении. Определить

задачи

(процессы)

приложения

описано в пункте «Задачи (процессы) в mRTOS».

Далее следует настроить системный таймер, что подробно описано в пункте «Нулевой таймер микроконтроллера Timer0». В

функции

main

приложения

инициализировать mRTOS: Init_mRTOS().

следует

СОДЕРЖАНИЕ

37


ПРО

MRTOS. МИНИ-ОПЕРАЦИОННАЯ СИСТЕМА ДЛЯ МК AVR

№9 (декабрь) 2010

граммист

Создать (зарегистрировать) задачи (процессы) в системе:

create_task(task1, 10, Active); create_task(task2, 50, Active); create_task(task3, 30, Active);

Выше приведен пример инициализации 3-х задач

в приложении. В действительности, количество, приоритет и статус инициализируемых задач зависит только от программиста. Передать

управление

Sheduler().

планировщику

задач:

При первом вхождении в планировщик задач управление

передается

предопределенной

в

mRTOS (в файле <mrtos.c>) системной задаче

«холостого хода» низкий

приоритет

выполняет

void idle(), которая имеет и,

никаких

программист

всегда

по

полезных может

умолчанию,

действий.

добавить

функцию какую-либо полезную работу. Далее будет

планирование происходить

и

не

переключение

согласно

Но

в

эту

задач

алгоритму

планировщика задач, и зависеть от приоритета и статуса задач. Заключение При проектировании mRTOS были изучены и переработаны

материалы

по

ОС

scmRTOS,

FreeRTOS, csRTOS и был выработан собственный подход

для

использования

достижения

ресурсов

с

минимального сохранением

необходимых функциональных возможностей.

В файле для загрузки помещены файлы mRTOS: <mrtos.c>

и

<mrtos.h>,

а

также

Спасибо Олегу Самоткову за его работу по

портированию mRTOS для компилятора AVR GCC (WinAVR). Ресурсы • • • • •

файл

примерами для микроконтроллеров AT90S2313 и

с журналом.

документации в формате PDF и две папки с ATMega162 [9, 10] или непосредственно в архиве

*** Комментарий редакции.

Как правило, в подобные системы включают сторожевой таймер (Watchdog

timer

http://ru.wikipedia.org/wiki/Сторожевой_таймер).

Ведь не исключено, что один из процессов зависнет (например, изза

ошибок

во

входных

параметрах,

несоблюдении условий эксплуатации т.д.).

ЛАБОРАТОРИЯ

аппаратном

сбое

при

• •

Иртегов

Д.В.

Введение

в

операционные

системы. – СПб.: БХВ-Петербург, 2002. – 624 с.: ил.

Столлингс В. Операционные системы, 4-е

издание.: Перев. с англ. – М: Издательский дом «Вильямс», 2002. – 848 с.: ил.

Гордеев А.В., Молчанов А. Ю. Системное

программное обеспечение. – СПб.: Питер, 2002. – 736 с.: ил. Олифер

Н.А.,

Олифер

В.Г.

Сетевые

операционные системы. – СПб.: Питер, 2001. – 544 с.: ил.

Таненбаум Э. Современные

операционные

системы. 2-е изд. – СПб.: Питер, 2002. – 1040 с.: ил.

Операционные

системы.

Учебное

Рощин Алексей Васильевич. Алгоритмы

планирования

Embedded

Multitasking

времени. И.С. Гусев.

microcontrollers. Keith E. Curtis

пособие.

процессорного with

small

Ресурсы. mRTOS порт CodeVision

http://movila.site11.com/attachments/011_mRT OS.rar

Ресурсы. mRTOS порт WinAVR

http://movila.site11.com/attachments/011_mrtos GCC.zip

СОДЕРЖАНИЕ

38


ПРО

ЗАПИСЬ ДИСКОВ В DELPHI СРЕДСТВАМИ IMAPI

№9 (декабрь) 2010

граммист

Доброго времени суток уважаемые любители Delphi. В этой статье я расскажу про запись CD/DVD дисков в среде Delphi. Общие принципы, изложенные в этой статье подойдут не только для языка Delphi, но и для языка С++. Для прочтения этой статьи с максимальной пользой, читателю рекомендуется получить базовые понятия об OLE/COM, впрочем даже незнание этих понятий вряд ли помешает понимаю этой статьи, так как классы и компоненты Delphi (так же как и классы С++), которые мы будет использовать полностью скрывают от нас все тонкости и неудобства использования COM интерфейсов для записи дисков. Руслан Аблязов

нам надо для этого сделать. Объясняю, как

by rpy3uH www.programmersforum.ru

импортировать

Технология, которая будет описываться в этой статье это технология IMAPI v2.0. Одной статьей эту

технологию

описать

не

представляется

возможным, поэтому в этой статье будут описаны

только основы работы с IMAPI2. Эта технология довольно-таки

новая,

и

поддерживается

операционными системами Windows XP SP2, 2003 Server,

Vista

и

использовать

т.д.

Т.е.

технологию

перед

IMAPI2,

тем

как

следует

убедиться, в том, что операционная система на компьютере,

на

котором

будет

библиотеку

типов

для

пользователей Delphi 7 (англ). Выбираем меню

работать

программа, является как минимум одной из

вышеперечисленных или более новая (например, Windows 7). «Олицетворением» IMAPI2 являются

две библиотеки imapi2.dll и imapi2fs.dll. Перед

Project → Import Type Library. В открывшемся

окне в списке находим «Microsoft IMAPI2 Base

Functionality (Version 1.0)», внизу ставим галочку

«Generate Component Wrapper» (по умолчанию она

поставлена),

Выбираем

нажимаем

вкладку

выбираем

файл,

«Into

куда

кнопку

new

будет

«Install».

package»

сохранен

и

пакет,

нажимаем кнопку ОК. После чего мастер сразу предложит

установить

эти

компоненты,

новые

компоненты

нажимаем «Yes» после установки перезагружаем Delphi.

По-умолчанию

должны установить на вкладку ActiveX. После чего

проделываем

«Microsoft

IMAPI2

(Version 1.0)».

то

File

же

самое

System

Image

Creator

Компоненты

компьютере, должны убедиться, что эти две DLL

создает классы и компоненты, которые являются

которая

будет

работать

на

существуют. Если их нет, то следует установить обновление

KB932716

с

узла

Microsoft.com

(ссылки на скачивание обновления, а также

обновление для Win XP смотрите в конце статьи) [1, 2].

Итак,

мы

убедились,

програм-

мировать. Как уже было сказано, Delphi сама оболочками

интерфейсов,

вокруг что

соответствующих

максимально

COM

упрощает

программирование. Но есть один минус. Если мы используем интерфейсы напрямую, то если их

работа методов заканчивается неудачно, то они просто

Что нам понадобится?

можно

пунктом

тем как использовать эту технологию вы или программа,

установлены,

с

возвращают

ошибку,

когда

мы

неудачи

генерируют

используем «дельфийские» классы, то методы что

IMAPI

v2

поддерживается операционной системой. Теперь нам нужны заголовочные файлы, вернее нам

надо установить компоненты для записи дисков. Программистам С++ по этой части проще, так как в Platform SDK есть заголовочные файлы и их

надо только подключить, чтобы воспользоваться

классов

в

случае

исключения, поэтому рекомендуется заключать вызовы

методов

и

важные

участки

кода

заключать в блоки try/except. Во время отладки (когда

мы

запускаем

программу

нажатием

кнопки F9) сообщения об ошибках, все равно выводятся, что довольно-таки раздражительно.

классами для записи дисков. Но в Delphi тоже не

В

библиотеку типов. После импорта библиотеки

COM интерфейсов мы сможем писать программы

очень

сложно,

в

Delphi

надо

импортировать

типов Delphi сама создаст компоненты и классы

для записи дисков и установит их в палитру. Что

АРХИВ

этой

статье

будут

описаны

методы

COM

интерфейсов, так как зная методы и названия не только на Delphi, но и на С++ и VB. Методы и свойства компонентов Delphi описываться не

СОДЕРЖАНИЕ

39


ПРО

ЗАПИСЬ ДИСКОВ В DELPHI СРЕДСТВАМИ IMAPI

№9 (декабрь) 2010

граммист

будут, так как в них и так все интуитивно понятно и просто.

MsftDiscRecorder.InitializeDiscRecorder(

Первое что надо сделать – это получить список

RecordersComboBox.Items.Add(MsftDiscRecorder.VendorId+'

MsftDiscMaster.Item);

приводов, которые могут прожигать диски и к

'+MsftDiscRecorder.ProductId);

которым можно получить доступ через IMAPI2. Это

можно

сделать

через

MsftDiscRecorder.Disconnect;

интерфейс

except

IDiscMaster2. Первое, что нам надо узнать – это

RecordersComboBox.Items.Add('---');

поддерживает ли хотя бы один привод в системе

запись дисков, и к нему можно обратиться через

end;

интерфейс IMAPI2. Для этого надо вызвать метод IDiscMaster2::get_IsSupportedEnvironment.

end;

Если

RecordersComboBox.ItemIndex:=0;

мы получим результат true, то в системе есть, хотя бы один подходящий для нас привод. Для получения

общего

системе

количества

надо

вызвать

IDiscMaster2::get_Count. уникального

Для

идентификатора

приводов

в

метод

получения

привода

надо

вызвать метод IDiscMaster2::get_Item.

Следующий пункт – это инициализация привода и получение от него информации, пока нам понадобится

только

VendorId

и

ProductId

привода. Именно эти две строки дают нам то названием

привода,

которое

выводится

в

диспетчере устройств. Для получения этих двух идентификаторов

надо

вызвать

методы

IDiscRecorder2::get_VendorId, IDiscRecorder2::

get_ProductId. Разумеется, сначала надо вызвать метод

IDiscRecorder2::InitializeDiscRecorder,

который принимает уникальный идентификатор привода,

полученный

IDiscMaster2::get_Item.

от

метода

TMsftDiscRecorder2.

TMsftDiscMaster2

Далее

приведу

получения списка доступных нам рекордеров:

var i:integer; begin RecordersComboBox.Clear; for i:=0 to MsftDiscMaster.Count-1 do

try

АРХИВ

и

код

procedure TForm1.UpdateRecordersButtonClick(Sender: TObject);

begin

Combobox

будут

выведены

все

доступные

пишушие рекордеры. Если какой-либо рекордер будет недоступен, то вместо его имени будет выведено «—».

Едем далее. Мы нашли нужный нам рекордер, теперь надо создать образ диска для записи. За создание

образа

IFileSystemImage. интерфейсе

отвечает

Файлы

и

представляются

папки

интерфейс в

этом

интерфейсами

IFsiFileItem и IFsiDirectoryItem. Для получения корневой

папки

надо

вызвать

метод

IFileSystemImage::get_Root. Получив интерфейс корневой папки можно спокойно добавлять в образ файлы и папки. Есть несколько методов

добавления файлов и папок в образ, я опишу наиболее простые из них.

Чтобы добавить папку со всеми ее файлами использовать

метод

IFsiDirectoryItem::AddTree, ему надо передать два

Итак, займемся самой «дельфей». Ставим на компонент

В

удобно

Приступим к практике… форму

end;

параметра. Первый параметр это путь к папке, второй параметр имеет тип Boolean, если он

равен true, то в образ будет добавлена сама

папка и все содержащиеся в ней файлы и папки, если параметр равен false, то в образ будут добавлены только файлы и папки, содержащиеся в искомой (искомая папка не будет добавлена).

Для добавления файла необходимо использовать метод

IFsiDirectoryItem::AddFile,

первый

параметр задает имя файла в образе, второй параметр

задает

интерфейс

IStream

с

содержимым искомого файла. Для получения

IStream c содержимым нужного файла можно

использовать функцию SHCreateStreamOnFileEx. Ни в одном заголовочной файле Delphi нет этой

СОДЕРЖАНИЕ

40


ПРО

ЗАПИСЬ ДИСКОВ В DELPHI СРЕДСТВАМИ IMAPI

№9 (декабрь) 2010

граммист

функции (как минимум в Delphi 7), поэтому приведу объявление этой функции:

fCreate:BOOL;

отвечает

функции

параметра, параметр

нам

первый

это

путь

и к

интересно

искомому

два

Первый

файлу,

в

последний параметр будет сохранен поток с

содержимым файла. Теперь можно написать код, которые создает образ диска из файлов пути, к которым занесены в ListBox:

if FileExists(FilesListBox.Items)

Для

установки

производиться

привода,

запись

на

надо

котором

вызвать

будет

метод

IDiscFormat2Data::put_Recorder. Чтобы запустить запись

диска

надо

вызвать

метод

IDiscFormat2Data::Write, передав ему в качестве можно

написать

функцию,

которая

var wstr:WideString;

then

i:integer;

begin

DiscRoot:IFsiDirectoryItem;

wstr:=FilesListBox.Items;

resimage:IFileSystemImageResult;

SHCreateStreamOnFileEx(PWideChar(wstr) ,0, 0,

DiscStream,fstream:IMAPI2_TLB.IStream;

False ,nil, IStream(fstream));

DR:IDiscRecorder2;

DiscRoot.AddFile(ExtractFileName(

begin

FilesListBox.Items), IMAPI2FS_TLB.IStream(fstream));

if RecordersComboBox.Items[RecordersComboBox.ItemIndex]='---'

end;

then exit;

end;

Чуть не забыл, чтобы задать имя диска надо вызвать

IFileSystemImage::put_VolumeName.

Для

метод

того

чтобы установить настройки файловой системы в зависимости от того, какой диск вставлен в надо

вызвать

IFileSystemImage::ChooseImageDefaults, качестве

параметра

IDiscRecorder2.

дальше.

результирующий

метод

передав

интерфейс

мы

if FilesListBox.Count=0 then exit; MsftDiscRecorder.InitializeDiscRecorder( MsftDiscMaster.Item[RecordersComboBox.ItemIndex]);

DiscRoot:=MsftFileSystemImage.Root;

MsftDiscFormat2Data.Recorder:= MsftDiscRecorder.DefaultInterface; MsftDiscFormat2Data.ClientName:='IMAPI';

Для

образ,

того,

надо

чтобы

вызвать

создать метод

IFileSystemImage::CreateResultImage. После его получим

IFileSystemImageResult.

АРХИВ

работе с IDiscFormat2Data.

procedure TForm1.BurnButtonClick(Sender: TObject);

DiscRoot.AddTree(FilesListBox.Items,true);

вызова

Также

IDiscFormat2RawCD,

ListBox:

if DirectoryExists(FilesListBox.Items) then

Идем

IDiscFormat2Data.

записывает на диск файлы и папки указанные в

begin

в

интерфейсы

стирания дисков), работа с ними аналогична

Теперь

for i:=0 to FilesListBox.Count-1 do

ему

нам

параметра IStream с содержимым образа диска.

DiscRoot:=MsftFileSystemImage.Root;

привод

образ,

IDiscFormat2TrackAtOnce, IDiscFormat2Erase (для

только

последний.

результирующий

интерфейс

есть

external 'shlwapi.dll' name 'SHCreateStreamOnFileEx';

этой

получили

осталось только записать его. За запись образа

pstmTemplate:IStream; var ppstm:IStream):DWORD;stdcall;

В

метод IFileSystemImageResult::get_ImageStream. Мы

Function SHCreateStreamOnFileEx( pszFile: PWChar; grfMode:DWORD; dwAttributes:DWORD;

понадобится его IStream, для этого надо вызвать

Для

интерфейс

записи

нам

DR:=IDiscRecorder2(MsftDiscRecorder.DefaultInterface); MsftFileSystemImage.ChooseImageDefaults(DR); MsftFileSystemImage.VolumeName:= DiscVolumeNameEdit.Text;

СОДЕРЖАНИЕ

41


ПРО

ЗАПИСЬ ДИСКОВ В DELPHI СРЕДСТВАМИ IMAPI

№9 (декабрь) 2010

граммист

его к интерфейсу IDiscFormat2Data. К счастью, мастер Delphi избавил нас от этой мороки и

for i:=0 to FilesListBox.Count-1 do

создал компоненты со свойствами событиями,

begin

таким образом поставить свой обработчик так же

if DirectoryExists(FilesListBox.Items) then

легко, как и поставить обработчик нажатия

DiscRoot.AddTree(FilesListBox.Items,true); if FileExists(FilesListBox.Items)

кнопки. Приводить полный код обработчика не

then

имеет смысла, поэтому далее приведен только

begin

код который выводит текущий прогресс:

wstr:=FilesListBox.Items; SHCreateStreamOnFileEx(PWideChar(wstr),0,0,False,nil, IStream(fstream)); DiscRoot.AddFile(ExtractFileName(FilesListBox.Items), IMAPI2FS_TLB.IStream(fstream));

procedure TForm1.MsftDiscFormat2DataUpdate(ASender: TObject; const object_, progress: IDispatch); var CurProgress: IDiscFormat2DataEventArgs;

end;

CurDiscF2D:IDiscFormat2Data;

end;

writtensectors:int64; begin

resimage:=MsftFileSystemImage.CreateResultImage; DiscStream:=IMAPI2_TLB.IStream(resimage.ImageStream);

LogListBox.Clear;

CurProgress:= progress as IDiscFormat2DataEventArgs; CurDiscF2D:=object_ as IDiscFormat2Data;

if CurProgress.CurrentAction =

LogListBox.Items.Add('запись началась');

IMAPI_FORMAT2_DATA_WRITE_ACTION_WRITING_DATA then

MsftDiscFormat2Data.Write(DiscStream);

begin

MsftDiscRecorder.EjectMedia;

writtensectors := CurProgress.LastWrittenLba-

MsftDiscRecorder.Disconnect;

CurProgress.StartLba;

BurnButton.Enabled:=false;

ProgressBar1.Position := round((writtensectors /

ShowMessage('запись закончилась');

CurProgress.SectorCount )*100);

end;

end;

Вроде бы все. Осталось только выводить текущее

состояние записи. Для этого нам надо создать свой интерфейс с методом Update:

Для получения текущего количества записанных

секторов надо вычесть из адреса последнего

HRESULT Update(

записанного сектора, адрес сектора, с которого

[in]

IDispatch *object,

[in]

IDispatch *progress

началась запись. Через

);

Параметр

интерфейс

object

осуществляет указывает

указывает

на

текущий

Параметр

progress

IDiscFormat2Data, запись.

на

IDiscFormat2DataEventArgs, текущее

состояние

записи.

IDiscFormat2DataEventArgs

которые

интерфейс

содержащий

является

интерфейса IWriteEngine2EventArgs.

Интерфейс потомком

Перед записью диска, необходимо, созданный

нами интерфейс с обработчиком подсоединить

АРХИВ

end;

IMAPI2

доступны

все

возможности

необходимые при записи дисков, в том числе и скорость записи. Заключение Вот, пожалуй, и все на сегодня. Если нужны еще какие-то аспекты записи дисков, которые вам хотелось бы, чтобы я осветил в следующих

статьях, пожалуйста, оставляем комментарии со своими пожеланиями. Возможны неточности и ошибки,

критике.

буду

рад

любой

конструктивной

СОДЕРЖАНИЕ

42


ПРО

граммист

ЗАПИСЬ ДИСКОВ В DELPHI СРЕДСТВАМИ IMAPI

№9 (декабрь) 2010

Рисунок. Окно тестового проекта записи дисков средствами IMAPI В архиве [3] находится исходник программыпримера* к этой статье (см. рисунок). Так же

* Комментарий автора.

Win XP SP2 Rus.

прямо из Delphi. Поэтому, в некоторых случаях, рекомендуется

прилагается архив с обновлением KB932716 для Все

Программа-пример не всегда нормально работает, если запущена запускать его отдельно от Delphi.

упомянутые

в

статье

исходные

коды

приведены в виде ресурсов непосредственно в архиве с журналом. Ресурсы • • • •

Официальная страница IMAPI на узле MSDN http://msdn.microsoft.com/enus/library/ aa366450(VS.85).aspx Официальная KB932716

страница

на

узле

с

обновлением

Microsoft.com

http://support.microsoft.com/kb/932716 Скачать

архив

с

исходником

http://pblog.ru/wpcontent/uploads/

на

Delphi

burncdsample.zip

Скачать обновление KB932716 для Win XP SP2 Rus http://pblog.ru/wpcontent/uploads/ windowsxp-kb932716-v2-x86-rus.zip

АРХИВ

СОДЕРЖАНИЕ

43


ПРО

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

№9 (декабрь) 2010

граммист

Многие наверняка, в свое время, задавались интересным вопросом: «А вот как бы задействовать всю силу применяемой в моем проекте СУБД? Не только стандартные SQL запросы, а и скрытые возможности». Тогда ведь можно будет получать результат наиэффективнейшими методами... Виталий Белик

by Stilet www.programmersforum.ru

«УРА!»

Верно. Не так уж и сложно разработать свой

провайдер, по крайней мере для FoxPro. Думаю, что эта СУБД еще имеет широкое применение. А вот как – описано в статье.

хочется

поделиться

я

и

попытался

почитать

малоприятно читать чужие писульки, особенно, если они плохо закоментированны…

Основное для себя уяснил – функции, которые мне

нужны

были с

оформлялись

четкими

в

виде

названиями,

соответствуя своим задачам, дабы их аргументы

Ну, что ж. Вот и я дожил до того, что пишу статью.

сказал

подпрограмм

Предисловная поболталовка собственную

«километровый» код программы… Скажу вам, что

Возможно

потому

наработками

что

или

из

альтруистических побуждений, или потому что не нашел аналогичных статей (может искал плохо). Но истинный смысл в том, что многие

были предельно понятны, и вызывать их не

составляло труда. Но, это можно было сделать только

в

FoxPro…

Так

что

пришлось

мне

выбирать: либо писать свои, и терять время, либо как-то заставит самого Фокса выполнять этот код.

знают и умеют интегрировать свои программы с

Я выбрал второе, поскольку я ленивый и мне

истинами, прописанными кем-то из аналогичных

методику. И вот, что из этого вышло…

СУБД

обычными

путями

(непрекословными

побуждений), а ведь на них свет клином не

сошелся. Очень жаль, что не всегда то, что кажется хорошим – хорошее на самом деле.

Вот и я столкнулся с весьма нетривиальной

ситуацией, в которой нужно было разработать программу,

хранящую

и

обрабатывающую

данные в какой-нить удобной локальной СУБД. Первое,

что

воспользоваться благо

Delphi

Неплохо,

пришло

его

в

голову*

стандартным любит

методы

и

набором

уважает.

стандартные,

А

это

ADO, что?

хорошо

задокументированные (от BDE, которого изучают в любых универах, отличающиеся мало).

Да никто и не спорит: ADO удобно, можно подключить любую СУБД, проинсталированную на

локальном

компьютере

провайдера удаленно.

или

подключить

«Что ж, можно попробовать» – подумал я. Но, только я начал набирать программу и базы, как оказалось, что все это до меня уже набрано хитрыми

программистами.

Базы,

коды-

расчетчики… Все уже есть, но не в Delphi, а в достаточно популярной ранее СУБД – FoxPro.

АРХИВ

никак не хотелось перелопачивать заново всю Немного теории Для

начала

пару

слов

об

ADO.

Говоря

о

компоненте Delphi, ADO позволяет обрабатывать

команды классического SQL плюс SQL навороты, которые поддерживает провайдер в командах. Для этого можно использовать: либо ADOQuery, как привычный компонент, либо ADOCOmmand, позволяющий

выполнять

как

отдельные

команды, так и целый файл с таковыми.

Однако и в этой ложке меда оказалась своя

бочка дегтя. И дело здесь вот в чем. Многим

известно, что FoxPro – это одна из первых СУБД, являющаяся на то время весьма революционной. Помимо применения сверхбыстрых (на то время) технологий обработки данных RushMore,

она

еще и имела мощный язык обработки данных, который, кстати, не очень сильно изменился и по сей день. Его возможности позволяли достаточно гибко работать с данными, написав при этом * Комментарий автора.

А тут читатель скажет: «А что же еще могло прийти?».

СОДЕРЖАНИЕ

44


ПРО

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

№9 (декабрь) 2010

граммист

кода меньше, чем скажем в Клиппере. К тому же,

пользовались

прадедушками нынешней DLL, что само по себе

программистом.

ядро

FoxPro

было

сделано

оверлеями

давало неплохую экономию ресурсов и прирост скорости даже на слабеньких машинах 8086.

С переходом под крылышко Микрософтовцев, эта СУБД

приобрела

полноценный

модуль

провайдера, и стала доступна как COM система.

«Что ж, гарно» – сказали программисты и… слегка

урезали,

обломались что

он

уже

провайдер

перестал

настолько понимать

стандартные команды этой СУБД, кроме тех, что попадают под определение классического SQL (SELECT, DELETE, UPDATE, CREATE, ALTER…).

Но оригинальный язык Фокса** был помимо этих

команд наполнен массой функций, которые увы

оказались запертыми в недрах ядра системы, и могли

выполняться

лишь

написанными в самом FoxPro. Практически

все

функции

программами,

их

в

FoxPro

множество) больше не могли работать в ADO. А

ведь было бы удобно, тем кто знает эту СУБД как пять

своих

пальцев,

использовать

ВСЕ

ее

возможности в своих программах, написанных на других языках.

Впрочем, ладно, разговор не об этом… Вернемся к

нашим

баранам.

Поскольку

ADO

мы

отбрасываем, возникает вопрос: «...а что вместо него?».

Резонно.

Что

ж,

есть

возможность

решения этой проблемы. Дело в том, что FoxPro была сделана во времена, когда большой славой

Тут я сделаю отступление, ибо может кто-то скажет: «Да ради

бога, пусть пишут прям на Фоксе». Однако, тут много минусов. Дело все в том, что прибрав к рукам СУБД Микрософт не особо

позаботилась о ее прогрессе, оно и понятно – купил конкурента, чтоб задавить своими продуктами. Поэтому, наверняка именно мыслями

руководствовались

тамошние

разработчики,

подарив Фоксу весьма корявую среду разработки, совершенно неудобную в пользовании и кучу багов в ядре. Да и обьектная

модель ее желает лучшего. Уж лучше бы не трогали вообще, от оконных разработок на Фоксе одни проблемы. Взять хотя бы

распространенный баг с закрытием окна – не всегда срабатывает крестик закрытия окна, а иногда просто вешает программу. И смех

и грех. Выходили из этой проблемы банально – ставили свою кнопку «Закрыть». Где же тут удобства?

АРХИВ

интерпретаторы

выполняющие Каждая

код

программы,

строчка

написанный программы

переводилась в код и сразу же исполнялась, потом интерпретатор повторял этот фокус на следующей строчке.

Эта возможность в FoxPro осталась до сих пор, правда FoxPro не совсем интерпретатор, а скоре псевдокомпилятор,

а

ядро

на

самом

деле

работает со скомпилированными байт-кодами (на P-CODE

Visual

Basiс

похоже),

но

это

нам

совершенно не важно. Главное, что все-таки источником

программиста команды,

является аз

именно

есьм,

посланной

даже

«писанина»

одна

интерпретатору,

строчка будет

рассматриваться им как целостная программа, и будет

успешно

выполнена.

переведена

в

псевдокод

и

Причем, строчка эта может быть представленная

такими типами как String и Pchar. Уже неплохо. Но как послать интерпретатору строку-команду? Вот мы и подошли к самому главному. Дело в том,

что

одна

из

магических

возможностей

FoxPro – есть инструкция, которая выполняет переданную ей строку-параметр как команду.

На Фоксе это называется макроподстановкой и звучит так:

StrCommand="Select * from table"&StrCommand

Где: StrCommand: String, говоря языком Вирта, строка содержащая команду.

При этом интерпретатору все равно, что там

будет находиться, если это правильная команда

** Комментарий автора.

такими

пошагово

он

ее

выполнит.

С

этим

примерно такую аналогию:

можно

провести

StrCommand:='Select * from Table'; Query.SQL.Add(StrCommand); Query.ExecSQL

«Ну и что такого?» – скажут многие. Чем круче

макроподстановка? А те, кто знают FoxPro на пять, ответят – макроподстановка позволяет не только

выполнять

ВСЕ

команды,

но

и

еще

возвращать результат, если в качестве команды поступило выражение. То есть:

СОДЕРЖАНИЕ

45


ПРО

№9 (декабрь) 2010

граммист

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO все таки пошли навстречу и снабдили СУБД возможностью

StrCommand="2+6*Sin(20)"

Опа!

return d && – вернет вычисленное выражение

Собственный

интерфейс

вот

то,

что

Стратегия Ну что ж, приступим к разработке стратегии.

Query.SQL.Add(s);

Нам нужно написать на FoxPro DLL с функциями,

Query.open

К тому же, как по мне, не этично создавать

отдельный курсор (курсор в FoxPro – это набор данных, полученный каким-либо образом) ради

одного значения. Можно конечно и так, но что в

которые

выражении

заложены

неизвестные провайдеру? команду

которые

бы

команды,

и

интерпретатором,

:=Query.Fields[0].AsFloat

Например,

раз,

пожелаем.

S:='select 2+6*Sin(20)';

если

сей

нужно. И там же можно навертеть все чего

А вот аналогия в SQL:

команды,

(на

полноценной) кода в COM Server в виде DLL.

STORE &StrCommand TO d

будет,

компиляции

замены

повстречаются в

в

ядре,

но

поле,

где

содержится имя файла расширения с TIF на JPG в таблице А1:

общались

напрямую

передавая

ему

возвращали

бы

с

строку

результат

выполнения этой команды. Для передачи строки

без возвращения результата напишем процедуру, ибо

может

понадобиться

выполнять

такие

команды как, скажем: Use или Replace (подобной вышеописанной, результат

или

из

тех,

что

не

генерируют

возвращают

курсоры).

Для

получения результата выполненного выражения

системой напишем функцию. Потом все это скомпилируем

как

DLL

с

COM

сервером

и

зарегистрировав на машине (командой Regsvr32 <Имя DLL> в консоли) вставим в Delphi через команду меню Project->Import type library, где

выберем эту DLL. После чего можно будет

REPLACE a1.fullname WITH

распоряжаться этими функциями, как методами

LEFT(a1.fullname,AT(".TIF",a1.fullname))+".JPG" all

Query подавится ею. Впрочем, для любителей

компонента.

классики есть менее эффективная команда –

Тактика

интерпретатором тет-а-тет, то команда будет

Начнем с написания библиотеки. Для этого

UPDATE.

Но,

если

поздороваться

так

с

выполнена немедля.

А значит, таким образом, можно легко взять старые

программы

и

построчно

(или

понадобится

Visual

Foxpro.

Я

делал

версии, но и более ранние тоже подходят.

на

8-й

прям

Запустим Foxpro и в меню File выберем пункт

SET PROCEDURE TO… после чего, пустив на

Project, и нажмем на кнопку New File. Нас

целиком программу из файла, указав его имя в

выполнение процедуру командой DO или, если

это функция просто выполнить ее) скармливать их интерпретатору напрямую обходя, или вообще не имея установленного провайдера.

по FoxPro. Смысл связи оказался простым: дело том,

Появилось

окошко

с

рисунок 1). Создадим новый класс, для чего, став и

его

наследование

(см.

рисунок

2).

Допустим, имя будет TFoxPro (назвать можно как угодно). Наследовать мы будем пользовательский

поле Based On выбираем Custom. В поле Store In

потом

можно

класса

применять в Delphi, поскольку Микросовтовцы

которые

FoxPro

Ок.

«чистый» класс, поскольку нам визуальные и

АРХИВ

на

TFoxPro.

описанием проекта – это шаблон компонента (см.

писать

компоненты,

что

будет

Появившееся окошко попросит нас написать имя

Первоначально пришлось почитать литературу в

попросят написать имя проекта. Имя, допустим,

на ветку Class Library, кликнем по кнопке New.

Вот эту идею я взял за основу

все

New. В появившемся окошке File Type выберем

с

легкостью

контейнерные классы никак не нужны, поэтому в

СОДЕРЖАНИЕ

46


ПРО

граммист

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

№9 (декабрь) 2010

Рис. 1. Шаблон компонента укажем путь куда сохранится класс. Жмем Ок.

Допустим, назовем его MyProc с видимостью

Теперь добавим в него методы. Тем кто знает,

метод MyFunc (см. рисунок 3). Если на экране

как в Delphi писать ActiveX, будет не сложно понять

следующие

действия,

поскольку

они

схожи. В главном меню Class выбираем New Method. Чтобы меню Class появилось, нужно стать в окно Class Designer созданного класса. В появившемся

окошке

создаем

ему

метод.

Public. Жмем Add. И так же добавим еще один есть окно Properties, то можно в нем увидеть как появляются новые методы. Если окошка этого нет, нужно его открыть либо с тулбара, либо контекстным меню по формочке класса (который

у нас называется tFoxPro в окне Class Designer) выбрать

элемент

Properties.

Добавив

методы,

Properties

найдем

впишем в них код. Сначала в MyProc, для

чего

в

окне

строчку с его названием и откроем ее, кликнув

дважды.

Открывшееся

окно

редактора всем своим видом пригласит нас

писать

займемся

программы Рис. 2. Создание нового класса

АРХИВ

(см.

программку, рисунок

будет

весьма

4).

чем

и

Текст

простой:

подобный тому, что приведен выше. Добавим

только

команду

описания

СОДЕРЖАНИЕ

47


ПРО

№9 (декабрь) 2010

граммист

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

типа String && далее, на всякий случай, дабы

задобрить интерпретатор,

обрезаем && ведущие и закрывающие пробелы. Можно и обойтись, && но лишняя предусмотрительность – не

помеха.

lcrun=ALLTRIM(lcrun) &lcrun && – И

Рис. 3. Добавляем метод классу

Здесь: && - означают комментарии (как «//» в

параметра, ибо нам же нужно в метод передавать

команду в виде строки, вот и опишем его как строка:

Делфи или Си), так что можно копипастить эти

строки полностью. «Всего-то?» – удивится кто-то. А

что

тут

Принимаемая команда.

LPARAMETERS lcrun as String

&& – Это указание, что метод примет

наконец Выполним команду из строки

параметр

Займемся

такого? строка

теперь

Все

будет

функцией:

проще

простого.

расценена

«…те

же

как

яйца,

только в профиль». Так же открываем ее код и

Рис. 4. Создаем наш проект

АРХИВ

СОДЕРЖАНИЕ

48


ПРО

граммист

№9 (декабрь) 2010

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

Рис. 5. Набор кода вписываем вышеприведенный пример, не забыв

build a DLL without OLE Public Class». Непонятно,

команда (см. рисунок 5):

сделать так, чтобы компилятор сам проверял

прикрутить параметр, в который будет передана

необходимость

Выберем

&& в переменную

выставим

Das Ist Alles – сохраним проект. Теперь дело за малым: скомпилировать библиотеку, но сначала класса

Multi-threaded все

птички

COM в

server

Options,

DLL

и

чтобы

перекомпилирование прошло над всеми фалами

потом возвращаем.

методы

если

кликаем по кнопке Build. В появившемся окне

команды-выражения

что

класса,

После перепрыгиваем в окно Project Manager и

STORE &lcrun TO mret && - Сохраняем результат выполнения

укажем,

публикации

компилируется COM Server (см. рисунок 6).

LPARAMETERS lcrun as String

RETURN mret && - которую

зачем создатели сделали эту опцию, могли бы

являются

OLE

(Recomile All Files). Если всплывут ошибки, мы их захотим

увидеть

(Display

errors)

и

пусть

перестраивает ID компонента (см. рисунок 7).

видимыми. Для чего в меню Class откроем окно

Жмем ОК. Итак, как говорил Слепой Пью: «Дело

Если этого не сделать, компилятор не впишет

увидеть,

Class Info. Здесь поставим галочку на OLE Public. класс в сервер заругавшись строчкой «Cannot

АРХИВ

сделано...». Заглянув в папку с проектом можно что

в

нем

лежит

библиотека

<tfoxpro.dll> (учитывая, что я все файлы называл

СОДЕРЖАНИЕ

49


ПРО

граммист

№9 (декабрь) 2010

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO Интеграция Вот и наступил второй этап. Своего провайлера мы написали. Теперь его нужно

зарегистрировать

рекомендую сделать это программой RegSVR32,

расположенной,

правило,

в

"C:\WINDOWS\system32\". нужно

как

папке

Далее

импортировать

библиотеку

типов, «превратив» ее в компонент Delphi и кинуть на форму, чтобы пользоваться им как родным. Приступим Поместив

DLL

каталог,

где

в

какой-нибудь

она

будет

жить,

зарегистрируем ее (можно даже в System32,

но

я

не

рекомендую

загаживать его). Если вы используете Total

Рис. 6. Свойства и публикация класса

Commander

или

подобные

проводники, то вам проще – стали на тот

файл

и

набрали

Энтер и Ок.

в

командной

RegSvr32

строке

TFoxPro.DLL.

На самом деле это можно сделать и в Delphi

при

импорте,

но

я

лично

сталкивался с непонятными для меня глюками,

«компонент»

регистрации

когда

проходит его

в

импорт

успешно,

реестре

в

а

нет.

Поэтому «чтоб уж наверняка не было ни

одного

дедовским

библиотека

упырька»

зарегим

правильно

сделана,

способом.

Если

сообщение об успешной регистрации вылезет на экран. Рис. 7. Входим в настройки

Кстати, если у вас нет regsvr32, не нужно

отчаиваться,

его

аналог

одинаковым именем и сложил в одну папку).

можно написать и на Delphi. Эта возможность

библиотеку

библиотеках функций DLLRegisterServer, которая

Компилятор также любезно предоставил нам типов

<tfoxpro.tlb>.

Остальные

файлы принадлежат самому проекту FoxPro.

Например: VCX – это тот самый класс, VCT – описание

его

методов

(можно

посмотреть

в

блокноте), тот код, что мы написали. Остальные файлы: версия проекта и описания проектов.

АРХИВ

имеется

благодаря

наличию

в

такого

рода

регистрирует в реестре Windows свои классы. И соответственно

DLLUnregisterServer,

которая

вызывает.

регистрации

отмены

отменяет регистрацию. Эти функции regsvr32 и достаточно библы.

Для

просто

вызвать

или

эти

ее

функции

из

СОДЕРЖАНИЕ

50


ПРО

БЛИЗКИЕ ТРЕТЬЕГО С VISUAL FOXPRO ДЕЛАЕМ КОНТАКТЫ ДИНАМИЧЕСКИЕ ТЕНИВИДА НА OPENGL. ЧАСТЬ 1

№9 (декабрь) 2010

граммист

В Delphi это выглядит так:

var m,k:integer;

function DllRegisterServer: HResult; stdcall;

begin

external

// Откроем таблицу командой USE

'TFoxPro.dll';

foxpro.MyProc('USE"'+

...

ExtractFilePath(paramstr(0))+'a1.dbf"');

begin

// Получим количество записей и выставим количество

DllRegisterServer;

// строк в таблице

end;

StringGrid1.RowCount:=foxpro.MyFunc('reccount()')+1;

...

StringGrid1.ColCount:=2;

Соответственно

предполагается,

программа-регистратор реестр

библиотеку

с

лежит

классом

что

возле мы

эта

DLL.

// Для красоты можно масштабировать размер

В

// колонки по максимально

поселили,

m:=0;

теперь получим компонентик. Для этого откроем

// Пока не конец текущей таблицы

окно Import Type Library из меню Project. По

while foxpro.MyFunc('.NOT.

крайней мере, так делается в Delphi 6. Если у вас

// поле FILENAME обрезая ненужные ведущие и замыкающие

возможность импорта библиотеки. Предположим

// пробелы функцией ALLTRIM

нашли. Найдем в списке нашу библиотеку и package.

ее

Выберите

класс

сами

в

ему

какой-нибудь

название

EOF()') do begin

// в соответствующую ячейку записываем из текущей записи

другая версия, то нужно найти соответствующую проинсталлируем

длинной строке

StringGrid1.Cells[1,k]:=

(см.

foxpro.MyFunc('alltrim(filename)');

рисунок 8). После всего, если вы правильно

// Получаем ее порядковый номер

появиться на соответствующей вкладке палитры.

// Переходим на следующую запись

проинсталлировали

пакет,

компонент

должен

StringGrid1.Cells[0,k]:=foxpro.MyFunc('recno()');

Теперь можно им пользоваться.

foxpro.MyProc('SKIP'); // Маштабируем колонку авторазмером

Применение

if

StringGrid1.Canvas.TextWidth(StringGrid1.Cells[1,k])>m

Для начала создадим таблицу в FoxPro. Да не

then m:=StringGrid1.Canvas.TextWidth(

файлов в строковом поле. Назовем таблицу «а1».

StringGrid1.ColWidths[1]:=m;

важно, что там будет. Предположим, список Допустим,

в

ней

будет

прописаны пути к файлам.

поле

Filename,

StringGrid1.Cells[1,k]);

где

end; end;

Кинем на форму наш компонент. Дадим ему имя

А

этого

не оставлять мусора.

FoxPro. Теперь мы хотим отобразить содержимое поля

в

таблице.

«Долой

тяжелые

и

неповоротливые DB компоненты» – скажу я и

в

событии

OnClose()

формы

закроем

все

курсоры командой foxpro.MyProc(‘close all’), дабы

растяну на форме обычный StringGrid. Его и

Не очень много кода****. Кто-то скажет «А зачем

нужно проделать следующее:

написав ни одной строчки кода?». Можно, но

будем • • •

наполнять

открыть базу***; получить

данными.

количество

RECCOUNT();

Программно

записей

нам

функцией

Все, приступаем. Предположим код этот будет

выполняться при создании формы. А можно его

АРХИВ

это,

если

можно

применить

DBGrid

не

работать с DB компонентами в Delphi – сущий

в цикле вписать записи в таблицу.

описать*** в отдельную функцию:

все

мазохизм. К тому же, в качестве еще одного довода, приведу еще один аргумент... Растяните *** Комментарий автора.

Для этого в FoxPro используется команда USE. Если нужно получить не все записи можно следующей командой послать что-то

типа SELECT * FROM… WHERE <Условие отбора> ибо FoxPro понимает классический SQL...

СОДЕРЖАНИЕ

51


ПРО

№9 (декабрь) 2010

граммист

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO goAlwaysShowEditor,

чтобы

режима редактирования.

не

выходить

из

Писать сам код можно в событии OnSetEditText. Тактика будет такова: •

становимся передается важно,

на

в

чтобы

запись,

индекс

OnSetEditText количество

которой

(здесь

строк

в

очень гриде

совпадало с количеством строк в курсоре •

базы);

заменяем значение в поле.

Все это делается примерно так: procedure

TForm1.StringGrid1SetEditText(Sender: TObject;

ACol, ARow: Integer; const Value: String); begin // Становимся на

запись

foxpro.MyProc('GO '+inttostr(aRow)); // Заменяем значение ее поля новым значением foxpro.MyProc('REPLACE

fullname WITH "'+value+'"');

end;

Как видим, тоже ничего мудренного. И это притом, что DBGrid в паре с Query так просто не позволит

провернуть

такую

операцию

обязательно повыбрыкивается чем-нибудь вроде

«DataSet not in edit or insert mode». FoxPro такого не скажет, потому как запись-то открыта по

Рис. 8. Интеграция библиотеки на

чистой

форме

DBGrid

и

ADOQuery.

Скомпилируйте и посмотрите размер файла. У

меня он равен 758 с копейками килобайт. А

теперь скомпильте проект с TFoxPro. 453 с

умолчанию и для чтения и для записи, если

конечно на этой записи не стоит какой-нибудь другой

клиент

при

многопользовательской

работе. Тогда запись блокируется.

копейками. И это при том, что я в первом

Но речь сейчас не о многопользовательском

Если нет, попробуйте написать тяжеловесный

это правило действует в любых курсорах, даже

проекте ни строчки кода не написал. Убедил? проект с кучей DB компонентов и посмотрите,

сеансе. Плюс к этому (опять я похвалю FoxPro),

что разница будет в десятки раз*****.

***** Комментарий автора.

Ну, да ладно. Продолжим. Теперь наша задача –

конструкторской документации. Не PDM, но все же. Применил

редактирование. Редактировать будем прямо в Гриде, благо тот позволяет это сделать, выставив

в свойстве Options флажок goEditing и к нему **** Комментарий автора.

Обратите внимание. Я легко воспользовался стандартным набором

функций FoxPro и выражениями. Аналог Alltrim конечно и в Delphi есть, но почему бы не напрячь саму СУБД?

АРХИВ

Когда-то

я

писал

весьма

сильный

проект

по

обработке

соответственно BDE. Когда база разрослась, а лежала она на расшаренной папке, программа заметно начала тормозить. Даже оптимизация толком не дала прироста скорости. После того как я

перешел на FoxPro таким способом программа опять стала летать. Я практически не замечал тормозов. Плюс ко всему эту программу поставили на убитый горем старый компьютер, который еще

«Ленина

видел

живым».

Вот

тогда

оператор-расчетчик

с

удивлением сказал, что новая версия доставляет удовольствие от работы, и спросил: «…что я сделал?».

СОДЕРЖАНИЕ

52


ПРО

тех,

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

№9 (декабрь) 2010

граммист

которые

были

получены

классическими

SELECT * FROM… или подобными. TQuery без шаманских танцев с бубном над ним подавится такими запросами. Как ни странно, это касается

очень многих СУБД с которыми взаимодействует

этот компонент, не потому что это плохие СУБД,

FUNCTION ReplExtension LPARAMETERS s as String && Найдем

&& Тут же можно написать тучу кода чего-то рассчитывающего replace filename WITH

а потому что сам компонент не рассчитан на такую гибкость. Впрочем, и с ним можно решить такую

задачу,

Мигрени точно.

но

чего

это

будет

стоить…

А теперь представим, что проект ведет человек хорошо

знающий

Delphi.

основную

FoxPro,

Естественно работу

с

но

ему

БД

хуже

знающий

выгоднее

написать

LEFT(filename,RAT(".",filename)-

1)+"."+s all && Вернем True RETURN .t. ENDFUNC FUNCTION FindName LPARAMETERS s as String

будет

&& Поищем введенную

командами

подстроку в записях и станем на нее,

если нашли

FoxPro, а на Delphi сделать только интерфейс и

LOCATE for AT(s,filename)<>0

выполнение таких команд. Есть два выхода из этой ситуации:

&&

1. Написать или взять командные файлы FoxPro

ENDFUNC

(.PRG)

расширение и заменим его на новое во всех записях

вернем номер найденной строки

RETURN RECNO()

и просто в Delphi считывая построчно

скармливать их интерпретатору.

Теперь

файлы, которые содержат код, самостоятельно их

результате компиляции FXP псевдокод ложем в

2. FoxPro имеет возможность выполнять целые читая.

Первый

способ

неплох,

но

только

в

случае

ручками

вводил

линейной программы, без процедур и функций, так

как,

если

бы

оператор

команды в консоль FoxPro. К тому же механизм выражений возьмемся

теряет

за

свою

второй

силу.

способ

Поэтому –

мы

пакетное

выполнение программ и модулей. Для этого в

FoxPro предусмотрена команда SET PROCEDURE

TO, которая действует примерно по аналогии с Include

некоторых

отдаленно

языков,

напоминает

ну

uses

в

или,

скажем,

паскале.

В

параметрах этой инструкции указывается либо линейная программа, либо модуль с процедурами или функциями.

Выглядит это так Для

начала

напишем

простенький

модуль

с

блокнот, либо можно писать в среде FoxPro.

Допустим, в нем будет две функции. Одна будет

глобально менять разрешения файлов в записи, а

другая просто искать введенную строку. Вот как

АРХИВ

этот

скомпилируем

файлик

его******.

в

FoxPro

Полученный

и в

папку с программой. В Delphi пишем следующий код. В OnCreate() инициализируем модуль: { Ладно уж. Пусть скомпилирует сам, чего напрягаться } foxpro.aproc('COMPILE "'+ExtractFilePath(paramstr(0))+'File1.prg"'); { Скомпилиный модуль инициализируем } foxpro.MyProc('set

procedure to

"'+ExtractFilePath(paramstr(0))+'file1"');

Предполагается, что он называется <File1.prg>. На самом-же деле выполняться будет лежащий рядом

кнопки.

FXP.

Теперь

Одна

поместим

будет

на

скармливать

ReplExtension, другая FindName.

форму

две

функцию

Код первой кнопки:

расширением PRG. Для этого подойдет обычный

он будет выглядеть:

откроем

var s:string; begin s:=InputBox('Введите новое разширение','',''); foxpro.MyFunc('ReplExtension("'+s+'")'); FillGrid(StringGrid1); end;

Код второй:

СОДЕРЖАНИЕ

53


ПРО

БЛИЗКИЕ КОНТАКТЫ ТРЕТЬЕГО ВИДА С VISUAL FOXPRO

№9 (декабрь) 2010

граммист

procedure

TForm1.Button1Click(Sender: TObject);

****** Комментарий автора. Увы,

var s:string; begin

версии

FoxPro

обязательно

нуждаются

в

разработчикам – они оставили команду COMPILE. Так что можно

s:=InputBox('Введите что искать','','');

не компилировать ничего, но перед вызовом SET PROCEDURE TO выполнить COMPILE.

StringGrid1.Row:=foxpro.MyFunc('findname("'+s+'")'); caption:=IntToStr(StringGrid1.Row);

В общем, главное, что нам предоставили выбор:

StringGrid1.SetFocus;

либо

end;

В первом случае – возвращаемое значение мы не обрабатываем, во втором случае – присваиваем его

последние

псевдокомпиляции – это минус. Впрочем нужно отдать должное

свойству

Грида,

отвечающему

за

позиционирование курсора в Гриде. Опять таки ничего сложного, зато весь управляющий код мы

править

бал

заученyыми

до

дыр

возможностям, либо писать креативы, что тоже

не так уж и плохо. Самое главное – учесть

требования задачи, ибо может оказаться, что креатив даст большую выгоду, благодаря своей неформальности.

спихнули на совесть FoxPro. А ведь это только пример…

Мне

бухгалтерии,

довелось

в

частности

повидать –

расчеты

в

калькулирование

себестоимости, где модули такие насчитывали около

100

строк.

Там

очень

много

деталей

учитывалось. Удобная схема – не нужно менять EXE-шник.

TStoredProc.

По аналогии с этим есть компонент Но

меньше.

его

возможностей

гораздо

Послевкусие Вот так вот, други мои. Против лома – нет приема, если нет другого лома. Я не настаиваю на том, что FoxPro круче всех и вся, но умелое применение

возможностей

этой

СУБД

извне

позволит достичь весьма эффектных результатов

достаточно простыми путями. Кто-то скажет: «Да ну… Это нужно ставить на каждую машину

FoxPro полностью». Необязательно. Например, достаточно поставить ее на сервер, а в Delphi в свойстве указать

компонента

сервер.

Плюс

на

RemoteMachineName сервере

правильно

настроить достут к нему удаленно. Это обычная

практика для хорошего администратора. Или есть еще возможность (если ее уже не отменили

разработчики), просто проинсталлировать одно ядро (это около 10 DLL’ок) на машину. Подобное

мне показывал один фан этой СУБД, и ничего – заработало нормально. Опять таки повторюсь – данная статья описывает однопользовательскую систему.

покрупнее

В

многопользовательских

пошаманить,

например

нужно

запретить

клиенту вызовы компиляции, чтобы не повесить сервер.

АРХИВ

СОДЕРЖАНИЕ

54


ПРО

ЧЕГО ТОЛЬКО НЕ БЫВАЕТ

№9 (декабрь) 2010

граммист

Q: Как проверить, существует ли таблица в БД?

со стремянками и инструментами. Наблюдая за

"Таблица существовала...";}

агрегата, способного автоматизировать процесс.

A: if(mysql_query("DROP TABLE `таблица`")){echo

Агрегата так не дождался, зато последней из

Кабелеукладчик

Однажды мне было необходимо срочно проложить четыре

десятка

проводов

расстояние в сто метров.

процессом разгрузки, я с нетерпением ждал чудо-

витой

пары

на

микроавтобуса была выгружена некрупная такса. Не

успел

я

для

трех-

В

моих

костюмчик вдоль

админских плеч решение в

сроки

приемлемые

является

сильным,

принялся

привлечения

сторонних

скрипя

и

сердцем,

сился.

Я

тот,

согла-

общей

сбруя

фонариком

и

место. ное

из

хватало

длинных

и

была

ли

прокладки и

просто

же

на

в

трудно-

участках

фантас-

тической. Такса резво

задание. поняли

метров

пятьдесят.

доступных

что

провод.

мощности

конкурентов! На всякий

Ответили,

к

шустро

собой

живал,

дешевле, чем любой из

поняли

его

Надрессирован-

Скорость

они

путем

труднодоступное

один день, причем втрое

правильно

кабеля

Потолок собаку выдер-

они выполнят всего за

уточнил,

шлейка.

животное

за

Ребята

перезвонил

на

или свет фонаря, волоча

утверждали, что работу

случай

для

мчалось на звук голоса

предложений

массы.

ручкой

переноски,

в

разработал

выделялось

таксе

шлейке и запуска таксы

ждать.

сильно

спины

прикрепления

разным конторам и стал

из

с

осуществлялась

техзадание, разослал по

Одно

к

специальный

Прокладка

терзать шефа на предмет монтажников,

кабеле-

голову со светодиодным

непо-

я

комплекте

шел

единственных в конторе задачи

появления

укладчик.

метровой высоте. Поняв, что

поводу

таинственный

проходила над навесным на

по

животного, как мне объяснили, что это и есть

Большая часть дистанции потолком

удивиться

носилась в одну сторону

по верху, а обратно – по

прекрасно, а скорость и дешевизна объясняется

коридору, пугая женскую часть персонала.

был заинтригован – с кабелеукладчиками имел

Даже ЧП в виде выпавшей панельки потолка не

образом данный девайс можно приспособить к

сыграл

тем, что в работе используется кабелеукладчик. Я дело в армии и решительно не представлял, каким прокладке витой пары под фальшпотолком. В

назначенный день прибыли всего два монтажника

ЮМОР

повлияло на ее настроение: протягиваемый провод роль

страховочного

троса,

и

собачка

плавно опустилась на пол. Ребята сказали, что к таким ситуациям «кабелеукладчик» приучен.

СОДЕРЖАНИЕ

55


ПРО

граммист

ЧЕГО ТОЛЬКО НЕ БЫВАЕТ

№9 (декабрь) 2010

Смех смехом, но такса на полном серьезе стояла у ребят

на

балансе

фирмы

мне

были

продемонстрированы документы. Работу дружный

коллектив действительно выполнил менее, чем за день, причем без предварительного разматывания

кабеля и, соответственно, без обрезков. Правда, работа нашей конторы полностью встала – все население

сбежалось

посмотреть

«кабелеукладчика». Оказывается,

многие

за

известные

работой

пословицы

можно перевести на «технический» язык: •

Дуалистический

принцип

сельскохозяйственных гидроповерхности

Бинарный

орудий

(ВИЛАМИ

ПИСАНО). •

использования ПО

характер

индивидуума,

на

ВОДЕ

высказываний

утратившего

социальную

активность (БАБУШКА НАДВОЕ СКАЗАЛА). •

Проблемы

транспортировки

жидкостей

в

сосудах с переменной структурой плотности (НОСИТЬ ВОДУ В РЕШЕТЕ).

Оптимизация средства

динамики

передвижения,

устранением

транспортной

изначально

единицы

КОБЫЛЕ ЛЕГЧЕ). •

работы

баг...

Нашими

учеными

разработан

отбирающий пробы грунта у американцев.

луноход,

xxx: Я нашел, что тормозило в вашей рабочей проге.

yyy: Ну?

xxx: error-log.txt в 27 гигабайт.

yyy: И зачем он? Он как-то задействован? xxx: Неа. Он даже в отчеты не входил.

yyy: Отправь файл разработчикам, пусть изучают. И ты, root? Трудна IT-ков работа,

Мы пашем даже по субботам, И в коридоре нашем ночью,

Коллегу в тапках встретишь точно. Я к вам пишу – чего же боле?

На чем, на Жаве? – На КОБОЛе! Кулер тоже вертолет. Только маленький еще...

тяглового

Можно ли сообщение «программа выполнила

деструктивной

разработчику» считать официальным вызовом в

сопряженная

(БАБА

С

ВОЗУ

с

Проблемы повышения мелкодисперсионности оксида двухатомного водорода механическим

недопустимую

операцию

обратитесь

к

США?

Насколько проще была бы жизнь, если бы она была в исходниках.

путем (ТОЛОЧЬ ВОДУ В СТУПЕ).

С точки зрения программиста пользователь –

Синдром

символов в ответ на команду READ.

отказа

опирающийся

на

от

отсутствие

легитимизации, возможностей

это периферийное устройство, вводящее набор

быстрой идентификации личности (Я – НЕ Я, И

– Что такое пошаговая стратегия?

001, 010, 011, 100, 101 вышел зайчик погулять.

Я повторяю свой вопрос: «Reboot?!»

ЛОШАДЬ НЕ МОЯ). •

Если глюк оказался вдруг и не друг, и не враг, а

Долгое время считалось, что бит неделим. Но советские ученые...

ЮМОР

– Это «Need for Speed III» на 486-ом компьютере.

Одни источники утверждают, что поскольку в

китайском языке 5700 знаков, то клавиатуры там очень многорядные*, вот такие:

СОДЕРЖАНИЕ

56


ПРО

граммист

ЧЕГО ТОЛЬКО НЕ БЫВАЕТ

№9 (декабрь) 2010

Мастер открыл распределительный шкаф, достал мобильник и позвонил бабке. Телефон зазвонил не сразу, а только после того, как собака заскулила. Покопавшись в проводах мастер выяснил что:

Грамотным

элементарном

заземлитель плохо присоединен к громоотводу,

Видимо верхняя клава для китайцев с высшим

человек,

освоивший

уровне

собака привязана к заземлению телефонного

может

считаться

на

1500

знаков...

образованием.

Разговор диспетчера аэропорта Франкфурта и пилота рейса Аэрофлот (Москва-Франкфурт):

провода железными цепью и ошейником; разрывая, тем самым, цепь; собака

звонке;

получала

90

вольт

скулить и писалась;

увлажненная земля замыкала цепь и телефон звонил.

Не сняв с себя статический заряд

Борт 4554: Вас понял! Снижаюсь!

Сначала наберись терпенья,

Диспетчер: Борт 4554! Полоса свободна! Можете садиться!

Борт 4554: Понял вас! Сажусь... промахивается мимо полосы и снова набирает высоту.

Диспетчер: Борт 4554! Вы что, никогда раньше не были во Франкфурте?

Борт 4554: Был! В 1944-ом, но тогда я не садился! Перевод гугла: «ехал путин на желтой калине = Putin went on a yellow Mazda» Деревенская

бабка

мастера. Мастер приходит:

вызвала

телефонного

– Что случилось?

– Мне говорят, что я очень долго не подхожу к телефону, не все дожидаются и бросают трубку

входящем

после нескольких ударов тока собака начинала

Диспетчер: Борт 4554. Занять корридор 8 и спуститься на 1000 метров!

при

Не смей касаться платы, гад! Потрогай шину заземленья, Чтоб никому не навредить

И микросхемы не «пробить». Но сняв статический заряд

Касайся смело платы, брат!

Запомни, в трении - рожденье

До тыщи вольт доходит напряженье. Товарищ, лучше средства нет Чем заземляющий браслет. Его на шею ты не одевай,

Химсредство «ЛАНУ» лучше применяй Как не был бы высок потенциал,

Химсредство «ЛАНА» его валит наповал Чтоб тыщу вольт свести к нулю Браслет и «ЛАНУ» я куплю!

думая, что меня нет. Но я к телефону сразу

Как-то Ландау с Капицей сидели на даче у

перед самым звонком. Она ясновидящая?

вопрос:

подхожу! Еще почему-то собака скулит всегда

* Справка. При

всем

«...если

к

хвосту

кошки

привязать

консервные банки на веревке, с какой скоростью

должна бежать кошка, чтобы банки не гремели?» кажущемся

многообразии,

китайские

иероглифы

в

современном виде представляют собой комбинации большего или

меньшего числа cтрого определенных графических единиц ...из 24 графических элементов состоят все без исключения китайские иероглифы в их современном начертании / Т.П.Задоенко Основы китайского языка.

ЮМОР

одного из них. И Ландау задал Капице такой

Капица тут же погрузился в какие-то расчеты, исписал целый лист формулами...

В результате Ландау ошарашил его, сказав, что кошка должна просто сидеть (ведь покой – это одна из форм движения).

СОДЕРЖАНИЕ

57


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.