Последние записи
- Windows 10 сменить администратора
- Рандомное слайдшоу
- Событие для произвольной области внутри TImage
- Удаление папки с файлами
- Распечатка файла
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
23rd
Сен
Программы для самых маленьких
Компьютер в настоящее время для большинства уже перестал быть чем-то диковинным. Он используется и для развлечений, и для работы, а среди его пользователей школьники и студенты, любители и профессионалы, люди разных возрастов и профессий. Идея использовать компьютер, а точнее компьютерные программы для обучения и развития, естественно, родилась и реализуется уже давно. И вот, видя, с каким интересом мой маленький внук (а было ему тогда всего лишь 3,5 годика) наблюдает, как я работаю за компьютером, и как он старается тоже подвигать мышкой или понажимать клавиши, я понял: пора использовать его интерес для развития. Первым делом, конечно, поискал в Интернете программы, обучающие ребенка счету, рисованию и раскраске простеньких рисунков, знакомству с азбукой. Увы, результат оказался плачевным. Большинство программ, найденных мной в Интернете, или платные, или настолько сложные для ребенка, что и взрослому не всегда удается разобраться, как ею пользоваться. Так и появилась идея самому создать развивающие программы для маленьких с учетом интересов и способностей самого ребенка. Вскоре появились красочные программы “Раскраска” и “Азбука”, очень понравившиеся малышу. Яркие рисунки с любимыми игрушками и персонажами сказок и мультфильмов, простота управления программой – все это привлекает ребенка, прививая ему первые навыки координации движений, правильного выбора действий.
Владимир Дегтярь
by DeKot degvv@mail.ru
Целью данной статьи является помощь начинающим программистам в создании полноценных программ для маленьких детей. Вы можете просто скачать из приложения к журналу файлы *.exe (не забыв про ресурсы программы – папку Image с рисунками) и предложить поиграть своим маленьким пользователям.
В данной статье рассмотрим создание двух небольших программ, которые наверняка понравятся малышам. Думаю, что тем, кто хоть немного знаком с компьютером (тем более с программированием), не составит большого труда заменить или добавить рисунки, более подходящие для конкретного ребенка.
Программа “Раскраска”
Программа* представляет из себя, в прямом смысле, обычную раскраску, где ребенок выбирает понравившийся рисунок и раскрашивает его выбранными им же цветами.
* Комментарий автора.
Сразу отмечу, что данная программа обсуждалась на форуме http://programmersforum.ru/showthread.php?t=80497&highlight=%D0%E0%F1%EA%F0%E0%F1%EA%E0. Форумчанин raxp устранил некоторые ошибки и добавил ряд красивых рисунков, а mutabor заменил стандартный курсор на симпатичную кисточку.
Прежде чем приступить к самому процессу программирования, определимся со структурой программы. А именно, что же мы хотим получить от программы:
- Все действия будем производить на форме, точнее на канве формы. Следовательно, будем использовать в программе свойства и методы работы с канвой формы – вывод рисунков на форму (методы Draw, StretchDraw), заливку области канвы цветом (свойства кисти Brush.Color, метод заливки FloodFill и т. п.).
- Нам понадобятся рисунки для раскраски. При этом каждый рисунок будет иметь два вида. Один – это полноцветный рисунок, используемый для выбора и для подсказки (чтобы ребенок видел, каким цветом закрашивать фрагменты рисунка). Второй – непосредственно сам выбранный рисунок для раскраски в виде контуров фрагментов рисунка. Все контуры должны образовывать замкнутую область.
- К выбору рисунков следует подходить индивидуально для каждого ребенка. Кому-то нравятся машинки, самолеты, кораблики, кому-то – персонажи сказок и мультфильмов. Самым маленьким вполне достаточно простейших рисунков – солнышка, шарика, звездочки и т. п. Множество рисунков можно найти в Интернете. Это и готовые рисунки для раскрасок, и просто красочные картинки с различными персонажами.
- Еще нам потребуется набор палитры цветов. Естественно, что применение, скажем, стандартного компонента выбора палитры цветов вряд ли будет интересно для ребенка. Куда привлекательней, если он будет выбирать краску из разноцветных ведерочек.
Все действия в программе производим при помощи мыши – курсором, а затем кнопкой мыши выбираем или меняем рисунок, цвет заливки, закрашиваемую область рисунка. Вместо стандартного системного курсора будем использовать самодельный в виде кисточки.
* Комментарий автора.
Казалось бы, детской ручке тяжело манипулировать мышкой (даже если подобрать мышку самых маленьких размеров). Однако мой внук быстро сообразил, что удобно передвигать мышку и управлять курсором одной рукой, а второй нажимать кнопку мыши в нужном месте.
Вот, в принципе, и все основные пункты структуры программы. Итак, начнем постепенно создавать саму программу…
Предварительно следует подобрать рисунки для раскраски. Для получения из цветного рисунка контурного для раскрашивания можно применить простой способ. Откройте цветной рисунок в графическом редакторе Paint, а затем сохраните его как черно-белый рисунок. При необходимости можно залить области рисунка белым цветом и подправить контурные линии, чтобы получить замкнутые области. Все рисунки храним в папке Image в файлах формата bmp, которую расположим в папке с проектом. Для выбора рисунка выводим на форму одновременно 12 рисунков. При смене рисунков выводим следующую группу из 12 рисунков. При этом совсем необязательно, чтобы размеры рисунков были одинаковыми. При выводе рисунков на форму будем подгонять размер рисунка до необходимого. Файлам цветных рисунков, для удобства обработки в коде программы, присвоим цифровые имена. Для первой группы цветных рисунков – 1.bmp… 12.bmp, для второй – 21.bmp… 32.bmp, для следующей – 41.bmp… 52.bmp и т. д.
Файлы черно-белых рисунков для раскрашивания соответственно имеют имена р1.bmp… р12.bmp, р21.bmp… р32.bmp, р41.bmp… р52.bmp. Здесь же находятся еще два вспомогательных файла – рисунок пока пустого ведерка для краски col.bmp и изображение курсора в виде кисточки brush.bmp.
Рис. 1. Окно программы “Раскраска”
Окно программы состоит из трех частей (см. рисунок 1):
- Область выбора рисунка. Здесь расположены 12 цветных рисунков (размером 100х100 пикселей) для выбора и кнопка смены рисунков (в виде зеленого треугольника).
- Область выбора цвета – 15 разноцветных ведерок с красками.
- Область выбранного рисунка для раскраски. Здесь выводится выбранный рисунок (размером 600х600 пикселей).
Определимся, какие процедуры нам понадобятся для реализации программы. Так как все манипуляции в программе осуществляются при помощи мыши, будем использовать стандартные обработчики FormMouseDown() и FormMouseMove(), а также процедуру обработчика событий FormClick(). Вывод всех рисунков, а также курсора в виде кисточки будем производить в стандартных процедурах для окна формы FormShow() и FormPaint(). Еще две стандартные процедуры: FormCreate() используется для инициализации приложения после запуска, SetBrushColor – для окрашивания кисточки-курсора в выбранный цвет.
Две процедуры мы создадим сами. Одна из них – процедура выбора рисунка SelPicture для считывания цветных рисунков из файлов папки Image. Данная процедура вызывается при запуске (инициализации) приложения и каждый раз при смене рисунков выбора (когда нажимается треугольная кнопка смены рисунков). Вторая – процедура выбора области окна программы SelRegion. В зависимости от того, в какой области окна мы нажмем кнопку мыши, происходит одно из четырех событий:
- Выбор рисунка для закрашивания.
- Смена блока из 12 рисунков для выбора.
- Выбор цвета для закрашивания.
- Сама процедура закрашивания фрагментов выбранного рисунка.
В качестве параметра в процедуру SelRegion при нажатии кнопки мыши передаются координаты курсора мыши. Определимся с необходимыми нам переменными…
Так как все необходимые рисунки находятся в виде файлов, то будем по необходимости загружать их в объекты типа TbitMap: BufCol – изображения ведерка с краской, MyBrush – курсор-кисточка, Buffer – буфер для загрузки всех изображений, кроме курсора, и BufWin – буфер окна программы, из которого все изображения выводятся на форму.
Значения цветов будем хранить в одномерном массиве mas_col. Также нам понадобятся координаты курсора в момент нажатия кнопки мыши (xm и ym) и еще одна переменная типа byte – page. По ней будем определять имена файлов цветных рисунков при смене блоков рисунков (по 12 шт.). Все это переменные глобального типа (см. код ниже).
Form1: TForm1;
BufCol: TBitMap; // буфер загрузки ведерка с краской
MyBrush: TBitmap; // буфер загрузки курсора-кисточки
Buffer: TBitmap; // буфер загрузки всех компонентов, кроме кисточки
BufWin: TBitmap; // общий буфер вывода окна программы на форму
xm,ym: integer; // координаты курсора мыши
mas_col: array
[0..14] of integer; // массив палитры цветов
page: byte; // страница блока из 12 рисунков
Необходимые локальные переменные будем рассматривать по ходу описания кода приложения. Сначала изучим процедуры выборов рисунка и области окна приложения.
1. Выбор рисунков SelPicture
var i: byte; // переменная цикла
BufPic: TBitMap; // буфер загрузки цветных рисунков
x,y: integer; // координаты рисунков на канве буфера
begin
BufPic:=TBitmap.
Create; // создаем буфер
x:= 10; y:= 20; // координаты первого из 12 рисунков
for i:= 1 to 12 do // цикл загрузки рисунков
begin
BufPic.LoadFromFile(
‘Image\’ + IntToStr(i+page) + ‘.bmp’);
Buffer.Canvas.StretchDraw(bounds(x,y,100,100),BufPic); // вывод на канву Buffer
x:= x + 105;
if x > 115
then begin x:= 10; y:= y + 105; end;
end;
BufPic.Free; // освобождаем память
end;
В буфер BufPic типа TBitMap в цикле загружаем из файлов 12 цветных рисунков и помещаем на канву основного буфера Buffer, приводя к размеру 100х100 пикселей каждый. Имя файла определяется значением переменной цикла и значением страницы блоков из 12 рисунков: (i + page).bmp. Значение переменной page при запуске приложения равно нулю. При нажатии кнопки смены рисунков значение page увеличивается на 20 и при значениях >40 опять принимает значение, равное 0 (организовано в процедуре выбора области окна приложения).
2. Выбор области окна приложения
Процедура SelRegion вызывается по событию OnClick на форме, если мы нажимаем кнопку мыши в области выбора рисунка или в области выбора цвета (см. Рис. 1). В зависимости от координат курсора в момент нажатия кнопки мыши происходит следующее:
- “Клик” по кнопке выбора рисунков – изменяется значение переменной page ( 0 – 20 – 40 – 0 – ) и вызывается процедура SelPicture для загрузки других 12 рисунков;
- “Клик” по одному из цветных рисунков – определяется имя файла рисунка для раскраски по локальной переменной num, загружаем файл в буфер рисунка BufPic, а затем переносим в основной буфер Buffer (размер рисунка 600х600 пикселей) в область раскраски.
- “Клик” по любому из цветных ведерок – происходит выбор цвета, и цвет передается на канву основного буфера Buffer и на канву формы.
Теперь рассмотрим работу программы. При запуске приложения в процедуре FormCreate происходит инициализация:
- создаются объекты типа TBitMap для загрузки графических изображений;
- рисунки ведерка и курсора-кисточки загружаются из файлов в соответствующие буферы BufCol и MyBrush;
- заполняем массив mas_col значениями цветов.
В процедуре FormShow() присваиваются атрибуты основным буферам Buffer и BufWin – размеры, равные размерам клиентской области формы, и цвет канвы. Здесь же выводим на канву буфера Buffer 15 цветных ведерок для выбора цвета, цветные рисунки выбора, затем рисуем кнопку смены рисунков и прямоугольник области рисунка для раскрашивания.
В процедуре FormPaint() считываем координаты курсора (GetCursorPos(P: TPoint)) в пределах клиентской области формы, содержимое буфера Buffer копируем в буфер окна BufWin и в него же добавляем изображение курсора-кисточки. Затем содержимое BufWin выводим на форму. Далее управление программой осуществляет пользователь с помощью мыши. При перемещении мыши обрабатывается событие FormMouseMove(), в буфер окна BufWin копируется содержание основного буфера Buffer и накладывается новое положение курсора-кисточки, а затем все это выводится на форму.
При нажатии кнопки мыши вызываются два обработчика события – FormMouseDown(), в котором переменным xm и ym присваиваются значения координат курсора, и FormClick(), в котором, если курсор находится в области окна для раскрашивания рисунка, происходит заливка замкнутой области, где находится курсор, выбранным ранее цветом (метод FloodFill). При нахождении курсора в любой другой области окна и нажатии кнопки мыши вызывается процедура SelRegion, работу которой мы уже рассмотрели выше. При этом координаты мыши передаются в процедуру SelRegion (xm,ym) в качестве параметра.
И последняя процедура SetBrushColor(C: Tcolor) устанавливает для курсора-кисточки выбранный цвет. Более подробно весь код приложения можно посмотреть в приложении в файле <Unit1.pas>, который содержит подробные комментарии кода***.
* Комментарий автора.
Считаю, что нет необходимости добавлять в программу какие-либо “красивости” (разве, что добавить звуковое оформление), так как маленькому ребенку в первую очередь интересны предложенные красочные рисунки и простота управления программой.
Программа “Азбука”
Данная программа знакомит ребенка с буквами алфавита, помогая быстрее их запоминать и составлять простые слова. Чтобы понять смысл программы, рассмотрим окно приложения (см. Рис. 2):
Рис. 2. Окно программы “Азбука”
Оно разбито на четыре части:
- Область выбора рисунка (1) – здесь выводятся два рисунка или фотографии знакомых ребенку игрушек или персонажей сказок, мультфильмов, которые можно выбрать, “кликнув” по изображению. Также здесь находятся кнопки (в виде треугольников) смены рисунков или фотографий. Также можно взять фотографии родителей или домашних питомцев.
- Область выбранного рисунка с подписью (2), которая повторяется в поле вывода слова (3) по мере того, как ребенок будет правильно выбирать буквы из алфавита (4) в верхней части окна программы. В программе используются не все буквы алфавита, а только наиболее употребляемые. Кроме того, можно заменить русский алфавит на любой другой национальный (украинский, казахский и т. д.).
Суть программы в том, что после выбора изображения ребенку нужно повторить подпись к выбранному рисунку, нажимая на соответствующие буквы в поле алфавита. При правильном выборе букв слово-подпись повторяется в поле вывода. В качестве подсказки очередная буква подписи к рисунку мигает.
Аналогично предыдущей программе сначала опишем ее структуру и особенности.
- Все действия программы производим на канве формы.
- В папке Image проекта храним набор рисунков и фотографий, которые по мере необходимости выводим на форму.
- Все манипуляции в программе осуществляются мышью.
Процедуры для реализации программы: аналогично предыдущей программе будем использовать стандартные обработчики FormMouseDown() для получения координат курсора мыши, а также процедуру обработчика событий FormClick(), в которой обрабатываем все манипуляции мышкой в окне формы. Стандартная процедура FormCreate() используется для инициализации приложения после запуска, а в процедуре FormPaint(). выводим все необходимые изображения на форму. В обработчике таймера Timer1.Timer() организуем подсказку в виде мигания очередной буквы в слове-подписи. Кроме этих стандартных процедур, напишем еще две. SelAlfavit – процедура выбора буквы в поле алфавита. В качестве параметров в процедуру передаются координаты курсора, и по ним из алфавита выбирается буква. Если выбранная буква совпадает с очередной буквой подписи (для подсказки ребенку она мигает), то выбранная буква выводится в поле вывода слова. В процедуре SelFoto производится выбор рисунка или фото и вывод его
изображения на форму.
Заключение
Программа настолько проста, что нет смысла подробно рассматривать каждую процедуру. Весь код программы с подробными комментариями смотрите в файле Unit1.pas в виде ресурсов в теме “Журнал клуба программистов. Шестой выпуск” или непосредственно в архиве с журналом.
Как известно, готовность ребенка к школе определяется комплексом его общей интеллектуальной, психологической и физической подготовки. Причем, психологическая – одна из самых трудных, так как она не возникает сама по себе и требует особого внимания родителей. В чем она проявляется? Все просто как дважды-два и через эти проблемы каждый раз проходят и родители и преподаватели и сам ребенок. Это и отсутствие сосредоточенности ребенка на предмете и личной инициативы, частое отвлечение внимания. Быть готовым к школе – это не только уметь читать, писать и считать. Это прежде всего, готовность всему этому учиться.
Для детей дошкольного возраста очень важна усидчивость и способность доводить дело до конечной цели. В этом плане хорошо помогают разнообразные настольные игры, вроде конструктора или лепки поделок из пластилина или глины, игры на счет, используя аппликации, палочки и тому подобные. Что примечательно, эти же игры помогают развивать и мелкую моторику пальцев.
Сегодня, в свете огромного скачка вперед в информационных технологиях, компьютер есть практически в каждой семье. И нельзя отрицать тот факт, что использование его на школьных занятиях практикуется уже повсеместно. Так почему-бы не познакомить ребенка с чудом двадцатого века раньше и дать возможность заранее адаптироваться к школьным трудностям. Также не будем забывать про акселерацию детей.
Конечно же, все это должно быть в форме игры и обязательно под присмотром старших. Для развития мелкой моторики малыша не нужно дорогих игрушек и особого подхода. Достаточно поиграть в:
1) пальчиковый театр;
2) электронную раскраску или говорящий алфавит.
Именно, о них и шла речь в представленном материале. Мы не предлагаем панацею, а лишь показываем, что такая область как программирование полезна и в детском творчестве. Примечательно, что этот номер вышел как раз в начале учебного года. Надеемся, статья нашего постоянного автора Владимира Дегтяря поможет вам в игровой форме занять ваших малышей, а вам самим подарить несколько свободных минут. Удачи!
Статья из шестого выпуска журнала “ПРОграммист”.
23rd
Компилятор домашнего приготовления. Часть 1
Почему мне пришла в голову идея разработать собственный компилятор? Однажды мне на глаза попалась книга, где описывались примеры проектирования в AutoCAD на встроенном в него языке AutoLISP. Я захотел c ними разобраться, но прежде меня заинтересовал сам ЛИСП. “Неплохо бы поближе познакомиться с ним”, – подумал я и начал подыскивать литературу и среду разработки. С литературой все оказалось просто – по ЛИСПу ее море в Интернете. Достаточно зайти на портал [1]. Дело оставалось за малым – найти хорошую среду программирования, и вот тут-то начались трудности. Компиляторов под ЛИСП тоже немало, но все они оказались мне малопонятны. Ни один пример из Вики, по разным причинам, не отработал нормально в скачанных мною компиляторах. Собственно, серьезно я с ними не разбирался, но, увы, во многих не нашел как скомпилировать EXE-файл. Самое интересное, что компиляторы эти были собраны разными людьми практически в домашних условиях…
Виталий Белик
by Stilet
И мне пришла в голову мысль: а почему бы не попробовать самому написать свой компилятор или, основываясь на каком-либо диалекте какого-либо языка, свой собственный язык программирования? К тому же на форумах я часто видел темы, где слезно жаловались на тиранов-преподавателей, поставивших задачу написания курсовой – компилятора или эвалюатора (программы, вычисляющей введенное в виде строки выражение). Мне стало еще интереснее: а что если простому студенту, не искушенному книгами Вирта или Страуструпа, написать такую программу? Появился мотив.
In the Beginning
Итак, начнем. Прежде всего, нужно поставить задачу хотя бы на первом этапе. Задача будет банальная: доказать самому себе, что написание компилятора не такой уж сложный и страшный процесс. И что мы, хитрые и смекалистые, способны родить в муках собственного творчества шедевр, который, возможно, полюбится массам. Да и вообще: приятно писать программы на собственном языке, не так ли?
Что ж, цель поставлена. Теперь самое время определиться со следующими пунктами:
- Под какую платформу будет компилировать код программа?
- На каком языке будет код, переводимый в машинный язык?
- На чем будем писать сам компилятор?
Первый пункт достаточно важен, ибо широкое разнообразие операционных систем (даже три монстра – Windows, Linux и MacOS) уже путают все карты. Их исполняемые файлы по-разному устроены, так что нам, простым смертным, придется выбрать из этой “кагалы” одну операционную систему и, соответственно, ее формат исполняемых файлов. Я предлагаю начать с Windows, просто потому, что мне нравится эта операционная система более других. Это не значит, что я терпеть не могу Linux, просто я его не очень хорошо знаю, а такие начинания лучше делать по максимуму, зная систему, для которой проектируешь.
Два остальных пункта уже не так важны. В конце концов, можно придумать свой собственный диалект языка. Я предлагаю взять один из старейших языков программирования – LISP. Из всех языков, что я знаю, он мне кажется более простым по синтаксису, более атомарным, ибо в нем каждая операция берется в скобочки; таким образом, к нему проще написать анализатор. С выбором, на чем писать, еще проще: писать нужно на том языке, который лучше всего знаешь. Мне ближе паскалевидные языки, я хорошо знаю Delphi, поэтому в своей разработке я избираю именно его, хотя никто не мешает сделать то же самое на Си. Оба языка прекрасно подходят для написания такого рода программ. Я не беру в расчет Ассемблер потому, что его диалект приближен к машинному языку, а не к человеческому.
To Shopping
Выяснив платформу, для которой будем писать компилятор (я имею в виду Win32), подберем все необходимое для комфортной работы. Давайте составим список, что же нам пригодится в наших изысканиях.
Для начала нам просто крайне необходимо выяснить, как же все-таки компиляторы генерируют исполняемые EXE-файлы под Windows. Для этого стоит почитать немного об устройстве этих “экзэшек”, как их часто называют, покопаться в их “кишках”. В этом могут помочь современные отладчики и дизассемблеры, способные показать, из чего состоит “экзэшка”. Я знаю два, на мой взгляд, лучших инструмента: OllyDebugger (он же “Оля”) и The Interactive Disassembler (в простонародье зовущийся IDA).
Оба инструмента можно достать на их официальных сайтах http://www.ollydbg.de/ и http://www.hex-rays.com/idapro. Они помогут нам заглянуть в святая святых – храм, почитаемый загрузчиком исполнимых файлов, – и посмотреть, каков интерьер этого храма, дабы загрузчик наших экзэшек чувствовал себя в нем так же комфортно, как “ковбой в подгузниках Хаггис”.
Также нам понадобится какая-нибудь экзэшка в качестве жертвы, которую мы будем препарировать этими скальпелями-дизассемблерами. Здесь все сложнее. Дело в том, что благородные компиляторы имеют дурную привычку пихать в экзэшник, помимо необходимого для работы кода, всякую всячину, зачастую ненужную. Это, конечно, не мусор, но без него вполне можно обойтись, а вот для нашего исследования внутренностей экзэшек он может стать серьезной помехой. Мы ведь не Ричарды Столлманы и искусством реверсинга в совершенстве не владеем. Поэтому нам лучше было бы найти такую программу, которая содержала бы в себе как можно меньше откомпилированного кода, дабы не отвлекаться на него. В этом нам может помочь компилятор Ассемблера для Windows. Я знаю два неплохих компилятора: Macro Assembler (он же MASM) и Flat Assembler (он же FASM). Я лично предпочитаю второй – у него меньше мороки при компилировании программы, есть собственный редактор, в отличие от MASM компиляция проходит нажатием одной-единственной кнопки. Для MASM разработаны среды проектирования, например MASM Builder. Это достаточно неплохой визуальный инструмент, где на форму можно кидать компоненты по типу Delphi или Visual Studio, но, увы, не лишенный багов. Поэтому воспользуемся FASM. Скачать его можно везде, это свободно распространяемый инструмент. Ну и, конечно, не забудем о среде, на которой и будет написан наш компилятор. Я уже сказал, что это будет Delphi. Если хотите конкретнее – Delphi 6.
The Theory and Researching
Прежде чем приступить к написанию компилятора, неплохо бы узнать, что это за формат “экзэшка” такой. Согласно [2], Windows использует некий PE-формат. Это расширение ранее применявшегося в MS-DOS, так называемого MZ формата [3]. Сам чистый MZ-формат простой и незатейливый – это 32 байта (в минимальном виде, если верить FASM; Турбо Паскаль может побольше запросить), где содержится описание для DOS-загрузчика. В Windows его решили оставить, видимо, для совместимости со старыми программами. Вообще, если честно, размер DOS-заголовка может варьироваться в зависимости от того, что после этих 28 байт напихает компилятор. Это может быть самая разнообразная информация, например для операционок, которые не смогли бы использовать скомпилированный DOS или Windows-экзэшник, представленная в качестве машинного кода, который прерываниями BIOS выводит на экран надпись типа “Эта программа не может быть запущена…”. Кстати, сегодняшние компиляторы поступают так же.
Давайте посмотрим на это чудо техники, воспользовавшись простенькой программой, написанной на чистом Ассемблере FASM (см. Рис. 1):
Рис. 1. Исходник для препарирования
Сохраним файл под неким именем, например Dumpy. Нажмем F9 или выберем в меню пункт RUN. В той же папке будет создан EXE-файл. Это и будет наша жертва, которую мы будем препарировать. Теперь ничто не мешает нам посмотреть: “из чего же, из чего же сделаны наши девчонки?”.
Запустим OllyDebuger. Откроем в “Оле” наш экзэшник. Поскольку фактически кода в нем нет, нас будет интересовать его устройство, его структура. В меню View есть пункт Memory, после выбора которого “Оля” любезно покажет структуру загруженного файла (см. Рис. 2):
Рис. 2. Карта памяти Dumpy
Это не только сам файл, но и все, что было загружено и применено вместе с ним, библиотеки, ресурсы программы и библиотек, стек и прочее, разбитое на блоки, называемые секциями. Из всего этого нас будут интересовать три секции, владелец которых Dumpy, – это непосредственно содержимое загруженного файла.
Собственно, эти секции были описаны нами в исходнике, я не зря назвал их по-русски (ведь операционной системе все равно, как названы секции, главное – их имена должны укладываться точь-в-точь в 8 байт. Это придется учесть обязательно).
Заглянем в первую секцию PE Header. Сразу же можем увидеть (см. Рис. 3), что умная “Оля” подсказывает нам, какие поля* у этой структуры:
Рис. 3. MZ-заголовок
Сразу хочу оговориться, не все из этих полей нам важны. Тем паче что сам Windows использует из них от силы 2-3 поля. Прежде всего, это DOS EXE Signature – здесь (читайте в Википедии по ссылке выше) помещаются две буквы MZ – инициалы создателя MS-DOS, и поле DOS_PartPag. В нем указывается размер MZ-заголовка в байтах, после которых помещается уже PE-заголовок.
Последнее поле, которое для нас важно, находится по смещению 3Ch от начала файла (см. Рис. 4):
Рис. 4. Смещение на PE-заголовок
Это поле – точка начала РЕ-заголовка. В Windows, в отличие от MS-DOS, MZ-заголовок заканчивается именно на отметке 40**, что соответствует 64 байтам. При написании компилятора будем соблюдать это правило неукоснительно.
Обратите внимание! Далее, с 40-го смещения, “Оля” показывает какую-то белиберду. Эта белиберда есть атавизм DOS и представляет из себя оговоренную выше информацию, с сообщением о том, что данная программа может быть запущена только под DOS-Windows. Этакий перехватчик ошибок. Как показывает практика, этот мусор можно без сожаления выкинуть. Наш компилятор не будет генерировать его, сразу переходя к PE-заголовку.
Что ж, перейдем непосредственно к PE-заголовку (см. Рис. 5). Как показывает “Оля”, нам нужно перейти на 80-й байт. Да, чуть не забыл. Все числа адресации указываются в 16-тиричной системе счисления. Для этого после чисел ставится латинская буква “H”. “Оля” не показывает ее, принимая эту систему по умолчанию для адресации. Это нужно учесть, чтобы не запутаться в исследованиях. Фактически 80h – это 128-й байт.
Рис. 5. Начало РЕ-заголовка
Вот она, святая обитель характеристик экзэшника. Именно этой информацией пользуется загрузчик Windows, чтобы расположить файл в памяти и выделить ему необходимую память для нужд. Вообще, считается, что этот формат хорошо описан в литературе. Достаточно выйти через Википедию по ссылкам в ее статьях [4] или банально забить в поисковик фразу вроде “ФОРМАТ ИСПОЛНЯЕМЫХ ФАЙЛОВ PortableExecutables (PE)”, как сразу же можно найти кучу описаний. Поэтому я поясню только основные его поля, которые нам понадобятся непосредственно для написания компилятора…
Прежде всего, это PE Signature – 4-хбайтовое поле. В разной литературе оно воспринимается по-разному. Иногда к нему приплюсовывают еще поле Machine, оговариваясь, чтобы выравнять до 8 байт. Мы же, как любители исследовать, доверимся “Оле” с “Идой” и будем разбирать поля непосредственно по их подсказкам. Это поле содержит две латинские буквы верхнего регистра “PE”, как бы намекая нам, что это Portable Executable-формат.
Следующее за ним поле указывает, для какого семейства процессоров пригоден данный код. Всего их, как показывает литература, 7 видов:
014Ch __80386
014Dh __80486
014Eh __80586
0162h __MIPS Mark I (R2000, R3000)
0163h __MIPS Mark II (R6000)
0166h __MIPS Mark III (R4000)
Думаю, нам стоит выбрать из всего этого второй вид – 80386. Кстати, наблюдательные личности могли заметить, что в компиляторах Ассемблера есть директива, указывающая, какое семейство процессора использовать, как, например, в MASM (см. Рис. 6):
Рис. 6. Указание семейства процессоров в МАСМ
386 как раз и говорит о том, что в этом поле будет стоять значение 014Ch***.
Обратите внимание на одну небольшую, но очень важную особенность: байты в файле непосредственно идут как бы в перевернутом виде. Вместо 14С в файл нужно писать байты в обратном порядке, начиная с младшего, т. е. получится 4С01 (0 здесь дополняет до байта. Это для человеческого глаза сделано, иначе все 16-тиричные редакторы показывали бы нестройные 4С1. (Согласитесь, трудно было понять, какие две цифры из этого числа к какому байту относятся.) Эту особенность обязательно придется учесть. Для простоты нелишним было бы написать пару функций, которые число превращают в такую вот перевернутую последовательность байт (что мы в дальнейшем и сделаем).
Следующее важное для нас поле – NumberOfSections. Это количество секций без учета PE-секции. Имеются в виду только те секции, которые принадлежат файлу (в карте памяти их владелец – Dumpy). В нашем случае это “Данные” и “код”.
Следующее поле хоть и не столь важно, но я его опишу. Это TimeDateStamp – поле, где хранится дата и время компиляции. Вообще, я его проигнорирую, не суть важно сейчас, когда был скомпилирован файл. Впрочем, если кому захочется помещать туда время, то флаг в руки.
Сразу хочу предупредить, что меня как исследователя не интересовали поля с нулевыми значениями. На данном этапе они действительно неважны, поэтому в компиляторе их и нужно будет занулить.
Следующее важное поле – SizeOfOptionalHeader. Оно содержит число, указывающее, сколько байт осталось до начала описания секций. В принципе, нас будет устраивать число 0Eh (224 байта).
Далее идет поле “характеристики экзэшника”. Мы и его будем считать константным:
И равно оно 010Eh. На этом поле заканчивается так называемый “файловый заголовок” и начинается “Опциональный”.
Следующее поле – MagicNumber. Это тоже константа. Так называемое магическое число. Если честно, я не очень понял, для чего оно служит, в разных источниках это поле преподносится по-разному, но все хором ссылаются на знаменитый дизассемблер HIEW, в котором якобы впервые появилось описание этого поля именно в таком виде. Примем на веру.
Следующие два поля, хоть и не нулевые, но нам малоинтересны. Это: MajorLinkerVersion и MinorLinkerVersion. Это два байта версии компилятора. Угадайте, что я туда поставил?
Следующее важное поле – AddressOfEntryPoint. Важность этого поля в том, что оно указывает на адрес, с которого начинается первая команда, – с нее процессор начнет выполнение. Дело в том, что на этапе компиляции значение этого поля не сразу известно. Ее формула достаточно проста. Сначала указывается адрес первой секции плюс ее размер. К ней плюсуются размеры остальных секций до секции, считаемой секцией кода. Например, в нашей жертве это выглядит так (см. Рис. 7):
Рис. 7. Расчет точки входа
Здесь секция кода вторая по счету, значит, Адрес точки входа равен размеру секции “Данные” плюс ее начало и равен 2000. К этому еще пририсовывается базовый адрес, в который загрузчик “сажает” файл, но он в вычислении для нашего компилятора не участвует. Поэтому в жертве точка входа имеет значение 2000.
Следующее поле – ImageBase. Это поле я приму как константу, хотя и не оговаривается ее однозначное значение. Это значение указывает адрес, с которого загрузчик поместит файл в память. Оно должно нацело делиться на 64000. В общем, необязательно указывать именно 400000h, можно и другой адрес. Уже не помню, где я слышал, что загрузчик может на свое усмотрение поменять это число, если вдруг в тот участок памяти нельзя будет загружать, но не будем это проверять, а примем на веру как константу =400000h.
Следующая важная константа – SectionAlignment. Это значение говорит о размере секций после загрузки. Принцип прост: каждая секция (имеется в виду ее реализация) дополняется загрузчиком пустыми байтами до числа, указанного в этом поле. Это так называемое выравнивание секций. Тут уж хороший компилятор должен думать самостоятельно, какой размер секций ему взять, чтобы все переменные (или сам код), которые в коде используются, поместились без проблем. Согласно спецификации, это число должно быть степенью двойки в пределах от 200h (512 байт) до 10000h (64 000 байт). В принципе, пока что для простенького компилятора можно принять это значение как константу. Нас вполне устроит среднее значение 1000h (4096 байт – не правда ли, расточительный мусор? На этом весь Windows построен – живет на широкую ногу, память экономить не умеет).
Далее следует поле FileAlignment. Это тоже хитрое поле. Оно содержит значение, сколько байт нужно дописать в конец каждой секции в сам файл, т. е. выравнивание секции, но уже в файле. Это значение тоже должно быть степенью двойки в пределах от 200h (512 байт) до 10000h (64 000 байт). Неплохо бы рассчитывать функцией это поле в зависимости от размеров, данных в секции.
Следующие поля – MajorSubsystemVersion и MinorSubsystemVersion – примем на веру как константы. 3h и Аh соответственно. Это версия операционной системы, под которую рассчитывается данная компиляция****.
Я не проверял на других ОС: у меня WinXP. В принципе можно не полениться и попробовать пооткрывать “Олей” разные программы, рассчитанные на другие версии Windows.
Далее из значимых следует SizeOfImage. Это размер всего заголовка, включая размер описания всех секций. Фактически это сумма PE-заголовка плюс его выравнивание, плюс сумма всех секций, учитывая их выравнивание. Ее тоже придется рассчитывать.
Следующее поле – SizeOfHeaders (pазмеp файла минус суммарный pазмеp описания всех секций в файле). В нашем случае это 1536-512 * 2=200h (512 байт). Однако РЕ тоже выравнен! Это поле тоже нужно будет рассчитывать.
Далее следует не менее коварное поле – CheckSum. Это CRC сумма файла. Ужас… Мы еще файл не создали, а нам уже нужно ее посчитать (опять-таки вспоминается Микрософт злым громким словом). Впрочем, и тут можно вывернуться. В Win API предусмотрена функция расчета CRC для области данных в памяти, проще говоря, массива байт – CheckSumMappedFile. Можно ей скормить наш эмбрион файла. Причем веселье в том, что эта операция должна быть самой последней до непосредственной записи в файл. Однако, как показывает практика, Windows глубоко наплевать на это поле, так что мы вполне можем не морочить себе голову этим расчетом (согласитесь, держать в файле поле, которое никому не нужно, да еще и напрягать нас лишним расчетом – это глупо, но, увы, в этом изюминка политики Микрософта. Складывается впечатление, что программисты, писавшие Windows, никак не согласовывали между собой стратегию. Спонтанно писали. Импровизировали).
Следующее поле – Subsystem. Может иметь следующие значения*****:
- IMAGE_SUBSYSTEM_WINDOWS_CUI=3. Это говорит о том, что наш откомпилированный экзэшник является консольной программой.
- IMAGE_SUBSYSTEM_WINDOWS_GUI=4. Это говорит о том, что экзэшник может создавать окна и оперировать сообщениями.
Для справки, кто хорошо знает Delphi: директивы компилятора {$APPTYPE GUI} и {$APPTYPE CONSOLE} именно эти параметры и выставляет.
Вот, собственно, и все важные для нас параметры. Остальные можно оставить константно, как показывает “Оля”:
SizeOfStackReserve = 1000h (4096)
SizeOfStackCommit = 1000h (4096)
SizeOfHeapReserve = 10000h (65536)
NumberOfRvaAndSizes = 10h (16)
И остаток забить нулями (посмотрите в “Оле” до начала секций, какие там еще параметры). О них можно почитать подробнее по ссылкам, которые я привел.
После идет описание секций. Каждое описание занимает 32 байта. Давайте взглянем на них (Рис. 8):
Рис. 8. Описание секций
В начале секции идет ее имя (8 байт), после этого поле – VirtualSize, описывает (я процитирую из уроков Iczeliona) “RVA-секции. PE-загpузчик использует значение в этом поле, когда мэппиpует секцию в память. То есть, если значение в этом поле pавняется 1000h и файл загpужен в 400000h, секция будет загpужена в 401000h”.
Однако “Оля” почему-то показывает для обеих секций одно и то же значение 9. Что это? Я не понял, почему так. Пока оставим это как данное. Вдруг в будущем разберемся.
Далее следует VirtualAddres, который указывает, с какого адреса плюс ImageBase будет начинаться в памяти секция – это важное поле, именно оно станет для нашего компилятора базой для расчета адреса к переменной. Собственно, адрес этот напрямую зависит от размера секции. Следующий параметр PointerToRawData – это смещение на начало секции в скомпилированном файле. Как я понял, этот параметр компиляторы любят подводить под FileAlignment. И последнее – поле Characteristics. Сюда прописывается доступ к секции. В нашем случае для секции кода оно будет равным 60000020=CODE|EXECUTE|READ, а для секции данных C0000040=INITIALIZED_DATA |READ|WRITE.
Вот и все. Закончилось описание заголовка. Далее он выравнивается нулями до 4095 байт (с этим числом связан один прикол). В файле мы его будем дополнять до FileAlignment (в нашем случае до 200h).
Hello world. Hey! Is There Anybody Out There?
Вот мы и прошлись по кишкам нашей жертвы – экзэшника. Напоследок попробуем на скорую руку закрутить простейший компилятор для DOS-системы без PE-заголовка. Для этого подойдут инструменты, которые так почему-то любят преподавать до сих пор.
Я говорю о классическом Паскале. Итак, предположим, злобный преподаватель поставил задачу: написать компилятор программы вывода на экран некой строки, которую мы опишем для компилятора, введя ее ручками (см. листинг 1):
e,i:integer;
f:file;
begin
{Это MZ-заголовок}
header:=#$4D#$5A#$3E#$00#$01#$00#$
00#$00#$02#$00#$00#$01#$FF#$FF#$02#$00#$00;
header:=header+#$10#$00#$00#
$00#$00#$00#$00#$1C#$00#$00#$00#$00#$00#$00#$00;
writeln(
‘give me welcome ’);readln(s);
{Поскольку у нас все в одном сегменте, и код и данные, лежащие непосредственно в конце кода, нужно, чтобы регистр, содержащий базу данных, указывал на код. Предположим, мы будем считать, что и сам код представляет из себя данные. Для этого поместим в стек адрес сегмента кода}
{*******************************************************************************************}
Commands:=#$0E; { push cs}
{и внесем из стека этот адрес в регистр сегмента данных}
Commands:=Commands+#$1F; { pop ds}
Commands:=Commands+#$B4#$09; { mov ah, 9 – Вызовем функцию вывода строки на экран}
{Передадим в регистр DX-адрес на строку. Поскольку пока что строка у нас не определена, передадим туда нули, а позже подкорректируем это место}
Commands:=Commands+#$BA#$
00#$00; { mov dx, }
{Запомним место, которое нужно будет скорректировать. Этим приемом я буду пользоваться, чтобы расставить адреса в коде, который обращается к переменным}
e:=length(commands)-1;
{Выведем на экран строку}
Commands:=Commands+#$CD#$21;
{ int 21h ; DOS – PRINT STRING}
{подождем, пока пользователь не нажмет любую клавишу}
Commands:=Commands+#$B4#$01; { mov ah, 1}
Commands:=Commands+#$CD#$21; { int 21h ; DOS – KEYBOARD INPUT}
{После чего корректно завершим программу средствами DOS}
Commands:=Commands+#$B4#$4C; { mov ah, 4Ch}
Commands:=Commands+#$CD#$21; {int 21h ; DOS – 2+ – QUIT WITH EXIT CODE (EXIT)}
Commands:=Commands+#$C3; {retn}
{*******************************************************************************************}
{Теперь будем править адреса, обращающиеся к переменной. Поскольку само значение переменной у нас после всего кода (и переменная) одно, мы получим длину уже имеющегося кода – это и будет смещение на начало переменной}
i:=length(commands);
{В запомненное место, куда нужно править, запишем в обратном порядке это смещение}
commands[e]:=chr(lo
(i));
commands[e+1]:=chr(hi(i));
{Учтем, что в DOS есть маленький атавизм – строки там должны завершаться символом $. По крайней мере, для этой функции.}
commands:=commands+s+‘$’;
{не забудем дописать в начало заголовок}
commands:=header+commands;
{Теперь скорректируем поле DOS_PartPag. Для DOS-программ оно указывает на общий размер файла. Честно говоря, я не знаю, зачем это было нужно авторам, может быть, когда они изобретали это, еще не было возможности получать размер файла из FAT. Опять-таки запишем в обратном порядке}
i:=length(commands);
commands[3]:=chr(lo(i))
;
commands[4]:=chr(hi(i));
{Ну, и кульминация этого апофигея – запись скомпилированного массива байт в файл. Все заметили, что я воспользовался типом String, – он в паскалевских языках был изначально развит наиудобнейшим образом}
Assign(f,‘File.exe’);rewrite(f);
BlockWrite(f,commands[1],length(commands), e);
Close(f);
end.
Не удивляет, что программа получилась небольшой? Почему-то преподаватели, дающие такое задание, уверены, что студент завалится. Думаю, такие преподаватели сами не смогли бы написать компилятор. А студенты смогут, ибо, как видим, самая большая сложность – это найти нужные машинные коды для решения задачи. А уж скомпилировать их в код, подкорректировать заголовок и расставить адреса переменных – задача второстепенной сложности. В изучении ассемблерных команд поможет любая книга по Ассемблеру. Например, книга Абеля “Ассемблер для IBM PC”. Еще неплохая книга есть у Питера Нортона, где он приводит список функций DOS и BIOS.
Впрочем, можно и банальнее. Наберите в поисковике фразу “команды ассемблера описание”. Первая же ссылка выведет нас на что-нибудь вроде [5] или [6], где описаны команды Ассемблера. Например, если преподаватель задал задачку написать компилятор сложения двух чисел, то наши действия будут следующими:
- Выясняем, какая команда складывает числа. Для этого заглянем в книгу того же Абеля, где дается такой пример:
сложение содержимого
ADD AX,25 ;Прибавить 25
ADD AX,25H ;Прибавить 37 - Значит, нам нужна команда ADD. Теперь определимся: нам же нужно сложить две переменные, а это ячейки памяти; эта команда не умеет складывать сразу из переменной в переменную, для нее нужно сначала слагаемое поместить в регистр (AX для этого лучше подходит), а уж потом суммировать в него. Для помещения из памяти в регистр (согласно тому же Абелю) нужна команда
mov [адрес], ax
- Таким образом, инструкции будут выглядеть так:
mov [Адрес первой переменной], ax
add [Адрес второй переменной], ax - Теперь нужно определиться с кодами этих команд. В комплекте с MASM идет хелп, где описаны команды и их опкоды (машинные коды, операционные коды). Вот, например, как выглядит опкод команды MOV из переменной:
Рис. 9. Опкоды MOV
Видим (см. Рис. 9), что его опкод A1 (тут тоже любят 16-тиричность). Таким образом, выяснив все коды, можно написать компилятор что-то вроде этого (см. листинг 2):
Commands:= Commands+#$A1#$00#$00; { mov [Из памяти] в AX}
aPos:= Length(Commands)-1;{Запомним позицию для корректировки переменной a}
Commands:= Commands+#$03#$06#$00#$00;
{ $03 – Это опкод команды ADD $06 – Это номер регистра AX}
bPos:= Length(Commands)-1;{Запомним позицию для корректировки переменной b}
Commands:= Commands+#$A3#$00#$00; { mov из AX в переменку b}
b2Pos:= Length(Commands)-1;
{Запомним позицию для корректировки для переменной b}А далее, в конце, скорректируем эти позиции (см. листинг 3):
commands:= commands+#$01#$00; {Это переменка a, ее значение}
i:= length(commands);
commands[aPos]:= chr(lo(i)); {Не забудем, что адреса в перевернутом виде}
commands[
aPos+1]:= chr(hi(i)); {Поэтому сначала запишем младший байт}
commands:= commands+#$02#$00; {Это переменка b, ее значение}
i:= length(commands);
commands[bPos]:= chr
(lo(i)); {Поскольку переменка b фигурирует в коде}
commands[bPos+1]:= chr(hi(i)); {дважды придется корректировать ее}
commands[b2Pos]:= chr
span style=”color: #66cc66;”>(lo(i));
commands[b2Pos+1]:= chr(hi(i));Запустим компилятор, он скомпилирует экзэшник, который посмотрим в “Иде” (см. Рис. 10):
Рис. 10. Реверсинг нашего кода
Все верно, в регистр пошло значение одной переменной, сложилось со второй и во вторую же записалось. Это эквивалентно паскалевскому b:=b+a;
Обратите внимание: значения переменных мы заранее проинициализировали. При желании можно сделать, чтобы компилятор спросил их инициальное значение, и подставить в нужное место:
Post Scriptum
Ну как, студенты, воспряли духом? Теперь понятен смысл, куда двигаться в случае столкновения с такими задачами? Это вряд ли потянет на курсовую, но вполне подойдет для простенькой контрольной. А вот следующая задача – написать транслятор – уже действительно тянет даже на хороший диплом, так что пока переварим все то, что выше, а в следующий раз попробуем приготовить основное ядро компилятора, дабы потом уже делать упор на сам код программы.
The Чтиво
- Ресурс Википедии по языку LISP http://ru.wikipedia.org/wiki/Lisp
- Ресурс Википедии по формату PE http://ru.wikipedia.org/wiki/PE
- Ресурс Википедии по формату MZ http://ru.wikipedia.org/wiki/MZ_(формат)
- Micheal J. O’Leary (Microsoft). The portable executable format http://www.nikse.dk/petxt.html
- Описание простейших команд Ассемблера http://students.uni-vologda.ac.ru/pages/it10/2.php
- Питер Абель. Ассемблер и программирование для IBM PC. – British Columbia Institute of Technology
Статья из шестого выпуска журнала “ПРОграммист”.
Обсудить на форуме — Компилятор домашнего приготовления. Часть 1
22nd
Сен
Свернуть програму при запуске через PI.dwProcessId?
Привет всем!
Как свернуть программу запускаемую через ShowWindow(); используя ProcessInformation.dwProcessId?
var
len: Integer;
classname: array [0..$ff] of Char;
begin
Result:=True;
if IsWindowVisible(hwnd) then
begin
ShowWindow(hwnd,SW_SHOWMINIMIZED);
end;
end;
procedure TForm1.sButton2Click(Sender: TObject);
var
startupinfoa: _STARTUPINFOA;
processinformation: _PROCESS_INFORMATION;
begin
ZeroMemory(@startupinfoa, SizeOf(_STARTUPINFOA));
startupinfoa.cb:=SizeOf(_STARTUPINFOA);
startupinfoa.dwFlags:=STARTF_USES
HOWWINDOW;
startupinfoa.wShowWindow:=SW_SHOWMINIMIZED;
CreateProcess(nil, PChar(‘calc.exe’), nil, nil, False, 0, nil, nil, startupinfoa, processinformation);
WaitForInputIdle(processinformation.hProcess, 10000);
EnumThreadWindows(processinformation.dwThreadId, @EnumThreadWndProc, 0);
end;
22nd
Скрытное копирование каталога
от замечательная функция для копирования:
OverWriteFiles: Boolean): Boolean;
Var
SR: TSearchRec;
I: Integer;
Begin
Result:=False;
SourceDir:= IncludeTrailingBackslash(SourceDir);
TargetDir:= IncludeTrailingBackslash(TargetDir);
If Not DirectoryExists(SourceDir) Then Exit;
If Not ForceDirectories(TargetDir) Then Exit;
I:=FindFirst(SourceDir + ‘*’, FaAnyFil
e, SR);
Try
While I = 0 Do
Begin
If (SR.Name <> ”) And (SR.Name <> ‘.’) And (SR.Name <> ‘..’) Then
Begin
If SR.Attr = FaDirectory Then
Result:= FullDirectoryCopy(SourceDir + SR.Name, TargetDir + SR.NAME, StopIfNotAllCopied, OverWriteFiles)
Else If Not (Not OverWriteFiles And FileExists(TargetDir + SR.Name)) Then
Result:= CopyFile(Pchar(SourceDir + SR.Name), Pchar(TargetDir + SR.Name),
False)
Else Result:=True;
If Not Result And StopIfNotAllCopied Then Exit;
End;
I:=FindNext(SR);
End;
Finally
SysUtils.FindClose(SR);
End;
End;
21st
Сен
О правильном составлении ТЗ. Часть 1
Рано или поздно в жизни программиста появляется заказчик с неким проектом. Разработчик берется за этот проект, но результатом каждой последующей встречи с заказчиком становится появление новых функциональных и нефункциональных требований, в то время как сроки сдачи и бюджет остаются прежними, таким образом, все наваливается снежным комом, и в итоге наступает коллапс. Для того, чтобы такая скверная ситуация не наступила, с заказчиком нужно договориться еще на берегу. Но нельзя полагаться на какие-то словесные договоренности и т. п.: мы должны максимальн
о себя обезопасить. Разрабатывая программу, мы преследуем определенную цель, ставим перед собой определенные задачи. Успех нашего дела во многом зависит от того, насколько наша цель будет четкой и ясной. Знакомясь с выполненной работой, заказчик, естественно, будет анализировать, выполнили ли мы поставленные задачи, поэтому все они должны быть четко сформулированы, описаны и согласованы с ним. Вот тут нам на помощь и приходит ТЗ.
Дарья Устюгова
by Sparky
Введение
В цикле статей, основываясь на своем опыте и на опыте других, я попробую рассказать, что такое ТЗ, зачем оно нам нужно, из чего состоит, как его написать и оформить, какие подводные камни можно обойти, написав грамотное ТЗ. В первой статье я постараюсь объяснить, зачем ТЗ используется, в чем его плюсы, кто его должен писать, и приведу примерное содержание ТЗ.
Техническое задание. Что это и зачем оно нам?
Начнем мы с определения: техническое задание (ТЗ) – точная формулировка задачи. Можно даже сказать, что ТЗ всему голова. Многие слышали о таком понятии, как жизненный цикл программного обеспечения (ПО); для тех, кто не слышал, а быть может, просто забыл, напомню: жизненный цикл ПО – системы процедур, правил и инструментальных средств, используемых для разработки и поддержания работоспособности программной системы. Жизненный цикл включает в себя этапы создания программы. Существует множество версий: по Глассу, по ГОСТ ЕСПД, по Майерсу. Все эти версии
21st
Как из базы ABS достать файлы?
У меня есть база ABS. В неё вложено два файла mapinfo (это не важно могли быть и обычные картинки).
Как я могу достать их?
_SERGEYX_:
В каком поле хранятся файлы?
Если тип этого поля BLOB или GRAPHIC, то в AbsDb Manager достаточно два раза кликнуть по ячейке в этом поле и откроется окошко сохранения и
загрузки данных (в/из файла). Кстати, к AbsDb Manager есть исходники, где можно увидеть код сохранения данных в файл. Для графики вот такой:
var
FileStream: TFileStream;
BlobStream: TStream;
begin
if (sdGraphic.Execute) then
begin
FileStream := TFileStream.Create(sdGraphic.FileName,fmCreate);
BlobStream := CurrentTable.CreateBlobStream(CurrentGrid.SelectedField,bmRead);
FileStream.CopyFrom(BlobStream,BlobStream.Size);
BlobStream.Free;
FileStream.Free;
end;
end;
Для BLOB:
var
FileStream: TFileStream;
BlobStream: TStream;
begin
if (sdBlob.Execute) then
begin
FileStream := TFileStream.Create(sdBlob.FileName,fmCreate);
BlobStream := CurrentTable.CreateBlobStream(CurrentGrid.SelectedField,bmRead);
FileStream.CopyFrom(BlobStream,BlobStream.Size);
BlobStream.Free;
FileStream.Free;
end;
end;
21st
Application.Terminate или Close?
MainForm.Close – вызывает закрытие немедленно. Application.Terminate – отправляет сообщение о закрытии в очередь. Т.е форма закроется после обработки всех сообщений.
В 99% случае разницы между немедленным закрытием и отложенным – нет.
Ends application execution.
Call Terminate to end the application programmatically. By calling Terminate rather than freeing the application object, you allow the application to shut down in an orderly fashion.
Terminate calls the Windows API PostQuitMessage function to perform an orderly shutdown of the application. Terminate is not immediate.
Terminate is called automatically on a WM_QUIT message and when the main form closes.
21st
Может ли функция в delphi возвращать массив?
TArInt=array of integer;
function FuncName(Param:integer):TArInt;
20th
Сен
Изменение цвета шрифта надписи в выделенной ячейки ListBox
Stilet:
Выставь свойство Style:=lbOwnerDrawFixed
И опиши два обработчика:
Rect: TRect; State: TOwnerDrawState);
begin
with TListBox(Control) do begin
if index=ItemIndex then
Canvas.font.Color
:=clred
else
Canvas.font.Color:=clblack;
Canvas.FillRect(rect);
Canvas.TextOut(rect.Left,rect.Top,items[index]);
end;
end;
procedure TForm1.ListBox1Click(Sender: TObject);
begin
ListBox1.Repaint;
end;
19th
Сен
Исследование протокола PS/2 для мышки
В этой статье я попытаюсь объяснить аспекты, связанные с интерфейсом PS/2 для периферийного устройства типа мышь, включая физический, электрический интерфейс, протокол низкого уровня, режимы работы, команды и расширения…
Евгений Амосов
by Gambit_OZ gambitoz@mail.ru
Мышь воспринимает своё перемещение в рабочей плоскости (обычно – на участке поверхности стола) и передаёт эту информацию компьютеру. Программа, работающая на компьютере, в ответ на перемещение мыши производит на экране действие, отвечающее направлению и расстоянию этого перемещения. В универсальных интерфейсах (например, в оконных) с помощью мыши пользователь управляет специальным курсором – указателем, то есть манипулятором элементами интерфейса.
В дополнение к детектору перемещения мышь имеет от одной до трёх и более кнопок, а также дополнительные элементы управления (колёса прокрутки, потенциометры, джойстики, трекболы, клавиши и т. п.), действие которых обычно связывается с текущим положением курсора (или составляющих специфического интерфейса).
Фактически все эти устройства общаются с компьютером при помощи двух интерфейсов: универсальной последовательной шины (USB) или интерфейса PS/2.
Интерфейс PS/2 расшифровывается как Personal System/2. Широкую популярность он приобрел благодаря использованию для взаимодействия с манипулятором типа мышь в компьютерах Apple Macintosh и позднее в ОС Windows для IBM PC в конце 80-х. Однако сегодня быстро завоевавший популярность интерфейс USB в конечном итоге практически заменил PS/2 полностью. Тем не менее, протокол PS/2 представляет собой интересную платформу для различных экспериментов научного характера. Например, можно использовать мышку с разъемом PS/2 для управления каким-либо передвижным устройством-роботом или сделать свой манипулятор, который при помощи датчиков-гироскопов, закрепленных на пальцах руки, будет эмулировать передвижение курсора на экране, а щелчком пальцев открывать папки и т. д. В дальнейших статьях будет описано, как это можно реализовать.
Интерфейс мыши PS/2 использует двунаправленный последовательный протокол, по которому передаются данные о движении и состоянии кнопок вспомогательному диспетчеру устройств компьютера (далее по тексту – хост). Диспетчер, в свою очередь, посылает команды для мыши, чтобы установить частоту обмена, разрешение, ее перезагрузку, выключение и т. д. Напряжение питания на линии передачи 5В ~100 мА. На Рис. 1 показано обозначение контактов разъема PS/2, на Рис. 2 – возможное подключение мышки к своему устройству:
Рис. 1. Обозначение контактов PS/2
Рис. 2. Вариант подключения мышки к своему устройству
Входы, разрешение и масштабирование
Стандартный интерфейс мыши PS/2 поддерживает следующие входы: перемещение по координате X (вправо/влево), перемещение по координате Y (вверх/вниз), левая кнопка, средняя кнопка, правая кнопка. Данный тип мыши является стандартом, но сейчас уже не используется. Мышь периодически читает эти входы, обновляет связанные с ними счетчики и устанавливает флаги, чтобы в дальнейшем отправить хосту текущее состояние кнопок и перемещение. Есть много манипуляторов PS/2, которые имеют дополнительные входы и могут сообщить о данных по-другому, чем описано в этом документе. Одним из популярных расширений является Microsoft Intellimouse, которое включает в себя поддержку стандартных входов, а также колеса прокрутки и двух дополнительных кнопок (это уже современные мышки).
У стандартной мыши есть два 9-разрядных счетчика с флагами переполнения, которые отслеживают перемещение: по координате X и по координате Y. Их содержание, а также состояние трех кнопок мыши отправляется хосту в виде 3-хбайтового пакета данных. Счетчики перемещения определяют смещение мыши относительно ее предыдущей позиции, когда было совершено перемещение или когда пришла команда Resend (0xFE).
Когда мышь читает свои входы, она записывает текущее состояние своих кнопок и постепенно увеличивает/уменьшает счетчики перемещения согласно значению перемещения, которое произошло относительно последнего значения. Если любой из счетчиков переполнится, то будет установлен соответствующий флаг переполнения.
Параметр, который определяет величину увеличения/уменьшения счетчиков перемещения, является разрешением. Разрешение по умолчанию равно четырем значениям на миллиметр, и хост может изменить это значение, используя команду Set Resolution (0xE8).
Существует параметр, который не влияет на счетчики перемещения, но влияет на значения, которые снимаются со счетчиков. Этот параметр называется масштабированием. По умолчанию мышь использует масштабирование 1:1. Однако хост может выбрать масштабирование 2:1, используя команду Set Scaling 2:1 (0xE7). Если будет включено масштабирование 2:1, то мышь применит следующий алгоритм к счетчикам перемещения прежде, чем отправить их содержание хосту (см. Таблицу 1).
Состояние счетчика движения | Отсылаемое значение |
---|---|
0 | 0 |
1 | 1 |
2 | 1 |
3 | 3 |
4 | 6 |
5 | 9 |
N>5 | 2 * N |
Масштабирование 2:1 применяется только к автоматически отсылаемым данным в потоковом режиме. Это не влияет на данные, которые отправляются в ответ на команду Read Data (0xEB).
Пакет данных о перемещениях
Стандартная мышь PS/2 посылает информацию о движении/кнопках хосту, используя следующий 3-хбайтовый пакет (см. Таблицу 2):
Байт | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
---|---|---|---|---|---|---|---|---|
1 | Y-переполнение | X-переполнение | Y знак бит | Х знак бит | всегда 1 | Средняя кнопка | правая кнопка | левая кнопка |
2 | X-перемещение | |||||||
3 | Y-перемещение |
Значения перемещения – это два 9-разрядных целых числа, где старший значащий бит, появляется битом “X/Y знак” в 1-м байте из передаваемого пакета данных. Их значение представляет смещение мыши относительно ее предыдущей позиции, определенной текущим разрешением. Диапазон отсылаемых значений лежит в пределах от -255 до +255. Если этот диапазон будет превышен, то установится соответствующий бит переполнения.
Режимы работы
Создание отчетов данных обработано согласно режиму, в котором работает мышь. Есть четыре режима работы:
- сброс (Reset) – начальный режим, в котором мышь выполняет инициализацию и самодиагностику;
- поток (Stream) – рабочий режим по умолчанию, в котором мышь отправляет пакеты данных о перемещениях, когда происходит перемещение или изменяются состояния кнопок;
- удаленный (Remote) – хост должен упорядочить пакеты данных о перемещениях;
- обратный (Wrap) – диагностический режим, в котором мышь отправляет каждый полученный пакет назад к хосту.
Режим сброса (Reset)
Мышь переходит в режим сброса при включении питания или в ответ на команду Reset (0xFF). После ввода этого режима мышь выполняет диагностическую самопроверку и устанавливает следующие значения по умолчанию:
Частота дискретизации =100 значений в секунду
Разрешение =4 значения на 1мм
Масштабирование =1:1
Создание отчетов данных = отключено
После режима самодиагностики мышь отправляет хосту результат проверки – 0xAA (успешно) или 0xFC (ошибка).
Следующим значением после 0xAA или 0xFC мышь отправляет свой ID=0×00. Это значение указывает на то, что это мышь, а не клавиатура или иное устройство. В некоторых описаниях протокола указано, что хост не должен передавать данные, пока тот не получит ID устройства. Однако некоторые BIOS’ы отправляют команду Reset (0xFF) сразу после команды 0xAA, полученной после того, как включенное питание было сброшено.
Как только мышь отправила свой ID устройства хосту, она входит в потоковый режим.
Потоковый режим (Stream)
В потоковом режиме мышь отправляет данные перемещения, когда обнаруживается перемещение или изменение в состоянии одной или более кнопок мыши. Максимальная частота, на которой можно сообщить об этих данных, известна как частота дискретизации. Этот параметр изменяется в пределах от 10 до 200 значений в секунду (по умолчанию – 100 значений в секунду). Хост может изменить это значение, используя команду Set Sample Rate (0xF3).
Отметим, что создание отчетов отключено по умолчанию. Мышь не будет фактически слать пакеты данных о перемещениях, пока она не получит команду Enable Data Reporting (0xF4).
Потоковый режим – рабочий режим по умолчанию или режим, в который можно установить, используя команду Set Stream Mode (0xEA).
Удаленный режим (Remote)
В удаленном режиме мышь читает свои входы и обновляет счетчики/флаги на текущей частоте дискретизации, но не отсылает автоматически пакеты данных, если произошло перемещение. Вместо этого хост опрашивает мышь, используя команду Read Data (0xEB). После получения этой команды мышь отсылает единственный пакет данных о перемещениях и сбрасывает свои счетчики перемещения.
Мышь входит в удаленный режим при получении команды Set Remote Mode (0xF0). Удаленный режим используется редко.
Обратный режим (Wrap)
Это “эхо”-режим, в котором каждый байт, полученный мышью, отсылается назад к хосту. Даже если полученный байт будет соответствовать системной команде, то мышь не станет отвечать на эту команду, а только отправит данный байт назад хосту. Однако есть два исключения: команды Reset (0xFF) и Reset Wrap Mode (0xEC). Мышь обработает их как допустимые команды и не отправит назад хосту.
Обратный режим используется редко.
Расширения Intellimouse
Популярное расширение стандартной мыши PS/2 – Microsoft Intellimouse – включает в себя поддержку в общей сложности пяти кнопок мыши и трех осей перемещения (вправо/влево, вверх/вниз и колесо прокрутки). Эти дополнительные функции требуют использования 4-хбайтового пакета данных перемещения, а не стандартного 3-хбайтового. Так как стандартные драйверы мыши PS/2 не могут распознать этот пакетный формат, Intellimouse обязан работать точно как стандартная мышь PS/2. Таким образом, если Intellimouse будет использоваться на компьютере, который поддерживает только стандартную мышь PS/2, то она (мышка) будет все еще функционировать, за исключением колеса прокрутки и 4-й и 5-й кнопок.
После включения питания или сброса Microsoft Intellimouse работает точно так же, как стандартная мышь PS/2 (то есть использует 3-хбайтовый пакет данных о перемещениях, отвечает на все команды таким же образом, как на стандартную мышь PS/2, и сообщает о ID устройства 0×00).
Чтобы включить колесо прокрутки, хост отправляет следующую последовательность команд:
- Установить частоту дискретизации =200
- Установить частоту дискретизации =100
- Установить частоту дискретизации =80
Хост отправляет команду Get device ID (0xF2) и ожидает ответа. Если это стандартная мышь PS/2 (то есть не IntelliMouse), то она ответит ID устройства 0×00. В этом случае хост распознает факт, что мышь действительно не имеет колеса прокрутки, и будет продолжать обрабатывать ее как стандартную мышь PS/2. Однако если будет подключена Microsoft Intellimouse, то она ответит ID =0×03. Это сообщит хосту, что у присоединенного манипулятора есть колесо прокрутки, и хост перейдет в режим ожидания 4-хбайтового пакета данных о перемещениях (см. Таблицу 3):
Байт | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
---|---|---|---|---|---|---|---|---|
1 | Y-переполнение | X-переполнение | Y знак бит | Х знак бит | всегда 1 | Средняя кнопка | правая кнопка | левая кнопка |
2 | X-перемещение | |||||||
3 | Y-перемещение | 4 | Z-перемещение |
“Z-перемещение” – дополнительное значение, которое представляет собой перемещение колеса прокрутки начиная с последнего отчета данных. Допустимые значения находятся в диапазоне от -8 до +7. Это означает, что число фактически представлено как четыре младших, значащих бита; старшие четыре бита – только как расширение знака.
Чтобы включить колесо прокрутки, а также 4-ю и 5-ю кнопки, хост отправляет следующую последовательность команд:
- установить частоту дискретизации =200
- установить частоту дискретизации =200
- установить частоту дискретизации =80
Хост шлет команду Get device ID (0xF2) и ожидает ответа. Microsoft Intellimouse отвечает ID устройства =0×04, затем использует следующий 4-хбайтовый пакет данных перемещения (см. Таблицу 5):
Байт | Бит 7 | Бит 6 | Бит 5 | Бит 4 | Бит 3 | Бит 2 | Бит 1 | Бит 0 |
---|---|---|---|---|---|---|---|---|
1 | Y-переполнение | X-переполнение | Y знак бит | Х знак бит | всегда 1 | Средняя кнопка | правая кнопка | левая кнопка |
2 | X-перемещение | |||||||
3 | Y-перемещение | |||||||
4 | 0 | 0 | 5-я кнопка | 4-я кнопка | Z-перемещение |
4-я кнопка =1, если нажата 4-я кнопка мыши, и 5-я кнопка =1, если нажата 5-я кнопка мыши. “Z-перемещение” представляет собой значение движения, которое произошло начиная с последнего отчета данных. Действительные значения изменяются в пределах от -8 до +7.
Набор команд
Следующее – набор команд; он является стандартом для мыши с интерфейсом PS/2. Если мышь находится в потоковом режиме, хост должен отключить создание отчетов данных (команда 0xF5) прежде, чем отправить какие-то команды.
- 0xFF (Reset) – мышь отвечает командой (0xFA) и входит в режим сброса.
- 0xFE (Resend) – хост отправляет эту команду всякий раз, когда он получает ошибочные данные от мыши. Мышь отвечает, посылая последний пакет, который она отправила хосту. Если мышь отвечает на команду Resend другим недопустимым пакетом, хост может или дать другую команду Resend, или сформировать команду Error (0xFC) и произвести сброс питания с мыши. Эта команда не буферизована, что означает, что Resend никогда не будет отправляться в ответ на команду Resend.
- 0xF6 (Set Defaults) – мышь отвечает командой (0xFA) и устанавливает следующие значения: частота дискретизации =100, разрешение =4 значения на 1 миллиметр, масштабирование =1:1, создание отчетов данных = отключено. Мышь сбрасывает все свои счетчики перемещения и входит в потоковый режим.
- 0xF5 (Disable Data Reporting) – мышь отвечает командой (0xFA), отключается создание отчетов данных и сбрасываются счетчики перемещения.
- 0xF4 (Enable Data Reporting) – мышь отвечает командой (0xFA), включается режим создания отчетов данных и сбрасываются счетчики перемещения. Эта команда может быть получена в тот момент, когда мышь находится в удаленном режиме, но будет выполнена, только если мышь переключится в потоковый режим.
- 0xF3 (Set Sample Rate) – мышь отвечает командой (0xFA) и ожидает один байт из хоста. Мышь сохраняет этот байт как новую частоту дискретизации. После получения частоты дискретизации мышь снова отвечает командой (0xFA) и сбрасывает свои счетчики перемещения. Допустимые частоты дискретизации – 10, 20, 40, 60, 80, 100 и 200 значений в секунду.
- 0xF2 (Get Device ID) – мышь отвечает командой (0xFA), сопровождая его ID устройства (0×00 для стандартной мыши PS/2). Мышь должна также сбросить свои счетчики перемещения.
- 0xF0 (Set Remote Mode) – мышь отвечает командой (0xFA), сбрасывает свои счетчики перемещения и входит в удаленный режим.
- 0xEE (Set Wrap Mode) – мышь отвечает командой (0xFA), сбрасывает свои счетчики перемещения и входит в эхо-режим.
- 0xEC (Reset Wrap Mode) – мышь отвечает командой (0xFA), сбрасывает свои счетчики перемещения и входит в режим, в котором она была до эхо-режима (в потоковый или удаленный).
- 0xEB (Read Data) – мышь отвечает командой (0xFA) и отправляет пакет данных перемещения. Это единственный способ считать данные в удаленном режиме. После того, как пакет данных был успешно отправлен, мышь сбрасывает свои счетчики перемещения.
- 0xEA (Set Stream Mode) – мышь отвечает командой (0xFA), сбрасывает свои счетчики перемещения и входит в потоковый режим.
- 0xE9 (Status Request) – мышь отвечает командой (0xFA), затем передается следующий 3-хбайтовый пакет состояния (см. Таблицу 6):
Таблица 5. Пакет состояния Байт Бит 7 Бит 6 Бит 5 Бит 4 Бит 3 Бит 2 Бит 1 Бит 0 1 Всегда 0 Режим включение масштабирование всегда 0 левая кнопка средняя кнопка правая кнопка 2 Разрешение 3 частота опроса Правая, средняя, левая кнопка =1, если соответствующая кнопка нажата; 0, если кнопка не нажата. Масштабирование =1, если масштабирование 2:1; 0, если масштабирование 1:1 (см. команды 0xE7 и 0xE6).
Включение =1, если включено создание отчетов данных; 0, если создание отчетов данных отключено (см. команды 0xF5 и 0xF4).
Режим =1, если удаленный режим включен; 0, если включен потоковый режим (см. команды 0xF0 и 0xEA).
- 0xE8 (Set Resolution) – мышь отвечает командой (0xFA), читает один байт из хоста и снова отвечает командой (0xFA), затем сбрасывает свои счетчики перемещения. Побайтовое чтение от хоста определяет разрешение следующим образом (см. Таблицу 7):
Таблица 6. Расшифровка данных, принятых с хоста Байт, считанный с хоста Разрешение 00 1 значение/мм 01 2 значения/мм 02 4 значения/мм 03 8 значений/мм - 0xE7 (Set Scaling 2:1) – мышь отвечает командой (0xFA), затем включает масштабирование 2:1.
- 0xE6 (Set Scaling 1:1) – мышь отвечает командой (0xFA), затем включает масштабирование 1:1.
Инициализация
Мышь PS/2 обычно обнаруживается/инициализируется, только когда компьютер загружается. Таким образом, мышь не может использоваться в горячем подключении; в результате приходится перезапускать свой компьютер всякий раз, когда устанавливается/удаляется мышь PS/2.
Начальное обнаружение мыши PS/2 происходит во время включения компьютера. Если мышь будет обнаружена, то BIOS позволит операционной системе конфигурировать/использовать мышь.
Иначе устанавливается запрет на передачу по шине мыши. Если загружать компьютер с присоединенной мышью, отключить мышь и повторно ее включить в то время, когда загружается Windows, ОС в состоянии обнаружить мышь и дать с ней работать.
Рассмотрим передачу данных между компьютером и стандартной мышью PS/2 во время процесса начальной загрузки (Листинг 1).
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: C8 число 200
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 64 число 100
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 50 число 80
Мышь: FA Подтверждение
Хост: F2 Прочитать тип устройства
Мышь: FA Подтверждение
Мышь: 00 Идентификатор мыши
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 0A число 10
Мышь: FA Подтверждение
Хост: F2 Прочитать тип устройства
Мышь: FA Подтверждение
Мышь: 00 Идентификатор мыши
Хост: E8 Установить разрешение
Мышь: FA Подтверждение
Хост: 03 8 значений/мм
Мышь: FA Подтверждение
Хост: E6 Установить масштабирование 1:1
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 28 число 40
Мышь: FA Подтверждение
Хост: F4 Включить
Мышь: FA Подтверждение
Инициализация завершена…
Если нажата левая кнопка.
Мышь: 09 1 1 00001001; Бит0 – состояние левой кнопки мыши; Бит3 всегда =1
Мышь: 00 1 1 Нет X-перемещений
Мышь: 00 1 1 Нет Y-перемещений
… и отпущена левая кнопка мыши:
Мышь: 08 0 1 00001000 Бит0 – состояние левой кнопки мыши; Бит3 всегда =1
Мышь: 00 1 1 Нет X-перемещений
Мышь: 00 1 1 Нет Y-перемещений
Теперь рассмотрим обмен данными между компьютером и мышью Intellimouse (при загрузке компьютера).
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса (все, надоело. Дальше хост не выделяю)
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: FF Команда сброса
Мышь: FA Подтверждение
Мышь: AA Тестовый режим
Мышь: 00 Идентификатор мыши
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: C8 число 200
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 64 число 100
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 50 число 80
Мышь: FA Подтверждение
Хост: F2 Прочитать тип устройства
Мышь: FA Подтверждение
Мышь: 03 Идентификатор мыши
Хост: E8 Установить разрешение
Мышь: FA Подтверждение
Хост: 03 8 значений/мм
Мышь: FA Подтверждение
Хост: E6 Установить масштабирование 1:1
Dev: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 28 число 40
Мышь: FA Подтверждение
Хост: F4 Включить устройство
Мышь: FA Подтверждение
Если нажата левая кнопка мыши…
Мышь: 09 00001001 Бит0 – состояние левой кнопки мыши; Бит3 всегда =1
Мышь: 00 Нет X-перемещений
Мышь: 00 Нет Y-перемещений
Мышь: 00 Нет Z-перемещений
… и отпущена левая кнопка мыши:
Мышь: 08 00001000
Мышь: 00 Нет X-перемещений
Мышь: 00 Нет Y-перемещений
Мышь: 00 Нет Z-перемещений
После установки драйвера IntelliMouse Microsoft с поддержкой 4-х и 5-х кнопок была найдена следующая последовательность:
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: C8 число 200
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 64 число 100
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 50 число 80
Мышь: FA Подтверждение
Хост: F2 Прочитать тип устройства
Мышь: FA Подтверждение
Мышь: 03 Идентификатор мыши
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: C8 число 200
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: C8 число 200
Мышь: FA Подтверждение
Хост: F3 Установить частоту дискретизации
Мышь: FA Подтверждение
Хост: 50 число 80
Мышь: FA Подтверждение
Хост: F2 Прочитать тип устройства
Мышь: FA Подтверждение
Мышь: 04 Идентификатор мыши
….
Заключение
Удалось выяснить принцип работы мышки – протокол обмена с компьютером. Благодаря полученной информации представилась возможность использовать мышь не только по ее прямому назначению, но и для поделок, как я говорил выше. Самый простой пример – это прикрепление мышки под днище самодельного робота, а так как мы знаем протокол обмена, можно, например, сделать дешевый импровизированный GPS-навигатор, и ваш робот будет всегда знать, где он находится, а заодно и шарики мышки будут использоваться как дополнительные колеса. Другой пример. Подключаем мышку к тому же самому роботу и управляем им: двинул мышь вперед – робот поехал вперед, кликнул мышкой – робот выстрелил импровизированной ракетой.
Ресурсы
Статья в Википедии
http://ru.wikipedia.org/wiki/Компьютерная_мышь
Мышь, которая всегда под рукой. Веб-архив журнала “Наука и жизнь”
http://www.nkj.ru/archive/articles/8810
Принцип работы компьютерной мыши
http://www.molodinfo.n-vartovsk.ru/insite/mouse/mouse_tech.htm
The PS2 protocol
http://pcbheaven.com/wikipages/The_PS2_protocol
Подключение PC AT клавиатуры к AVR
http://radioded.ru/content/view/53/49
Описание протокола PS/2 для мыши и клавиатуры
http://marsohod.org/index.php/ourblog/11-blog/57-ps2proto
Adam Chapweske. The PS/2 Mouse/Keyboard Protocol
http://www.computer-engineering.org/ps2protocol
Adam Chapweske. The PS/2 Mouse Interface
http://www.computer-engineering.org/ps2mouse
Статья из шестого выпуска журнала “ПРОграммист”.
Облако меток
css реестр ассемблер timer SaveToFile ShellExecute программы массив советы word MySQL SQL ListView pos random компоненты дата LoadFromFile form база данных сеть html php RichEdit indy строки Win Api tstringlist Image мысли макросы Edit ListBox office C/C++ memo графика StringGrid canvas поиск файл Pascal форма Файлы интернет Microsoft Office Excel excel winapi журнал ПРОграммист DelphiКупить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)