99

VR-Online (February 2011)

Embed Size (px)

DESCRIPTION

Бесплатный электронный журнал для программистов и всех тех, кто интересуется околокомпьютерными вопросами

Citation preview

Page 1: VR-Online (February 2011)
Page 2: VR-Online (February 2011)

INTRO2

INTROот главного редактора:Игорь Антонов (Spider_NET)

vr-on l ine | февраль 201 1

No retreat, no surrender.

Ты можешь быть программистом, а может кем-то другим. Восвоении той или иной профессии есть свои оптимальныепути. Два из которых стандартны – постоянное изучениеновой информации и стремление. И действительно, ничегоне удастся добиться без стремления к цели и преодолениятрудностей. Я всегда считал и считаю, что возможностичеловека безграничны и при должной сноровке и мотивацияможно стать кем угодно. Например, мне в школе пророчилибедную жизнь и должность столяра, из-за того что в 1 0-м и11 -м классе у меня были плохие оценки по алгебре ифизике. Когда моя математичка услышала, что я хочупрограммистом она рассмеялась и сказала, чтобы пересталсебя обманывать. Меня, естественно, это не зацепило, и ястал учиться самостоятельно и верить в свою мечту.Прошло время, и получил профессию, которую я хотел. Имогу с уверенностью сказать, что я это заслужил. Я тратилкучу времени, ограничивал себя в «людских» радостях(надеюсь, ты правильно понял смысл этой фразы) и учился,двигался к цели. Да, были трудности, было желание всебросить и заняться чем-то еще, но я удержался.Результатом доволен до сих пор.

Стремление, труд, постоянная работа над собой и вера вуспех – это и есть элементы успеха. Если ты пытаешьсячему-то научиться и сам не веришь в себя, то будь уверен –у тебя ничего не выйдет. Сам настрой играет очень важнуюроль и никогда не нужно об этом забывать. Это относится нетолько к работе/творчеству, но и человеческим отношениям.Смотри на все максимально шире, верь в свою идею (вразумных пределах) и добивайся поставленных целей. Мнеэто очень помогает жить, и считаю, что может помочь и тебе.

Отдельно хочется сказать про такой коварный момент какбоязнь оценки. Еще со школьной скамьи нас приучили, что 5– это true, а 2 – false. Однако, в жизни все сложнее. Нужнонаучиться оценивать свою работу самостоятельно. Напервый взгляд это кажется просто, но нужно понять, как этоделать не предвзято. Если получился отстой – так и скажисебе. Не нужно обманывать себя. Но если ты уверен, чтоэто - шедевр, то не зачем сразу опускать нос, когда Вася ссоседнего подъезда попытается выразить свою завистьчерез негатив. Имей терпение.

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

Автор и идея проекта:

Михаил Фленов (Horiffic)

Редакция:

Игорь Антонов (Spider_NET)

Роман Костенко (Lord of fear)

Верстка и оформление:

Антон Козлов (Jimmy Jonezz)

Голубниченко Юрий (Ghost Rider)

Обложка журнала:

Антон Козлов (Jimmy Jonezz)

Письма и предложения:

mail@vr-onl ine.ru

antonov. igor.khv@gmail . ru

Примечание:

Редакция приветствует любоесвободное распространениеномеров журнала в неизменномвиде.

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

За перепечатку материалов безспроса и указания авторства -преследуем.

Page 3: VR-Online (February 2011)

3

февраль 201 1 | vr-on l ine

{Содержание}_Февраль [30] 2011_

IT-NEWS

HARD-NEWS

VrIP ПЕРСОНА

8. BitByBit: Учимся программироватьпостепенно

КОДИНГ

11 . C#. Заметки программиста

1 4. C#. Криптографические алгоритмы.PKCS#5

1 6. C#. Отзывчивые приложения

1 9. C#. MongoDB. Нереляционный скуль

23. C#. NHIBERNATE и C#

29. C#. Reflection

32. Delphi. Сохраняем класс в файл

34. Java. Адаптеры в Android

40. Паттерны MVC, MVP и MVVM

44. Пишем игру для Android. Часть 5.Хранение настроек

50. С++. Защита программы от анализа

53. С++. Сетевое программирование.Часть 1

64. C++ Делаем свою секцию данных в PE

БЕЗ РАМКИ

67. Сетикет - этикет в Интернете

68. VR-online в лицах. Часть 2

73. Разговор о программировании. Часть 2

МЕНЯ ТОШНИТ

ОБЗОРЫ ОТ VR-ONLINE

78. Тест наушников до 1 00$

81 . Книги. Доступный Unix

Я ПРУСЬ

АДМИНИНГ

84. FliMP своими руками

КРЕАТИFF

88. Inskape. Диско-шар своими руками

МНЕНИЕ VR

ШКОЛА

92. CodeIgniter 2.0. Быстрая разработкаweb-сайтов. Часть 1

94. CodeIgniter 2.0. Отправляем E-mail

96. 1 С Предприятие 8. Часть 8. Документы

Содержание

Page 4: VR-Online (February 2011)

4

vr-on l ine | февраль 201 1

IT-NEWS

IT-NEWSСамые важные новости компьютерного мира

Второго марта состоялась долгожданнаяпремьера нового планшета от Apple – iPad 2.Пожалуй, все пользователи, успевшие запрошедший год оценить плюсы iPad, снетерпением ждали этого события. Ведь многиесчитали, что первая версия близка к идеалу ибыло интересно, а что сможет предложить Appleв новинке. А предлагают они следующие фичи:

- Еще более тонкий корпус (8,8 мм);

- Две камеры (можно снимать HD ролики);

- Повышенная производительность (процессорApple A5 1 Ггц);

- На 1 5% легче, чем предшественник;

- и т.д.

Найдет ли iPad 2своих клиентов?Думаю да, этоотличное решение ипожалуй пока лучшеничего нет. Даже еслиучесть, что прилавкимагазинов заваленыпланшетами от такихкомпаний какSamsung, RowerPad –суть дела не меняется.Пока iPad лидер. Какпо цене, так и пофункциональнымвозможностям.

iPad 2 начинает свое шествие

Вы еще не забылиотца VR-Online,славного парня поимени Horrific? Сейчасон трудится на благоодной солиднойканадской компании инаправляет потокисвоего сознания надоработку какого-тоинтернет-магазина.

Очень радует, что мигрировав из России Миша незабросил свое перо. Он периодически пишет

статьи в ][ (я во всяком случае одну читал) и ещестарается поддерживать свои старые проекты –книги. В начале января полки книжных магазиноввстретили обновленные версии Библии Delphi (3-е издание) и Библии C# (2-ая редакция).Насколько известно, первая книга изменилась несильно, а вот библейские притчи от C# былисущественно переписаны. Все кто планировалпорадовать себя покупкой одной из этих книг –не промахнитесь. VR-Online категорическирекомендует приобретать последние издания.Остерегайтесь подделок!

Новые редакции книг от Horrific’а

Предыдущий конкурс показал, что вам приятнопринимать в них участвовать. Итоги мы подвели,призы отправили – самое время повторить успехи взбудоражить ваши сердца. Мы с РомойКостенко подумали и решили, что следующийконкурсом станет «Лучший блоггер VR». Блогичертовски популярны, и практически каждыйактивный интернет-пользователь хочет завестисвой блог, который взорвет сознание масс изавоюет неслыханную популярность. Идеяконечно добротная и похвальная, но иногда

бывает трудно начать еереализовывать. VR-Onlineпредлагает тебебесплатную площадкудля экспериментов. Мысделали блогиобщедоступными!Каждыйзарегистрированныйпользователь можетзавести блог на VR-Online

Новый конкурс от VR-Online

Page 5: VR-Online (February 2011)

5

февраль 201 1 | vr-on l ine

IT-NEWS

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

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

Администрацияпредставителя СШАв сфере внешнейторговли ежегодно вапреле публикуетдоклады серииSpecial 301 онарушении правинтеллектуальнойсобственности в

мире. Обычно к этим докладам прилагаетсясписок крупнейших рынков разных стран,торгующих контрафактными товарами, и сайтов,распространяющих пиратские файлы. Однако в2011 году ведомство решило опубликовать такойсписок отдельно. Россию в списке представляютторрент-портал Rutracker, социальная сеть"ВКонтакте", которая, по словам авторовдокумента, "предположительно предоставляет

пользователям доступ к материалам снарушением авторских прав", и московскийСавеловский рынок, где, "как сообщается,свободно продается широкий ассортиментпиратской продукции". В список также попалибазирующийся на территории Украины торрент-трекер Demonoid и киевский рынок "Петровка".Лидером среди стран по количествуперечисленных в списке рынков и сайтовявляется Китай. Так, крупнейшая в Китаепоисковая система Baidu подозревается ввыдаче ссылок на пиратский контент, которыйфизически размещен на сторонних сайтах. Асамая крупная площадка для интернет-торговлив Азии Taobao охарактеризована как ресурс, накотором могут продаваться контрафактныетовары: сигареты, одежда, медицинскиепрепараты и т.д.

США нашла распространителей пиратского контента в России

Сколько же я уже получал писем с просьбойвернуть подкасты. Дело доходило чуть ли не доугроз (я не шучу). Мы никогда ничего не имелипротив подкастов, но как-то изначально с ними несложилось. Причин тут много. Первая и самаяглавная – время. На запись/сведение требуетсябольшое количество времени. Особенно трудновыбрать время чтобы собраться вместе в эфире.Если с Ромой мы живем в одном городе, то состальными участниками проекта – нет. Часовыепояса делают свою подрывную работу, и сборведущих постоянно превращался в очереднуючасть фильма «Миссия невыполнима». Я ужедумал, что эта проблема не будет решенаникогда.

Однако, совершенно случайно при беседой сРомкой за рюмкой коньяка чашкой кофе, мысгенерили идею, а почему бы не писать подкастына работе? Мы все равно приходим на часраньше, а этого времени вполне хватит длянебольшого подкастика. К тому же, мы можемзаписываться в неделю несколько раз. Идею мыподхватили на ура и решили сделать пробнуюзапись. Сама концепция подкаста витала в моейголове уже давно. Копировать «Радио-Т» нехотелось, нужно было искать что-то свое. Вот таки появились на свет первые душевныепосиделки. Такой формат идеально насустраивает, и мы будем пытаться его развивать идальше. А ты уже успел нас послушать?

Душевные посиделки от VR

Page 6: VR-Online (February 2011)

6

vr-on l ine | февраль 201 1

HARD-NEWSСвежие новости из мира "железных" технологий

HARD-NEWS

Оба неттопа Zotac ZBoxAD02 содержатпредустановленный 2-ядерный процессорAMD APU (acceleratedprocessing unit) E-350,который работает начастоте 1 ,6 ГГц и несетна бортуинтегрированноеграфическое ядроRadeon HD 631 0,

обладающее поддержкой DirectX 11 . Также вналичии имеется кард-ридер 6-в-1 , гигабитныйсетевой интерфейс Ethernet, модульбеспроводной связи Wi-Fi 802.11 b/g/n, два порта

USB 3.0, видео выходы D-Sub, DVI и HDMI. Вустройстве ZBox AD02 Plus также содержитсяоперативная память стандарта DDR3 объемом 2ГБ и 2,5-дюймовый жесткий диск емкостью 250ГБ. В barebone-системе ZBox AD02 этикомпоненты предстоит устанавливатьсамостоятельно. Компания Zotac разработалановый неттоп ZBox AD02, основанный наплатформе AMD Fusion. Новинка доступна в двухмодификациях: полностью готовый нетоп ZBoxAD02 Plus и barebone-система ZBox AD02, гдепользователь имеет возможность выбрать иустановить некоторые компонентысамостоятельно.

Компания Seagate сообщила о начале поставокновых жестких дисков высокой емкости BarracudaXT. Данные устройства ориентированы наприменение в составе домашних серверов,рабочих станций, компьютерных систем, накоторых осуществляется редактирование видео,игровых компьютеров. Жесткие диски Seagateсерии Barracuda XT выполнены в форм-факторе3,5 дюйма. Их емкость составляет 3 ТБ.Отмечается, что в устаревших операционныхсистемах (например, Windows XP) и компьютерахсо старыми версиями BIOS изначально непредусмотрена возможность использованиядискового пространства жесткого диска запределами емкости 2,1 ТБ. С целью устраненияданной проблемы Seagate предлагаетиспользовать программное обеспечение

DiscWizard, котороепозволяет пользователюлегко сконфигурироватьсистему с цельюполного использованиявсего доступногодискового пространства.В жестких дискахSeagate Barracuda XTиспользуется 64 МБкэш-памяти иинтерфейс подключенияSATA3 (скоростьпередачи данных до 6Гб/с). Скоростьвращения шпинделясоставляет 7200 об/мин.

Seagate начинает поставки жесткого диска Barracuda XT емкостью 3 ТБ

Компания Spireвыпустилакомпактный кулер дляноутбуков и нетбуков,получивший названиеJuno. Кулер для

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

устройствами, обладающими диагональю экранаот 7 до 1 5,4 дюйма. Новинка имеет размеры220х90х20 мм и массу 245 г. Устройствооснащается 70-миллиметровым вентилятором,получающим питание через интерфейс USBнепосредственно от ноутбука и нескользкиминакладками на верхней и нижней поверхностях.Представленная модель обеспечивается 3-летней гарантией производителя.

Компактный кулер Juno для ноутбуков от Spire

Zotac представила неттоп ZBox AD02

Page 7: VR-Online (February 2011)

7

февраль 201 1 | vr-on l ine

HARD-NEWS

На выставке MWC 2011 компания Motorolaрассказала о технических характеристиках ицене своего планшета, известного под названиемXoom. Планшет Motorola Xoom оснащается 1 0-дюймовым сенсорным дисплеем с разрешением1 280×800 точек, 2-ядерным процессором NVIDIATegra 2, встроенной флэш-памятью емкостью 32ГБ, гироскопом, акселерометром, 5-мегапиксельной камерой на задней панели(поддерживается возможность записи видео вразрешении 720p) и VGA камерой на переднейпанели. Также устройство содержит модулибеспроводной связи Wi-Fi 802.11 n и Bluetooth 2.1 .

Вдополнительной комплектациипланшетMotorola Xoomможетсодержать имодуль 3G, аво второмкварталеожидаетсяпоявление модели с модулем 4G. В качествеоперационной системы используется Android 3.0.

Motorola рассказала о характеристиках и цене планшета Xoom

Компания PackardBell выпустиламонитор Maestro230 LED, вкоторомприменяетсяоригинальнаяподставка,расположеннаяасимметричноотносительно

вертикального центра. Монитор Packard BellMaestro 230 LED обладает диагональю экрана 23

дюйма и поддерживает Full HD разрешение1 920×1 080 точек. В новинке используется LEDподсветка матрицы, которая обеспечиваетвысокую контрастность изображения и низкийуровень энергопотребления. В результате,максимальная динамическая контрастностьмонитора Packard Bell Maestro 230 LED заявленана уровне 1 2000000:1 , а максимальная яркостьсоставляет 260 кд/м2. Время реакции матрицысоставляет 5 мс. Для подключения источниковсигнала к монитору Packard Bell Maestro 230 LEDприменяются интерфейсы D-Sub, DVI и HDMI.

Packard Bell выпустила монитор Maestro 230 LED

Компания Sparkle выпустила видеокарту самбициозным названием GeForce GTX 580Thermal Guru, которая выполнена на печатнойплате оригинального дизайна и оснащенафирменной системой охлаждения. Последняя, поданным производителя, позволяет охлаждатьвидеочип GF11 0 под нагрузкой на пять градусовЦельсия сильнее, чем эталонный кулер, и приэтом имеет в два раза меньший вес. В основу

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

секций, атакже двавентиляторатипоразмера80 мм. Кожухсистемыохлажденияимеетспецифическую обтекаемуюформу. Хотязадняя панельвидеокартыимеет одноярусную компоновку, системаохлаждения всё равно занимает пространствососеднего слота расширения. Sparkle не сталаизменять технические характеристики GeForceGTX 580: видеокарта оснащается 1 536 Мбпамяти типа GDDR5 и работает на номинальныхчастотах 772/1 544/4008 МГц.

Sparkle охлаждает GeForce GTX 580 при помощи "прямого контакта"

Page 8: VR-Online (February 2011)

8

vr-on l ine | февраль 201 1

«Учимся программироватьпостепенно»Интервью с BitByBit.ru

Интервью брал Игорь Антонов и Роман Костенко

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

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

• Для начала представьтесь и расскажитенемного о себе. Кем работаете, где живете, накого учились.

Здравствуйте. Здесь правильным было быуказать как минимум всех программистов,которые трудились над проектом: ДмитрийКузьма, Александр Егоров, Виталий Гринько,Максим Горбачев, Артем Стребиж. Мы всеучились/учимся на околопрограммистскихспециальностях. Дмитрий и Александр окончилиЛЭТИ. Остальные еще учатся в ГУАПе.Большинство из нас работает, так что надпроектом трудимся в свободное от основнойработы время. Как и в большинстве проектов,над BitByBit работа ведется удаленно, тем болеечто живем достаточно далеко друг от друга.

• Расскажите о проекте BitByBit. Почему вырешили его создать? Сколько временипотребовалось для запуска проекта впродакшн? И самое главное, с чем связанвыбор названия?

Все началось с курсов веб-программирования,которые организовали и вели Александр иДмитрий. И по окончанию курсов нужен былполновесный командный проект, на основекоторого можно было закрепить полученныезнания. Но никому из нас не нужен был проектради проекта, нам хотелось создать нечтополезное. Вшестером, вместе с ВячеславомШмариным, нашим партнером, мы придумалиBitByBit – тогда еще просто «сервис дляпрограммистов». Выбор названия оказалсядовольно длительным процессом – мыразмышляли над тем, с чем должноассоциироваться наше название, затем«сгенерировали» огромное количество вариантовиз которого и выбрали BitByBit. Но еще большевремени мы, конечно, потратили на разработку,которая заняла больше года.

• Над созданием проекта трудится целаякоманда? Если команда, то, как выраспределяете обязанности? Кто за чтоотвечает?

Как уже ясно из предыдущих ответов, надпроектом мы работаем командой. В процессеэволюции проекта изменялись и нашиобязанности. Так, поначалу, Дмитрий занималсяпроектированием проекта, распределял задачи иподзадачи; Максим, Артем и Виталий трудилисьнепосредственно над кодом. Со временемуровень всех членов команды вырос и теперь,после очередного мозгового штурма мысовместно распределяем задачи на всехпятерых. Обычно это происходит по принципу,кто какой модуль делал, тот его и дорабатывает.Если кто-то расправился со всеми своимиподзадачами, то ему повезло – он можетзаняться созданием нового модуля. Но кое-что впроекте остается неизменным. То, каким долженбыть BitByBit в целом, а также его новые сервисымы всегда обсуждали и обсуждаем совместно.Помимо программистов в проекте участвуетдизайнер Денис Ширяев, его обязанностиочевидны. А также Вячеслав Шмарин – егодеятельность, которая, прежде всего, связана спереговорами и во многом только начинается.

• В чем особенность BitByBit среди подобныхпроектов?

Ну, если говорить о рунете, то «подобныхпроектов» просто не существует. Все нынедействующие проекты, являются простоколлективными неструктурированными блогами,в которых найти нужную информацию крайнесложно. Мы же, прежде всего, сервиссистематизации знаний, дающий адекватнуюоценку программистов. Сколько-нибудь стоящаясистематизация на текущий момент есть толькоу форумов. И именно из-за ее значимости многиепрограммисты, идущие в ногу со временем,продолжают пользоваться форумами несмотря

VrIP персона

Page 9: VR-Online (February 2011)

9

февраль 201 1 | vr-on l ine

на то, что они неустанно устаревают. Ну а подадекватной оценкой мы в первую очередьпонимаем то, что только у нас просто порейтингу можно отличить java специалиста отпрограммиста Ruby или даже языка Ада (когдамы сочтем нужным его добавить). Более того, вряде случаев наши оценки распределяются ещеглубже, доходя до фреймворков, библиотек, CMSи пр.

• К какой категории web-проектов правильнейотносить bitbybit - продвинутая социальнаясеть для разработчиков или...?

Мы больше любим использовать термин сервисс элементами социальный сети. Или портал –ведь BitByBit, это своеобразная точка входа дляпрограммиста, из который он получает доступ кнеобходимым ему сервисам. Это может бытьсамоучитель, готовое решение, системавопросов и ответов и многое другое. Более того впроцессе нашего развития сервисы будут всеприбавляться и прибавляться.

• BitByBit создавался с нуля или за основубыл взят какой-нибудь западныйаналогичный проект?

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

• При разработке BitByBit вы использовалиcmf? Если да, то какой, а если нет, то почему.

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

• Какие языки программирования являютсясамыми востребованными на вашемресурсе?

В большей степени пока это веб-технологи: PHP,JavaScript, HTML, CSS. Но проявляется интереси к таким языкам как Java, C++, C# и др.

• Проект BitByBit делался для души илипланируется создание платных сервисов?

Одно другому не мешает. Chatroulette, facebookaсписок можно продолжить. Мы верим, чтополезный востребованный продукт обреченприносить дивиденды без ущерба для своихпользователей.

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

Откровенно говоря, эту проблему мы еще нерешали. Да, мы предприняли пару шагов –

сделали пару публикаций на посещаемыхтематических сайтах, подключили социальныесервисы, в том числе twitter, организовалинебольшой конкурс. Увы, все этонепозволительно мало. Но, как не стыдно занедостаток проделанной работы, радует то, чтопользователи уже начали генерировать контент.Это подтверждает полезность нашего сервиса. Внаше оправдание скажу, что в ближайшее времямы планируем существенно активизироваться вэтом направлении. О конкретных действиях япока умолчу, может это станет поводом дляочередного интервью. Скажу лишь, что мыпланируем нововведение, которое может помочьнашим активным пользователям существенноувеличить свои доходы.

• Как вы относитесь к журналам(бумажным/электронным) на IT тематику?Какие журналы читаете регулярно?

Журналы – вещь безусловно полезная. В нихесть одно качество которое присуще и нашемупроекту - систематизация информации.Регулярно мы журналов не читаем, времени нехватает, да и формат не очень удобный для тогочтобы брать в дорогу. Изредка просматриваемнекоторые отдельные номера Хакера илиКомпьютерры если заинтересует.

• Как вы считаете, может ли современныйинтернет-проект, рассчитанный на большуюаудиторию существовать на голомэнтузиазме?

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

• У BitByBit интересный дизайн. Вродепростенько, но пользоваться удобно. Какдолго вы занимались дизайном ипродумыванием интерфейса сайта?

Сказать, что долго – ничего не сказать.Разработкой интерфейсов занимались те, комупредстояло ими пользоваться, т.е. мы сами,программисты. Задачей же дизайнера быловоплотить наши мысли в графику. Дизайнеров завремя создания BitByBit было два. Первый (дажене помню как его зовут) упорно отказывался наспонимать, ну или мы были не в состояниидоходчиво объяснить. Результаты нам настольконе нравились, что мы были вынуждены с нимраспрощаться. Затем мы стали сотрудничать сДенисом Ширяевым, с которым у нас уже былопыт работы над некоторыми из наших заказов.Вот он уже прекрасно справился со своейзадачей. Процесс обычно сводился кследующему – после длительных споровкомандой над очередной частью интерфейсаДмитрий переносил все это на бумагу и

VrIP персона

Page 10: VR-Online (February 2011)

1 0

vr-on l ine | февраль 201 1

VrIP персона

передавал Денису на прорисовку.

• Расскажите про свое отношение ксоциальным сетям (одноклассники,вконтакте, фейсбук)?

Социальные сети безусловно нужны и полезны.Помимо всем понятных вещей как поискзнакомых, друзей, обмен информацией и т.п.есть еще и большое подспорье дляразработчиков. Так как соц.сети объединяютбольшое количество людей и так сказать“приучают” их к одному интерфейсу, чтопозволяет не разбрасываться на мелочиподстраиваясь под каждого. Плюс к этому еще иopenAPI который дает возможностьпользователям заходить на сайты под своимаккаунтом соц.сети или рассказать друзьям обинтересной статье на сайте.

• Сегодня чертовски популяренмикроблоггинг. Есть ли у вашего ресурсааккаунт в Twitter'е?

Да, конечно: @bitbybit_ru. Кроме того, мыпланируем ввести оригинальный и весьмаполезный сервис, который у нас будет довольнотесно переплетаться с твиттером.

• Как на сегодняшний день оцениваетепопулярность проекта BitByBit?

Я бы сказал, что он еще весьма малопопулярен.Не многие о нем еще слышали; не все ктослышал, сразу его восприняли и поняли.Главное, уже начинает формироваться группалюдей, которым проект небезразличен –

регулярно на проекте появляются новыепубликации, ведутся обсуждения. Так что всевпереди.

• Многие разработчики считают, что в Россиитрудно заработать на "оригинальных"проектах. Не найдя инвесторов, золотые умыуезжают за рубеж и пробуют свои силы там.Что вы думаете по этому поводу? Не быложелания мигрировать?

За границей, конечно инвестиции найти проще. ВРоссии еще не сформировалась культуравенчурного инвестирования. У нас готовывкладывать только тогда, когда риски стремятся кнулю. Но какое же это венчурное (рисковое)инвестирование, если рисков нет?! С другойстороны, трудно заработать – это еще не значит,что невозможно. Иногда, чем труднее, теминтереснее!

• Успешный проект для Вас - этоX

Проект, который приносит пользу и покрываетзатраченные ресурсы (не важно финансово илинет).

• Ну и напоследок традиционный вопрос:"Чтобы вы хотели пожелать нашимчитателям".

Читателям хотелось бы пожелать никогда неостанавливаться на достигнутом, развиваться иизучать что-то новое. И если среди нового Вырешите освоить какой-то языкпрограммирования, то мы будем рады видетьВас на BitByBit

Page 11: VR-Online (February 2011)

11

февраль 201 1 | vr-on l ine

C#. Заметки программистаНесколько уроков для программиста изучаещего C sharp

Автор: Голубниченко Юрий aka Ghost Rider | ghostrider.gu@gmail .com

Привет! Сегодня мы поговорим о языке программирования С#.

Наша статья будет строиться на основе заметок. Что это значит?

Наверняка у многих есть собственный блог вИнтернете, где ты периодически публикуешьсвои статьи, отзывы, рецензии и прочее. Вдруг унас возникает мысль собрать все интересныезаписи воедино и замутить из всего этого книгу (кпримеру). У такой книги не будет четкойструктуры, определенной последовательности,как в учебниках. Но это и не надо, у таких книгесть свои плюсы, порой даже пожирнее отдельновзятых руководств. Мы можем начать читатьтакие книги с середины или с конца, неважно,ведь между отдельными частями нет жесткойзависимости (типа не сделаешь это, не получишьто ?).

Нечто похожее будет представлять и эта статья,просто заметки по языку C#.

Однако малость кое-какую структуру мы все же"наведем":

1 . C# - кто ты, и откуда к нам пришел?

2. .NET – а ты кто?

3. С#. заметки

4. Заключение

В качестве введения мы примем все вышенаписанное.

C# - кто ты, и откуда к нам пришел?

C# без преувеличения можно назвать самымглавным языком разработки для платформы.NET. В нем удачно сочетаются испытанныевременем средства и техникипрограммирования, а также современныетехнологии разработки ПО. Но откуда он к нампришел, что за ним стоит. Попробуемразобраться. C# является прямым "потомком"языков C и C++, а C++ в свою очередьпроизошел от С. Также следует упомянуть оJava, так как C# перенял у него некоторые идеи(обрати внимание, Java был создан примерно за1 0 лет до C#).

На основе всего выше сказанного сделаемдиаграмму (рис. 1 ).

Рисунок 1

Обрати внимание на красную стрелку. Приописании взаимосвязи этих языков по типу"родитель-потомок" этой стрелки ты не увидишь.Я ее сам добавил. Почему? Да, потому чтонельзя недооценивать вклад Java в развитие иформирования C#. Меня иногда терзаютсмутные сомнения, а если бы не было Java, былли C#, и если да, то каким, каковы были бы егоособенности реализации, что он умел бы делать,а что нет. Ну, и все в этом духе (последниестрочки - сугубо мое личное мнение). Прошлоуже 1 0 лет с момента анонсирования первойверсии C#, последняя версия языка на данныймомент 4.0 (входит в поставку Visual Studio201 0). Мы имеем перед собой очень мощныйинструмент для разработки.

Перечислим его достоинства и особенности(лишь небольшую его часть):

1 . Межъязыковая возможность взаимодействия –позволяет разрабатывать крупные,распределенные программные системы;

2. Полная интеграция с Windows;

3. Встроенный язык интегрированных запросовLINQ;

4. Лямбда – выражения;

5. Поддержка параллельного программированияс помощью библиотеки распараллеливания

Кодинг

Page 12: VR-Online (February 2011)

1 2

vr-on l ine | февраль 201 1

Кодинг

задач TPL (но это уже больше относится к самойплатформе .NET Framework 4.0);

6. Параллельный LINQ (PLINQ);

7. Тесная связь с .NET Framework.

Этот список можно продолжать, но мыостановимся на этом. Язык C# широкоприменяется. Его используют при созданииWindows приложений, WEB приложений и даже вробототехнике. В общем, все зависит от твоейфантазии, а фантазия в свою очередь заперта врамках платформы Windows.

2. .NET – а ты кто?

Перед тем как перейти уже непосредственно кнашим заметкам, немного поговорим о .NET.Основное назначение .NET Framework – служитьсредой для разработки и выполнения сильнораспределенных компонентных приложений.

P.S. Тут у меня опять несколько мыслей поповоду появления на свет платформы .NET.Помнишь JVM, технологии NET Beans и ихреализацию сборки мусора, переносимости ит.д.? А что если, опять же, не было бы JVM, былли .NET? Что-то опять не туда полез, вернемся к.NET. Приведу несколько аббревиатур связанныхс .NET (и с которыми ты навернякастолкнетешься при изучении C# и .NET):

1 . CTS (Common Type System) – общая систематипов;

2. CLS (Common Language Specification) – общаяязыковая спецификация (если ты вдругнадумаешь создавать свой язык для платформы.NET, то он просто обязан соответствовать этойспецификации);

3. FCL (Framework Class Library) – библиотекаклассов платформы .NET;

4. CLR (Common Language Runtime) –общеязыковая среда выполнения (что-то типаJVM);

5. MSIL (Microsoft Intermediate Language) –промежуточный язык Microsoft (я бы назвал егоассемблер для .NET (если кому интересно, наwasm.ru есть цикл статей на эту тему));

6. IDL (Interface Definition Language) – языкопределения интерфейса;

7. UML (Unified Modeling Language) –унифицированный язык моделирования (это - неновинка от MS? ).

По сути, платформа .NET состоит из двух частей(эти 2-е части, являются ее "ядром"):

- Общеязыковая среда выполнения (CLR) –именно эта вещь позволяет сменить нам языкразработки на другой (к примеру, VB.NET) без"ущерба" для проекта;

- Библиотека классов (что-то типа API дляWindows) – с ней происходит основная работапри программировании наших приложений.

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

может выступать любая ОС.

Еще одна вещь, с которой ты наверняка (ненаверняка, а точно) столкнешься припрограммировании под .NET – это сборка(assembly). Сборка – это коллекция файлов,которая предстает перед программистом в видеединой библиотеки динамической компоновки(DLL) или исполняемого файла (EXE).

Ну, думаю на этом все. Пора переходить к нашимзаметкам.

3. С#. заметки

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

1 . Имя главной функции Main() в C# пишется сбольшой буквы в отличие от C++ (main());

2. Технически можно иметь несколько методовMain(), в этом случае с помощью параметракомандной строки /main необходимо сообщитькомпилятору C#, какой класс содержит методMain(), являющийся точкой входа в программу. Ябы не рекомендовал этого делать, так как этосоздает определенные неудобства припостоянной сборке программы, а также будетсложно разобраться в куче методов Main();

3. Используй конструкцию using в основном длявстроенных – стандартных пространств имен, адля сторонних (в том числе и своих) пишиполностью от и до все пространство имен. Чем-то using напоминает подключение модулей вDelphi (uses), только намного удобней и имеетнекую иерархическую структуру (System.math);

4. Все основные типы C# (int, float, char и тд.)отражаются на типы .NET (Int1 6, Single, Double итд.). (Замечание: а) char размер 2 байта, потому,что Unicode; б) bool принимает только false и true,никаких нулей и единиц);

5. Явное преобразование типов аналогичностарому стилю в C++, к примеру (int)myvar;

6. Осмысленный выбор типа переменнойизбавит тебя от будущих логических ошибок ипозволит сэкономить память. Например, если мыобъявляем переменную для возраста, то намхватит диапазона чисел из ushort, int в 4 байтадля этой переменной будет слишком жирно;

7. В отличие от C++ (выдается предупреждениеWarning) в C# нельзя использовать переменныебез их предварительной инициализации;

8. При разработке большой библиотеки классов(и не только) используй пространства именnamespace;

9. Используй #region и #endregion для выделениянекоторого кода в редакторе (код, вставленныймежду этих директив можно будет"сворачивать");

1 0. Используй директивы #define, #if, #endif, #el ifдля выборочной компиляции кода. Обычно такоеприменяется при отладке;

11 . В отличие от C++, C# не поддерживаетфайлы заголовков. Описание методов

Page 13: VR-Online (February 2011)

1 3

февраль 201 1 | vr-on l ine

встраивается в объявление класса. Напомню,что в C++ можно было отделить интерфейс классот его описания;

1 2. Создание экземпляра класса происходит так(пример): MyClass example=new MyClass(); -таким образом происходит вызов одного изконструкторов класс MyClass и выполняютсянеобходимые действия по инициализациикласса;

1 3. В отличие от C++ в C# каждый метод ипеременная в класс имеют модификатор private(необходимо явно указывать для каждого членакласса модификатор прав доступа);

1 4. Модификаторы прав доступа: а) private –закрытые, доступны только самому классу; б)public – открытые, никаких ограничений; в)protected – защищенные, используются толькосамим классом и производными от этого класса;г) internal – внутренние, доступ только классам всборке нашего класса; д) protected internal –защищенные-внутренние, доступ только классампроизводным от нашего и в одной сборке снашим;

1 5. Для ключевых слов можно использовать @для превращения их в идентификаторы – чего,конечно же, не стоит делать;

1 6. Старайся объявлять переменные в одномместе, а не разбрасывать их по всему коду, такбудет легче следить за ними;

1 7. Чтобы объявить тип decimal мало указать самтип, укажи для константы префикс m;

1 8. Старайся предварять литералы суффиксами(m, L, u и тд.), для обозначения их типа, чтобыпотом не мотать станицы кода и не искать типнашей переменной;

1 9. @ перед выводимой строкой, позволяетвоспринять ее буквально как есть (со всемипробелами, табами и тд.);

20. Используй xor для простой шифровкисообщений (пример num1 =mes1 ^mes2;num2=num1 ^mes2; здесь значение num2совпадет с mes1 );

21 . Распределяй классы по разным файлам –принцип модульности (облегчает модификацию исопровождение);

22. В C# не следует полагаться на деструктор(однако, по завершению программы он будетвыполнен), все делает сборка мусора;

23. Используй this для доступа к скрытымэкземплярам переменных класса (если у тебямного переменных с одни и тем же именем, чего

настоятельно не рекомендуется делать);

24. Ссылочные переменные передаются какссылки;

25. Используй модификатор ref для передачизначения как ссылки и out для возврата болееодного значения из метода;

26. Следи за всеми сообщениями во времякомпиляции и по возможности исправляй всеwarnin’ги и прочие мессаги (это позволитизбежать проблем в дальнейшем, а также можетпредотвратить некоторые скрытые ошибки вовремя эксплуатации программы);

27. Терминология: суперкласс или базовый класс– это наследуемый класс, а подкласс илипроизводный класс – это наследующий класс;

28. С# не поддерживает множественноенаследование, в отличие от C++;

29. Для доступа к скрытым переменным внекласса лучше всего использовать свойства (get{код для чтения поля;} set {код для измененияполя;});

30. C# позволяет нам возвращать массивы;

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

На этом мы, пожалуй, завершим нашеповествование о C#. Конечно, многие вещиостались за бортом. Это и события в C#,делегаты, исключительные ситуации,интерфейсы, опасный код и указатели, и многое-многое другое. Давай оставим это дляследующих статей, где по возможности мы болееподробно будем разбираться в этих темах.

4. Заключение

Ну что, вот мы и подошли к завершению нашейстатьи. Можно, конечно, долго беседовать овозможностях C#, об архитектуре .NET, но этотема другой статьи и даже не одной. Здесь мылишь вскользь коснулись платформы .NET исамого C#. Хочу также обратить твое внимание,что все написанное в "заметках" является лишьмоим мнением, результатом наблюдений,исследований и их не стоит принимать какединственно верные. Если у тебя естьзамечания, предложения по дополнениюсодержания статьи, обращайся(ghostrider.gu@gmail .com).

На этом, пожалуй, и завершим. ПОКА!

Кодинг

Page 14: VR-Online (February 2011)

1 4

vr-on l ine | февраль 201 1

C#. КриптографическиеалгоритмыАлгоритм выработки ключа стандарта RSA Data Security – PKCS#5

Автор: Evgenij | evgenij .minsk@gmail .com

В этой статье я хочу рассказать о двух алгоритмах выработки ключа шифрованияданных из пароля пользователя, определенных в стандарте фирмы RSA Data Security– PKCS#5. Вообще, задачи генерации, выработки и распределении ключейшифрования данных являются очень важными для организации защищенного каналамежду пользователями. Известны примеры, когда неправильное решение этих задачприводило к краху всей системы безопасности.

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

Стандарт PKCS#5 предлагает весьмаинтересный подход к решению задачи выработкиключа шифрования из пользовательскогопароля. За счет выбора параметров алгоритмаможно добиться того, что на среднем помощности компе эта процедура по времени будетзанимать, например, 1 секунду. Если хакервозьмется перебирать пароль по словарю, то дляперебора 1 00000 паролей ему придетсяпотратить 1 00000 секунд, то есть чуть большесуток, что для него, конечно, неприемлемо =)Заранее же составить таблицу с паролями исоответсвующими им ключами мешает «соль» –некоторое количество случайных данных,которые участвуют в процедуре выработки.

Все алгоритмы, которые мы будемреализовывать, описаны в PKCS #5v2.1 :"Password-Based Cryptography Standard".

В первую очередь подключим набор классов дляработы с криптографическими примитивами:

using System.Security.Cryptography;

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

Кодинг

Листинг 1.public static byte[ ] PBKDF1(byte[ ] salt,byte[ ] password, uint stepsNumber, uintreqKeyLength, HashAlgorithm hAlg)

{

if (reqKeyLength * 8 > hAlg. HashSize) throw

new ArgumentOutOfRangeException("derived

key too long" ) ;

byte[ ] hTemp = new byte[password. Length +

salt. Length] ;

Array. Copy(password, hTemp,

password. Length) ;

Array. Copy(salt, 0, hTemp, password. Length,

salt. Length) ;

for (uint i = 0; i < stepsNumber; i++)

{

hTemp = hAlg. ComputeHash(hTemp) ;

}

byte[ ] res = new byte[reqKeyLength] ;

Array. Copy(hTemp, res, reqKeyLength) ;

Array. Clear(hTemp, 0, hTemp. Length) ;

return res;

}

Как видим процедура довольно простая.Параметр stepNumber определяет количествоитераций алгоритма выработки. Чем больше этотпараметр, тем дольше по времени будетпроцедура. Параметр reqKeyLength определяетдлину ключа на выходе функции. hAlg – алгоритмхэширования. Из листинга видно, что итоговыйключ получается многократным хэшированиеммассива, содержащего пароль пользователя исоль.

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

Листинг 2public static byte[ ] PBKDF2(byte[ ] salt,byte[ ] password, uint stepsNumber, uintreqKeyLength, KeyedHashAlgorithm hAlg)

{

ulong cond = 1;

cond = ((cond << 32) - 1) * (ulong) hAlg.

HashSize;

if ( ( (ulong) reqKeyLength * 8) > cond)

throw new ArgumentException("

derived key too long" ) ;

uint blockLength = (uint) (hAlg.

HashSize / 8) ;

uint numBlocks = (uint) (reqKeyLength /

(float) blockLength) ;

Page 15: VR-Online (February 2011)

1 5

февраль 201 1 | vr-on l ine

uint resBlock = (uint) (reqKeyLength -

numBlocks * blockLength) ;

if (resBlock ! = 0) numBlocks += 1;

byte[ ] resKey = new byte[reqKeyLength] ;

byte[ ] intermBlock;

for (uint i = 0; i < numBlocks; i++)

{

intermBlock = F(password, salt,

stepsNumber, i + 1, hAlg) ;

if (i + 1 ! = numBlocks)

{

Array. Copy(intermBlock, 0, resKey,

i * blockLength, blockLength) ;

}

else{

if (resBlock ! = 0) Array. Copy(

intermBlock, 0, resKey,

i * blockLength, resBlock) ;

else Array. Copy(intermBlock, 0,

resKey, i * blockLength,

blockLength) ;

}

}

return resKey;

}

private static byte[ ] F(byte[ ] password,byte[ ] salt, uint numberOfIterations, uintblockNumber, KeyedHashAlgorithm hAlg)

{

byte[ ] accumulator = Ufirst(password,

salt, blockNumber, hAlg) ;

byte[ ] resTmp = accumulator;

for (uint i = 1; i < numberOfIterations;

i++)

{

resTmp = Uintermadiate(password,

resTmp, hAlg) ;

ArraysXOR(accumulator, accumulator,

resTmp) ;

}

return accumulator;

}

private static byte[ ] Ufirst(byte[ ] password,byte[ ] salt, uint i, KeyedHashAlgorithm hAlg)

{

byte[ ] hTemp = new byte[ salt. Length + 4] ;

Array. Copy(salt, hTemp, salt. Length) ;

hTemp[ salt. Length] = (byte) ( (i >> 24) &

0xff) ;

hTemp[ salt. Length + 1] = (byte) ( (i >> 16) &

Вторая функция PBKDF2 вырабатывает ключ изпароля пользователя поблочно. Прииспользовании такого подхода можно получатьключи очень большой длины. По сравнению спервой функцией в идейном плане мало чтоизменилось – опять используется многократноехэширование соли и пароля, но в этом вариантедля каждого блока в алгоритме выработкиучаствует еще и его номер. Также в отличие отпервого подхода здесь в качестве алгоритмахэширования используется ключевая хэш-функция (класс KeyedHashAlgorithm), в которойв роли ключа выступает пользовательскийпароль. Кстати, алгоритм спороектирован так,чтобы недопускать распараллеливание (смотриреализацию функции F).

Вот и все. Как использовать эти функции смотрив исходниках, прилагаемых к журналу. Взаключение хочу отметить, что этот подходиспользуется повсеместно и практически во всехкриптографических программах, которыеиспользуют пользовательские пароли (например,TrueCrypt) и доставляет много головной боликриптоаналитикам и просто кул-хакерам,решившим заняться получением данных иззащищенных хранилищ.

Кодинг

0xff) ;

hTemp[ salt. Length + 2] = (byte) ( (i >> 8) &

0xff) ;

hTemp[ salt. Length + 3] = (byte) (i & 0xff) ;

hAlg. Key = password;

byte[ ] res = hAlg. ComputeHash(hTemp) ;

Array. Clear(hTemp, 0, hTemp. Length) ;

return res;

}

private static byte[ ] Uintermadiate(byte[ ]password, byte[ ] Uprev, KeyedHashAlgorithmhAlg)

{

hAlg. Key = password;

return hAlg. ComputeHash(Uprev) ;

}

private static void ArraysXOR(byte[ ] res,byte[ ] first, byte[ ] second)

{

if ( ! (res. Length == first. Length) &&

(res. Length == second. Length) ) throw

new ArgumentOutOfRangeException("

All arrays length must be equal" ) ;

or (uint i = 0; i < res. Length; i++)res[ i] = (byte) (first[ i] ^ second[i] ) ;

}

Page 16: VR-Online (February 2011)

1 6

vr-on l ine | февраль 201 1

Кодинг: C#создаем "отзывчивые" приложения

Автор: Поротников Андрей aka wwwnet

В чем удобство однопоточного программирования? В том, что не нужнозадумываться о синхронизации потоков, код получается намного проще и понятнее.Но есть один существенный минус такого подхода в приложениях с графическиминтерфейсом пользователя (ГУЕм) - при выполнении продолжительной работы окнопрограммы перестает отвечать на действия пользователя. У пользователя возникаетощущение, что приложение зависло и не выполняет никакой полезной работы.

Что делать в данном случае? В данной статье ярасскажу, как создавать приложения, у которыхне будет в заголовке окна возникать надпись "(Неотвечает)". Примеры будут на C#. В статье будутрассмотрены такие вопросы, как созданиемногопоточных приложений, использованиеделегатов, взаимодействие с элементами формыиз различных потоков.

Реализация

Для того, чтобы продемонстрировать какработать с многопоточным приложением,требуется какая-либо задача, выполняющаясязначительное время. Для примера возьмемзадачу загрузки в компонент ListView файлов,расположенных в определенной директории.Сам процесс получения имен файловвыполняется моментально, а загрузка его вListView как раз - то, что нужно. Поэтому формабудет выглядеть так, как показано на рисунке 1 .

Как видно, на форме расположен компонентTextBox для задания директории, из которойполучаем список файлов (по умолчанию этоC:\Windows\System32), Button "Файлы" длязапуска процесса, ListView для загрузки названий

файлов, ProgressBar для отображения ходапроцесса и Button "Отмена". При запускеприложения кнопка "Отмена" невидима. Еесвойство VIsible становится равным true когдазапускается процесс перечисления файлов ивозвращается в состояние false при завершениипроцесса или же при его отмене.

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

Кодинг

Рисунок 1. Форма приложения

Листинг 1. Требуемые простанства именusing System;

using System. Linq;

using System. Windows. Forms;

using System. IO;

using System. Threading;

Затем в классе формы определяем требуемыеобъекты, как показано в листинге 2.

Листинг 2. Объявление объектовprivate delegate void AddToLV(stringfileName) ;

private Thread newTh;

Зачем нужна вторая переменная, я думаю,понятно. С помощью нее мы будем работать спотоком, в котором будут осуществлятьсяпродолжительные по времени операции. Нозачем нам нужен делегат? Об этом чуть позже.

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

Листинг 3. Процедура для создания потокаprivate void WriteFiles(obj ect _files)

{

FileInfo[ ] files = (FileInfo[ ] ) _files;

foreach (FileInfo fi in files)

{

PutInLV(fi. Name) ;

}

}

Сам же поток создается при нажатии кнопки"Файлы", как показано в листинге 4

Page 17: VR-Online (February 2011)

1 7

февраль 201 1 | vr-on l ine

Листинг 4. Процедура нажатия кнопки "Файлы"private void btnGet_Click(obj ect sender,EventArgs e)

{

DirectoryInfo di = new DirectoryInfo(

txtPath. Text) ;

if ( ! di. Exists)

{

MessageBox. Show("Указанной

директории не существует! " ) ;

return;

}

btnCancel. Visible = true;

FileInfo[ ] fi = di. GetFiles( ) ;

progressBar1. Maximum = fi. Count( ) ;

progressBar1. Value = 0;

lvFiles. Items. Clear( ) ;

newTh = new Thread(newParameterizedThreadStart(WriteFiles) ) ;

newTh. Start(fi) ; }

оператору обращаться к методу invoke во времявызовов метода из элемента управления, так каквызывающий оператор находится не в томпотоке, в котором был создан элементуправления. Проще говоря, если вызовпроцедуры идет из нашего рабочего потока, товыполняется блок кода, стоящий после if, в иномслучае выполняется код после else. В этомсамом коде происходит добавление элемента вListView, увеличивается значение счетчикапрогресс бара и если текущий счетчик равенмаксимальному значению, значит потоквыполнил свою работу, и можно скрыть кнопкуотмены. В конце процедуры мы отрисовываемзаного компонент ListView, чтобы пользовательувидел уже добавленные нами файлы.

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

Кодинг

Как видно из кода, вначале идет проверка,существует ли указанная директория. Если еенет, то выводится сообщение и происходитвыход из процедуры. Если же папка есть, токнопка отмены становится видимой, в объект fiзагружается список файлов из этой директории,прогресс бару назначается максимальноезначение, равное количеству файлов,устанавливается текущее положение в 0,очищается компонент ListView и наконецсоздается новый поток с указанием напроцедуру, показанную в листинге 3.

Что же делает созданный поток?

Для каждого файла из переданного в качествеаргумента массива вызывает другую процедуру.Что это за процедура? Она показана в листинге5.

Листинг 5. Процедура заполнения ListViewprivate void PutInLV(string fileName)

{

if (lvFiles. InvokeRequired)

{

AddToLV add = new AddToLV(PutInLV) ;

this. Invoke(add, new obj ect[ ] {fileName } ) ;

}

else{

lvFiles. Items. Add(fileName) ;

progressBar1. Value++;

if (progressBar1. Value ==progressBar1. Maximum)

btnCancel. Visible = false;

lvFiles. Refresh( ) ;

}

}

Так как в рабочем потоке мы обращаемся ккомпоненту ListView, созданном в другом потоке,напрямую получить доступ к нему мы не сможем.Тут нам и пригодится делегат, созданный всамом начале. При выполнении процедурысначала проверяется свойство InvokeRequiredкомпонента ListView. Согласно MSDN, свойствоInvokeRequired позволяет получать значение,показывающее, следует ли вызывающему

Рисунок 2. Окно работающего приложения

Ну, и, наконец, осталось рассмотреть толькопроцедуру, вызываемую кнопкой отмены (Листинг6).

Листинг 6. Кнопка отменыprivate void btnCancel_Click(obj ect sender,EventArgs e)

{

if (newTh. IsAlive)newTh. Abort( ) ;

btnCancel. Visible = false;

}

Здесь все просто - если поток существует, мызавершаем его, вызвав его метод Abort(). Затемкнопка становится невидимой.

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

Листинг 7. Закрытие окнаprivate void frmMain_FormClosing(obj ectsender, FormClosingEventArgs e)

{

if (newTh ! = null)

if (newTh. IsAlive)newTh. Abort( ) ;

}

Page 18: VR-Online (February 2011)

1 8

vr-on l ine | февраль 201 1

Кодинг

Здесь все практически так же, как и в процедуре,вызываемой на событие нажатия кнопки отмены.Единственное, добавляется проверка нанеравенство объекта, представляющего поток,значению null . Причем интересно, что если этупроверку убрать, то при попытке закрыть форму,когда newTh == null , исключение не возникает.

Итог

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

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

И напоследок для тех, кто хочет узнать побольшепро работу с потоками средствами C#, могупорекомендовать отличную статью, доступную вИнтернете по адресуhttp: //www.rsdn.ru/article/dotnet/CSThreading1 .xml.

Page 19: VR-Online (February 2011)

1 9

февраль 201 1 | vr-on l ine

C#. Нереляционный скульЗнакомимся с MongoDB

Автор: Евгений Шапиро | [email protected]

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

Не всю жизнь же сидеть на традиционных MySQL или MS SQL.

Пора попробовать что-то новенькое. Вперед!

Начало начал

Ты, наверное, уже читал сотни раз, что в крупныхпроектах, типа Google, Яндекс или ВКонтакте неиспользуются традиционные реляционные базыданных, типа MySQL и/или MS SQL (во всякомслучае, в основных сервисах). Конечно же, тамсвои разработки, которые пока закрыты отобщественного взгляда. Но и мы с тобой можемвзять какую-нибудь необычную базу данных ипопробовать сделать что-нибудь быстрое имасштабируемое. Как пример, предлагаюостановиться на MongoDB.

Это кросс-плотформенная БД, написанная наС++, распространяющаяся по лицензии GNUAGPL v3.0. Она является представителемдокументно-ориентированных БД, т.е. главнымобъектом в ней является документ и наборы этихдокументов.

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

Формат документа не структурирован, т.е. можнохранить записи любого вида. В MongoDB всехранится в виде BSON — двоичномнадмножестве JSON (кстати, о JSON можнопрочитать в моей статье про взаимодействие спереводчиком от Google в прошлом номере), т.е.можно хранить файлы, фотографии, любыедвоичные данные.

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

{ "_id": "4d1 87b7f01 0c8d0900000001 ","firstname": "Ivan", "lastname": "Ivanov", "age":40 }

Видно, что запись содержит уникальный _id, атакже имя, фамилию и возраст человека. _id , какты видишь, содержит строку, очень похожую нахеш. Еще, в качестве примера (для лучшего

понимания структуры записей) можно провестианалогию с любым документом Word на твоемкомпьютере. Имя файла (полное, вместе спутем) - это его ключ, а содержание документа -значение.

Надо сказать, что MongoDB довольно молодаяразработка, так что периодически в нейобнаруживаются ошибки. Бояться не стоит,разработчики держат руку на пульсе и в новыхверсиях стабильно закрывают бреши.

Поехали!

На данный момент я просто хочу познакомитьтебя с основами работы с MongoDB. Мы небудем заморачиваться над слишком сложнымпроектом, а создадим некий аналог сервисастатусов из ВКонтакте. Я разбил работу на 2небольшие статьи. В этой части я расскажу онастройке MongoDB для работы и спроектируюприложение, а весь функционал вынесу вовторую.

Система статусов. Часть 1

Итак, у нас будет 2 документа (как ты помнишь,Mongo оперирует документами, а не таблицами):

1 . Пользователи. В нем мы будем хранить ФИОпользователя, дату рождения и датурегистрации. Пока хватит.

2. Статусы. Тут все просто: ссылка напользователя в первом документе и сам статус,который будет представлять собой строку.

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

Писать пример мы будем на C#, поэтому нампонадобиться сама Mongo+коннектор для .NET.Архив с Mongo и драйвер ищи в архиве сисходниками. Начинаем все это разворачиватьна своей машине.

Архив с MongoDB содержит папку bin, а в нейуже лежат нужные нам файлы, в частности,mongod.exe.

Кодинг

Page 20: VR-Online (February 2011)

20

vr-on l ine | февраль 201 1

Кодинг

Именно этот бинарник и является сердцемMongo. Распакуем архив в C:\mongodb, затем вкорне диска «C» создадим папку «C:\db»,вкоторой будут храниться данные. Теперьзапустим mongod из командной строкиследующим образом:

C:\mongodb\bin\mongod –dbpath C:\db

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

2. Status. Информация о каждом статусе вотдельности, с указанием кода пользователя,которому он принадлежит (см. листинг 2).

Рисунок 1. Условная схема БД

Рисунок 2. MongoDB успешно стартовал

Остановить его можно нажатием Ctrl+C, но покамы этого делать не будем. Теперь нам осталосьподключить нужные библиотеки к VisualStudio,чтобы подружить ее с MongoDB. Для этого мыраспаковываем архив c MongoDBDriver идобавляем ссылки на библиотекиMongoDB.Driver.dl l и MongoDB.Linq.dl l .Последним штрихом будет подключениеnamespace’ов в самом коде.using MongoDB. Driver;using MongoDB. Linq;

Проектируем

Ну, вроде со всей этой настроечной волокитойразобрались, теперь можно заняться делом. Длянаглядности, а также соблюдения принциповООП, предлагаю создать в нашем приложении 3класса:

1 . User. Класс будет содержать всю информациюоб одном пользователе (см. листинг 1 )

Листинг 1. Описание класса Userclass User

{

public string Id { get; set; }

public string FIO { get; set; }

public DateTime BirthDay { get; set; }

public DateTime RegisterDate{ get;set; }

}

Листинг 2. Описание класса Statusclass Status

{

public string Id { get; set; }

public string IdUser { get; set; }

public string Name { get; set; }

}

3. DBHelper. Отвечает за работу с БД:подключение/отключение от базы, добавление,удаление, изменение информации. Я его сделалстатическим, чтобы была возможность несоздавать его экземпляр, а сразу обращаться кметодам (см. листинг 3).

Листинг 3. Класс-помощник для работы с БДstatic class DBHelper

{

/// <summary>

/// Ссылка на открытое подключение

/// к MongoDB

/// </summary>

private static Mongo db;

private static bool ConnectToMongo( ) ;

private static boolDisconnectWithMongo( ) ;

public static string InsertUser(refUser user) ;

public static bool UpdateUser(refUser user) ;

public static bool DeleteUser(stringId) ;

public static string InsertStatus(refStatus status) ;

public static boolDeleteStatus(string Id) ;

public static bool FindUserById(string Id,ref User user) ;

public static List<Status>FindAllStatusUser(string Id) ;

}

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

Система статусов. Часть 2

Основной функционал по работе с Mongo у насбудет воплощен в классе DBHelper, поэтому япредлагаю потихоньку начать его реализовыватьи сразу разбираться с принципами работыMongo. Я буду писать комментарии прямо в коде.Их будет вполне достаточно для понимания сутипроисходящего. Начнем с подключения к БД (см.листинг 4).

Листинг 4. Подключаемся к БДprivate static bool ConnectToMongo( )

{

db = new Mongo( ) ;

try

{

///Делаем попытку подключения

db. Connect( ) ;

Page 21: VR-Online (February 2011)

21

февраль 201 1 | vr-on l ine

///если все ок, возвращаем true

return true;

}

catch(Exception)

{

///иначе -false

///для проcтоты сделана

///такая "тупая" обработка

///ошибки

return false;

}

}

Как ты помнишь, db-это у нас подключение кMongo, test в данном контексте - имя БД, а users-набор документов - пар ключ-значение. И когдамы обращаемся к данной БД и набору, еслитаковых еще нет в хранилище, то Mongo создастих автоматически. Процедуры по обновлению иудалению пользователя также, думаю, вполнепонятны (см. соответствующие листинги).

Кодинг

Код отключения от БД я привел в листинге 5.

Листинг 5. Отключение от БДprivate static bool DisconnectWithMongo( )

{

try

{

db. Disconnect( ) ;

return true;

}

catch (Exception) { return false;}

}

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

Листинг 6. Добавление нового пользователя вБДpublic static void InsertUser(ref User user)

{

///подключаемся к БД

ConnectToMongo( ) ;

///сздаем новый документ

var docuser = new Document( ) ;

///генерируем заранее его _id

user. Id =Oid. NewOid( ) . ToString( ) ;

///заполняем все поля

docuser[«_id»] = user. Id;

docuser[ “FIO”] = user. FIO;

docuser[ “BirthDay”] =user. BirthDay;

docuser[ “RegisterDate”] =DateTime. Now;

///вставляем новый документ в БД

db[ “test”] [ “users”] . Insert(docuser) ;

///отключаемся от БД

DisconnectWithMongo( ) ;

}

Как видно, в коде мы сами генерируем _id новойзаписи. Не знаю почему, но у меня почему-топоиск по _id не работал. Если я делал вставкузаписи, а потом брал ее _id, сгенерированныйуже базой и по нему осуществлял поиск. А вот,если я сначала сгенерировал _id, потом вставилзапись, и уже только потом делал поиск по этому_id, то он мне выдавал вставленную запись безпроблем.

Теперь второй момент. Для вставки записи, яиспользую объект db[“test”][“users”].

Листинг 7. Обновление информации опользователе/// <param name="user">

/// Ссылка на объект класса User

/// </param>

public static void UpdateUser(ref User user)

{

ConnectToMongo( ) ;

var docuser = new Document( ) ;

docuser[ "_id" ] = user. Id;

docuser[ "FIO" ] = user. FIO;

docuser[ "BirthDay" ] = user. BirthDay;

///обновляем запись, которая

///соответствует указанному _id

db[ "test" ] [ "users" ] . Update(docuser) ;

DisconnectWithMongo( ) ;

}

Листинг 8. Удаление информации о пользователе/// <param name="Id">

/// в качестве параметра передаем Idюзера

/// </param>

public static void DeleteUser(stringId)

{

ConnectToMongo( ) ;

var docuser = new Document( ) ;

///заполняем _id и удаляем запись

docuser[ "_id" ] = Id;

db[ "test" ] [ "users" ] . Delete(docuser) ;

DisconnectWithMongo( ) ;

}

Теперь разберем работу со статусами. Тут, впринципе, все то же самое, за исключением того,что работа выполняется не с наборомdb["test"]["users"], а db["test"]["statuses"]. Итак, коддобавления нового статуса я привел в листинге9, а удаление статуса приведено в листинге 1 0.

Листинг 9. Добавление нового статуса/// <param name="status">

/// Ссылка на объект Status

/// </param>

public static void InsertStatus(ref Statusstatus)

{

ConnectToMongo( ) ;

var docstatus = new Document( ) ;

docstatus[ "idUser" ] = status. IdUser;

docstatus[ "Name" ] = status. Name;

db[ "test" ] [ "statuses" ] . Update(docstatus) ;

DisconnectWithMongo( ) ;

}

Листинг 10. Удаление статуса/// <param name="Id">Id статуса</param>

Page 22: VR-Online (February 2011)

22

vr-on l ine | февраль 201 1

Кодинг

public static void DeleteStatus(string Id)

{

ConnectToMongo( ) ;

var docstatus = new Document( ) ;

docstatus[ "_id" ] = Id;

db[ "test" ] [ "statuses" ] . Delete(docstatus) ;

DisconnectWithMongo( ) ;

}

Листинг 12. Считывание всех статусовпользователяpublic static List<Status>FindAllStatusUser(string Id)

{

List<Status> res=new List<Status>( ) ;

ConnectToMongo( ) ;

ICursor status =db[ "test" ] [ "statuses" ] . Find(

new Document( ) . Append("idUser" , Id) ) ;

foreach (var s in status. Documents)

{

res. Add(newStatus( ) { IdUser=s[ "idUser" ] . ToString( ) , Name=s[ "Name" ] . ToString( ) } ) ;

}

return res;

}

Процедуру обновления статуса я делать не стал,т.к. , не вижу в ней особого смысла. Но, если тызахочешь сделать, я думаю, проблем у тебя невозникнет. Мне осталось продемонстрироватьеще 2 метода. Это поиск информации опользователе, а также считывание всех егостатусов по строке с его _id (см. соответ.листинги).

Листинг 11. Поиск пользователя по _id/// <param name="Id">Id пользователя</param>

/// <param name="user">В этот объект будетзаписана

/// полученная информация

/// </param>

/// <returns></returns>

public static bool FindUserById(string Id,ref User user)

{

ConnectToMongo( ) ;

user. Id = Id;

var resultuser = db[ "test" ] [ "users" ] .

FindOne(new Document( ) . Append("_id" ,user. Id. ToString( ) ) ) ;

if (resultuser==null)

{

DisconnectWithMongo( ) ;

return false;

}

user. FIO=resultuser[ "FIO" ] . ToString( ) ;

user. BirthDay =Convert. ToDateTime(resultuser[ "BirthDay" ] . ToString( ) ) ;

user. RegisterDate =Convert. ToDateTime(resultuser[ "RegisterDate" ]. ToString( ) ) ;

Эпилог

Теперь ты можешь, используя эти классы,сделать свой небольшое приложение(консольное, winforms или WPF) для работы сMongoDB. Только не забывай о запуске сервераБД и подключения необходимых библиотек. Еслибудут вопросы –пиши. Удачи!

Полезные ссылки

http: //www.mongodb.org/ - официальный сайтMongoDB.

http: //msdn.microsoft.com/ru-ru/magazine/ee31 0029.aspx ,

http: //msdn.microsoft.com/ru-ru/magazine/ff71 4592.aspx ,

http: //msdn.microsoft.com/ru-ru/magazine/ff798277.aspx - отличный цикл статейНА РУССКОМ ЯЗЫКЕ про Mongo. Очень помогпри подготовке статьи.

DisconnectWithMongo( ) ;

return true;

}

Page 23: VR-Online (February 2011)

23

февраль 201 1 | vr-on l ine

Кодинг: C#NHIBERNATE и C#

Автор: Евгений Шапиро | [email protected]

После написания статьи про работу с MySQL из C# (http: //www.vr-online.ru/content/c-uchimsja-rabotat-s-mysql-2858 ), один из посетителей справедливо заметил, что можноработать с MySQL, используя mysql-connector.

Я сначала хотел осветить этот момент, решил пойти дальше. В сегодняшней статье яразберу тот же телефонный справочник, но в этот раз код будет чист от языка SQL.Да-да, ты не ошибся.

А можно подробнее

Весь фокус заключается в использованиитехнологии ORM (Object-Relational Mapping).Благодаря ей, мы можем отображать объектышарпа на реляционную базу данных. Т.е. ,например, описать класс Person и отобразитьего на таблицу Person в MySQL и ORM самаразберется, какие запросы надо отправлять длявыборки, сохранения, обновления и удаления. Аты себе спокойно занимайся проектированиемкласса, тестированием модулей и т.д. Ну некрасота ли?

ORM’ов много всяких есть, но в рамках даннойстатьи я рассмотрю NHibernate. Это вариант ужедавно зарекомендовавшей себя ORM системыHibernate (которая, в свою очередь, большезаточена под Java) для .NET.

Немного расскажу, чем же мы сегодня конкретнозаймемся (я имею в виду, в статье). Нампридется реализовать работу нашеготелефонного справочника из предыдущей статьи(ссылку см. выше) с учетом возможностейNHibernate. Предлагаю следующий план работы:

1 . Рассмотрим структуру справочника.

2. Опишем классы, которые будем связывать стаблицами БД.

3. Разберемся с настройкой нашего приложениядля работы с NHibernate.

4. Поглядим на процедуру отображения классовБД.

5. Реализуем класс-оболочку для работы с БД изнашего приложения.

Структурируем

Наш справочник будет иметь следующуюструктуру:

1 . Список контактов, с указанием ФИО и датырождения.

2. Перечень типов информации, которые могут

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

3. Непосредственно сам справочник, соссылками на таблицу контактов, типовинформации, а также значением этойинформации.

Чтобы стало понятнее, объясню на примере. Втаблице “Abonents” хранится запись “ИвановИван Иванович, 1 .1 .1 970 г.р.” (запись, конечноже, разбита на колонки, но я демонстрируюобщий смысл). В таблице “TypeInfo”-запись“Мобильный”, а в таблице “Contacts” всесобираем воедино - “Иванов Иван Иванович,1 .1 .1 970 г.р. (idAbonent), 891 25476396,мобильный (idTypeInfo)”.Вот как эта схемавыглядит графически (см. рисунок 1 ).

Кодинг

Рисунок 1. Схема БД

Строим классы

В нашем приложении будет 4 вспомогательныхкласса, три из них будут нужны для связи стаблицами БД, а четвертый будет представлятьсобой “хелпер”, оболочку для работы с БД изосновного кода приложения. Последний классмы отложим на потом, а сначала рассмотрим трикласса для таблиц. Каждый класс представляеттип записи, хранящийся в конкретной таблице.

1 . Класс Abonent- таблица Abonents (см. листинг1 );

Page 24: VR-Online (February 2011)

24

vr-on l ine | февраль 201 1

Кодинг

Листинг 1. Класс Abonentpublic class Abonent

{

public virtual int Id

{ get; set; }

public virtual String FIO

{ get; set; }

public virtual DateTime BirthDay

{ get; set; }

}

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

Чтобы подключить к нашему приложениюNHibernate выберем в меню VisualStudio«Проект»-> «Добавить новый элемент» (у менярусская VS201 0, так что пишу, как у меня). Тамвыберем XML файл и назовем его«hibernate.cfg.xml». Именно в файле с такимназванием NHibernate (по умолчанию) ищет своинастройки. В нем должен быть следующий текст(см. листинг 4).

2. Класс TypeInfo - таблица TypeInfo (см. листинг2);

Листинг 2. Класс TypeInfopublic class TypeInfo

{

public virtual int Id

{ get; set; }

public virtual String Name

{ get; set; }

}

3. Класс PhoneBook- таблица Contacts (см.листинг 3);

Листинг 3. Класс PhoneBookclass PhoneBook

{

public virtual int Id

{ get; set; }

public virtual Abonent abon

{ get; set; }

public virtual string Value

{ get; set; }

public virtual TypeInfo info

{ get; set; }

}

С описанием классов, я думаю, все понятно.Классы Abonent и TypeInfo объявленыпубличными для корректной работы классаPhoneBook , который на них ссылается. Ещенадо отметить, что все свойства являютсявиртуальными - это требование NHibernate.

NHibernate

Ну вот, наконец-то, можно приступить к самомуинтересному: «ковырянию» NHibernate. Дляначала нам надо его скачать и установить. Наофициальном сайте http: //www.hibernate.org , намомент написания статьи, сама свежая версиябыла под номером 3.6.0. Скачиваем себе архив ираспаковываем.

Для того чтобы мы могли использовать в своемпроекте NHibernate, нам надо добавить ссылкина библиотеки NHibernate.dl l иNHibernate.ByteCode.Castle.dl l . Остальныебиблиотеки тоже должны лежать в одномкаталоге с приложением. Еще момент. Мы будемработать с MySQL, поэтому нам понадобитьсяmysql connector net. Его забираем отсюдаhttp: //dev.mysql.com/downloads/connector/net . Длятого, чтобы использовать его в своемприложении, нам надо подключить библиотекуMySQL.Data.dl l .

Вообще, я тебе советую с библиотеками пока не

Листинг 4. hibernate. cfg. xml<?xml version="1. 0" encoding="utf-8"?>

<hibernate-configurationxmlns="urn: nhibernate-configuration-2. 2">

<! -- настройки "фабрики"-сессий -->

<session-factory> ]

<! --настрйоки по умолчанию-->

<propertyname="proxyfactory. factory_class">

NHibernate. ByteCode. Castle. ProxyFactoryFactory, NHibernate. ByteCode. Castle

</property>

<property name="connection. provider">

NHibernate. Connection. DriverConnectionProvider

</property>

<! --драйвер для работы с БД-->

<property name="connection. driver_class">

NHibernate. Driver. MySqlDataDriver

</property>

<! --строка подключения к БД-->

<propertyname="connection. connection_string">

Server=localhost; Database=test; UserID=root; Password=1;

</property>

<! --диалект (в нашем случае MuSQL5) -->

<propertyname="dialect">NHibernate. Dialect. MySQL5Dialect</property>

<! --это свойство понадобиться, если мызахотим ,

чтобы sql-скрипт создания БД былскопирован в файл.

Т. е. первый аргумент в ф-ииschemaExport. Execute

равен true

-->

<property name="show_sql">true</property>

</session-factory>

</hibernate-configuration>

Проверь, чтобы в свойствах этого файла былиследующие параметры (чтобы просмотретьсвойства, надо в «Обозревателе решений»кликнуть на нужный файл) (см. рисунок 2):

1 . «Действие при построении» : «Нет».

2. «Копировать в выходной каталог»: «Всегдакопировать».

Гляжусь в тебя, как в зеркало

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

Page 25: VR-Online (February 2011)

25

февраль 201 1 | vr-on l ine

хранятся в отдельном xml-файле с именем«имя_класса.hbm.xml».

<class name="Abonent" table="Abonents"lazy="false">

<! --свойство класса Id связываем со

столбцом idAbonents.

Тип столбца "int" , значениегенерируется автоматически

-->

<id name="Id" column="idAbonents"type="int">

<generator class="native"></generator>

</id>

<! --св-во FIO класса связываем состолбцом FIO

Тип столбца VARCHAR(45)

-->

<property name="FIO" column="FIO"type="String" length="45"/>

<! --св-во BirthDay класса связываем состолбцом BirthDay

Тип столбца DATE

-->

<property name="BirthDay"column="BirthDay" type="Date"/>

</class>

</hibernate-mapping>

Кодинг

Рисунок 2. Свойства файла «hibernate. cfg. xml»

У нас всего 3 класса, для каждой из 3 таблиц;комментарии я буду приводить прямо в файле,их будет достаточно для понимания кода.

1 . «Abonent.hbm.xml». Как понятно из названияфайла, в нем мы опишем отображение классаAbonent (см. листинг 5);

Листинг 5. Файл «Abonent. hbm. xml»<?xml version="1. 0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn: nhibernate-mapping-2. 2"

assembly="NHibernateSimple"

namespace="NHibernateSimple">

<! --указываем имя класса, которыйотображаем

и название, в которую таблицы.

Здесь (как и в др. файлах) мы спец.устанавливаем атрибут lazy="false"

(по умолчанию равен true) , чтобы объект

данного класса создавался сразу. Еслиlazy="true" , то объект

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

Класс Abonent отображаем на таблицуAbonents

-->

2. «TypeInfo.hbm.xml» (см. листинг 6);

Листинг 6. «TypeInfo. hbm. xml»<?xml version="1. 0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn: nhibernate-mapping-2. 2"

assembly="NHibernateSimple"

namespace="NHibernateSimple">

<! --

Класс TypeInfo отображаем на таблицуTypeInfo

-->

<class name="TypeInfo" table="TypeInfo"lazy="false">

<! --свойство класса Id связываем со

столбцом idTypeInfo.

Тип столбца "int" , значениегенерируется автоматически

-->

<id name="Id" column="idTypeInfo"type="int">

<generator class="native"></generator>

</id>

<! --св-во Name класса связываем состолбцом Name

Тип столбца VARCHAR(45)

-->

<property name="Name" column="Name"type="String" length="45"/>

</class>

</hibernate-mapping>

3. «PhoneBook.hbm.xml». Этот класс немногоотличается от двух предыдущих тем, что онсодержит ссылки на первые 2 таблицы. И этодолжно быть отображено в данном файле (см.листинг 7);

Листинг 7. «PhoneBook. hbm. xml»<?xml version="1. 0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn: nhibernate-mapping-2. 2"

Page 26: VR-Online (February 2011)

26

vr-on l ine | февраль 201 1

Кодинг

assembly="NHibernateSimple"

namespace="NHibernateSimple">

<! --

Класс PhoneBook связываем с таблицейContacts.

-->

<class name="PhoneBook" table="Contacts"lazy="false">

<id name="Id" column="idContacts"type="int">

<generator class="native"></generator>

</id>

<property name="Value" column="Value"type="String" length="45"/>

<! --

Свойство класса abon отображаются настолбец idAbonent, который

связывает данный класс с классом Abonent.Связь многие-к-одному, т. е.

таблица Contacts может содержать многозаписей, ссылающихся на одну

и туже запись из таблицы Abonents.

-->

<many-to-one name="abon"column="idAbonent" not-null="true"class="Abonent"/>

<! --

Свойство класса info отображаются настолбец idTypeInfo, который

связывает данный класс с классомTypeInfo. Связь многие-к-одному, т. е.

таблица Contacts может содержать многозаписей, ссылающихся на одну

и туже запись из таблицы TypeInfo.

-->

<many-to-one name="info"column="idTypeInfo" not-null="true"class="TypeInfo"/>

</class>

</hibernate-mapping>

Листинг 8. Конфигурирование и создание БД/// <summary>

/// Объект-сессия работы с БД

/// Создание объекта ISessionFactory-трудоемкий процесс,

/// поэтому будем создавать егозаранее и сипользовать по

/// ходу работы приложения

/// </summary>

private static ISessionFactorysessions;

/// <summary>

/// Конфигурируем подключениеNHibernate к MySQL

/// </summary>

public static void Configure( )

{

///конфигурируем NHiberbate

sessions = newConfiguration( ) . Configure( ) .

///тут жеуказываем, что надо

Чтобы отображение происходило корректно, длявсех 3 файлов надо указать следующие свойства(см. рисунок 3):

1 . «Действие при построении»: «Внедренныйресурс»

2. «Копировать в выходной каталог»: «Всегдакопировать»

Красивая обертка

Теперь рассмотрим класс (DBHelper), которыйбудет реализовывать основной функционал поработе с БД. Первые 3 класса, как ты помнишь,просто описывали структуру хранения данных,но функционала никакого не содержали. Этот жекласс будет отвечать за создание БД (да-да,NHibernate сам создаст все таблицы, никакихCREATE TABLEa), просмотр, добавление,удаление информации. Для простоты работы склассом сделаю его статическим. Я разобьюлистинг на несколько частей, каждая из которыхбудет реализовывать свой небольшойфункционал. Первая часть отвечает законфигурирование подключения NHibernate исоздание БД (см. листинг 8).

Рисунок 3. Настраиваем свойства файлов

Page 27: VR-Online (February 2011)

27

февраль 201 1 | vr-on l ine

///отразить (смаппить) наши классы

AddClass(typeof(Abonent) ) .

AddClass(typeof(TypeInfo) ) .

AddClass(typeof(PhoneBook) ) .

///вызываем"фабричный метод" для создания сессии

BuildSessionFactory( ) ;

}

/// <summary>

/// Данная ф-ия отвечает за созданиетаблиц в нужной БД

/// </summary>

public static void CreateTables( )

{

///для данной процедуры созданиесессии

///не нужно, поэтому здесь мыбудем отдельно

///конфигурировать подключение кБД

Configuration configuration = newConfiguration( ) ;

configuration. Configure( ) ;

configuration. AddClass(typeof(Abonent) ) ;

configuration. AddClass(typeof(TypeInfo) ) ;

configuration. AddClass(typeof(PhoneBook) ) ;

///создаем объект типаSchemaExport на основе созданной

///ранее конфигурации. Данныйобъект нужен для экспорта схемы БД

///либо в скрипт, либонепосредственно в БД

SchemaExport schemaExport = newSchemaExport(configuration) ;

///выполняем экспорт.

///1-й параметр-нужно ли выноситькод создания таблиц

///в какой-то файл. Нам это ненадо, поэтому стоит false

///2-й параметр- нужно ли делатьэкспорт схемы в БД. Нам экспорт нужен-true

///3-й параметр-использоватьконструкции drop в создаваемом скрипте.

///Т. е. нужен ли drop table передcreate table

schemaExport. Execute(false, true,false) ;

}

public static void InsertContact(PhoneBookpb)

{

///Открываем новую сессию

using (ISession session =sessions. OpenSession( ) )

///Начинаем транзакцию

using (ITransaction tx =session. BeginTransaction( ) )

{

///Сохраняем информацию оновом контакте

session. Save(pb) ;

///Подтверждаем транзакцию

tx. Commit( ) ;

}

}

/// <summary>

///Обновляем контакт в тел. книжке

/// </summary>

public static voidUpdateContact(PhoneBook pb)

{

using (ISession session =sessions. OpenSession( ) )

using (ITransaction tx =session. BeginTransaction( ) )

{

session. Update(pb) ;

tx. Commit( ) ;

}

}

/// <summary>

/// Удаляем контакт из тел. книжки

/// </summary>

/// <param name="pb"></param>

public static voidDeleteContact(PhoneBook pb)

{

using (ISession session =sessions. OpenSession( ) )

using (ITransaction tx =session. BeginTransaction( ) )

{

session. Delete(pb) ;

tx. Commit( ) ;

}

}

Кодинг

Вторая часть связана с добавлением,обновлением и удалением элементов каждоготипа. Здесь я приведу примеры данных операцийтолько для объекта PhobeBook, но в архиве кстатье они реализованы для всех типов (см.листинг 9).

Листинг 9. Добавляем/обновляем/удаляемконтакт в телефонной книжке/// <summary>

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

/// </summary>

/// <param name="pb">Объект-контакт, которыйдобавляем в тел. книгу</param>

Третья часть выполняет различные выборки изБД (см. листинг 1 0). Тут немного пояснюотдельно. Для выборки данных мы будемиспользовать т.н. Criteria Query API (есть и другиеспособы, но мы пока рассмотрим этот). Сначаласоздадим критерий для какого-то класса, ккоторому и будем делать запрос. Затем укажемусловия запроса и выведем полученныйрезультат. Сейчас, на конкретном примере мывсе это и разберем.

Листинг 10. Выборка данных/// <summary>

/// Находим список абонентов, укоторых в

/// ФИО встречается строка FIO

/// </summary>

/// <param name="FIO"></param>

/// <returns>Возвращаем списокабонентов</returns>

Page 28: VR-Online (February 2011)

28

vr-on l ine | февраль 201 1

Кодинг

public static IList<Abonent>FindAbonent(string FIO)

{

///Открываем новую сессию

using (ISession sess =sessions. OpenSession( ) )

{

///возвращаем результатвыборки

return sess

///создаем критерий дляабонентов

. CreateCriteria(typeof(Abonent) )

///добавляем выражение:

///поиск по полю FIO, чтоаналогично запросу

///where FIO like ' %FIO%'

. Add(Expression. Like("FIO" , "%"+FIO+"%" ) )

///возвращаем списокобъектов типа Abonent

. List<Abonent>( ) ;

}

}

/// <summary>

/// Поиск по связным таблицамAbonents и Contacts.

/// Будем искать записи из

/// телефонной книги, у которыхстрока из столбца

/// FIO(таблица Abonents) содержитподстроку FIO,

/// а значение Value (таблицаContacts)

/// подстроку Value

/// </summary>

/// <param name="FIO"></param>

/// <param name="Value"></param>

/// <returns>

/// Возвращаем список объектовPhoneBook,

/// удовлетворяющих заданнымусловияем

/// </returns>

public static IList<PhoneBook>FindContacts(string FIO, string Value)

{

///открываем новую сессию

using (ISession sess =sessions. OpenSession( ) )

{

///создаем критерий дляглавного класса PhoneBook

returnsess. CreateCriteria(typeof(PhoneBook) )

///добавляемвыражением, SQL-аналог

///whereValue like ' %Value%'

. Add(Expression. Like("Value" , "%"+Value+"%" ) )

///добавляемкритерий для свойства abon

///классаPhoneBook

. CreateCriteria("abon" )

///добавляемвыражение для поиска по полю FIO

. Add(Expression. Like("FIO" , "%"+FIO+"%" ) )

///возвращаем список объектов PhoneBook

. List<PhoneBook>( ) ;

}

}

Так выглядит работа с БД через NHibernate наC#. Я постарался как можно подробнеепрокомментировать все в коде, но если появятсявопросы – пиши. Пример использования данногокласса в обычном winforms-приложении такжеждет тебя в архиве, хотя мне кажется с этимпроблем у тебя возникнуть не должно.

Подбиваем итоги

В этой статье я постарался кратенько рассказатьпро интересного зверька по имени NHIbernate.Сейчас программистам не надо писать тонныSQL-кода для динамического создания БД ивыполнения стандартных выборок: все этоделается с помощью ORM-систем. Конечно,бывают моменты, когда без SQL не обойтись, нотот же NHibernate позволяет выполнить черезсвой API любой SQL-запрос. Я описал толькосамые основы NHibernate, поэтому изучаймануалы, смотри ссылки, которые я привел и всеу тебя получится. Удачи!

Дополнительные ссылки

http: //hibernate.org/ - официальный сайт.

http: //nhforge.org/doc/nh/en/index.html -полнаядокументация по NHibernate.

http: //nhforge.org/wikis/howtonh/your-first-nhibernate-based-application.aspx - примерпростого приложения с использованиемNHibernate.

Page 29: VR-Online (February 2011)

29

февраль 201 1 | vr-on l ine

Кодинг: C#Плагин за 5 секунд

Автор: Евгений Шапиро | [email protected]

Сегодня я предлагаю поговорить на тему разработки плагина

для твоей программы.

Делать мы это будем с помощью интересной .NET технологии

под названием «отражение» (Reflection).

Все начинается с идеи

Пример будет предельно простой (его идеяпозаимствована из книги Д. Рихтера«Программирование на платформе Microsoft .NETFramework 2.0»). Мы сделаем консольноеприложение, которое будет подгружатьбиблиотеку AboutLibrary.dl l и вызывать из нееметод, возвращающий в качестве результатаabout-строку. После получения результата мывыведем ее на экран (из основного приложения).

И где же тут отражение? – спросишь ты. Сейчасобъясню. Наша библиотека содержит в себекласс ClassAbout, который реализует один метод- GetAboutText. Он и возвращает нужную намстроку.

С помощью reflection мы можем узнатьинформацию обо всех классах, их методах ипараметрах любой сборки (под сборкой можетпониматься как exe,так и dl l-файл). Главное,чтобы эта сборка была собрана с помощью JIT-компилятора, который как раз и используетсяплатформой .NET. В нашем случае, мы загрузимсборку (AboutLibrary.dl l), получим информацию одоступном в ней классе (ClassAbout),а потомвызовем метод этого класса (GetAboutText).

Но как же наше главное приложение узнает, чтонадо искать именно класс под названиемClassAbout и вызывать именно методGetAboutTex? Рихтер в своей книге предлагаетследующий вариант. Мы добавим еще однусборку (в данном случае, библиотеку) в нашпроект, в котором опишем интерфейс IAboutInt. Вэтом интерфейсе будет, как ты уже догадался,всего один метод- GetAboutText. Назовем этубиблиотеку AboutInterface.dl l . Класс ClassAbout избиблиотеки AboutLibrary.dl l будет в свою очередьреализовывать этот интерфейс.

К главному приложению мы тоже подключимAboutInterface.dl l и оно будет знать, что ему надонайти класс, реализующий интерфейс IAboutInt,и вызвать его метод GetAboutText. Получилосьнемного запутано, но, думаю, в процессе все

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

1 . Создаем библиотеку AboutInterface.dl l иописываем в ней интерфейс IAboutInt.

2. Создаем библиотеку AboutLibrary.dl l , к нейподключаем AboutInterface.dl l и создаем классClassAbout, реализующий интерфейс IAboutInt.

3. Создаем главное приложение, подключаем кнему AboutInterface.dl. Затем, в ходе работыприложения, загружаем AboutLibrary.dl l . Ищем вней доступный класс, реализующий интерфейсIAboutInt и вызываем его метод GetAboutText.

Мы начинаем ковырять

Итак, для простоты, я предлагаю создатьприложение и обе библиотеки в одном решении.Запускаем студию и создаем обычноеконсольное приложение (см. рисунок 1 ). Яназвал его SimplePluginApplication. Не забываемпоставить галочку «Создать каталог длярешения», если она еще не установлена.

Кодинг

Рисунок 1. Создаем консольное приложение

Теперь нам требуется создать 2 библиотеки:AboutInterface.dl l и AboutLibrary.dl l . Для этого вобозревателе решений (справа) щелкаем правойкнопкой мыши на самой верхней строке и

Page 30: VR-Online (February 2011)

30

vr-on l ine | февраль 201 1

Кодинг

выбираем «Добавить» -> «Создать проект». Воткрывшемся окне выбираем «Библиотекуклассов». В качестве имени указываем«AboutInterface» (см. рисунок 2).

вывода» указать путь к папке, где формируетсяexe-файл главного приложения (см. рисунок 4).

Рисунок 2. Создаем библиотекуAboutInterface. dll

Точно также добавляем и библиотекуAboutLibrary. В результате окно «Обозревательрешений» должно выглядеть как на рисунке 3.

Рисунок 3. Обозреватель решений

Предлагаю для удобства сделать еще одну вещь:указать для обеих библиотек выходной каталогтакой же, как и у главного приложения. Врезультате и обе библиотеки и ехе-файл будутнаходиться в одной папке. Для этого надо в«Обозревателе решений» кликнуть на проектеAboutInterface правой кнопкой, зайти в«Свойства» и там выбрать вкладку«Построение». В появившемся окне, в поле «Путь

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

Повтори эти же действия для библиотекиAboutLibrary.dl l .

А вот и код

Мы добрались до самого интересного –реализации наших грандиозных планов. Начнемс библиотеки AboutInterface.dl l . Тут нам нужнолишь описать интерфейс. Его код ты найдешь влистинге 1 .

Листинг 1. Описание интерфейса IAboutInt./// <summary>

/// Интерфейс, описывающий всего один метод-

/// получение строки "О программе"

/// </summary>

public interface IAboutInt

{

String GetAboutText( ) ;

}

Теперь переходим к библиотеке AboutLibrary.dl l .Сначала ей надо сообщить, что есть такойинтерфейс, как IAboutInt. Логика, мой друг,лучший спутник программиста. Сначала добавимк проекту AboutInterface.dl l (через добавитьссылку), а потом еще подключим пространствоимен: using AboutInterface;

Все, теперь можем закодить класс ClassAbout(см. листинг 2).

Листинг 2. Класс ClassAbout собственнойперсоны./// <summary>

/// Класс, реализующий

///IAboutInt интерфейс

/// </summary>

public class ClassAbout: IAboutInt

{

public String GetAboutText( )

{

return "This is my first plugin";

}

}

Тут, думаю, все понятно. Теперь нам осталосьнаписать главное приложение, которое будет

Page 31: VR-Online (February 2011)

31

февраль 201 1 | vr-on l ine

подгружать плагин и вызывать его метод.Сначала, опять же, подключаем AboutInterface.dl lи нужное пространство имен. Затем реализуемфункцию ShowAboutInfo, делающую всю«грязную» работу (см. листинг 3).

Пятиминутная пауза

Ну вот, вроде и все, что я хотел тебе показать.Конечно, этот пример ну очень простой, зато ондемонстрирует основы, принципы. Дальше всезависит от твоей фантазии. Reflection оченьупрощает работу с плагинами, делает ее болеепрозрачной. С его помощью ты легко можешьизучать и другие приложения, созданные в .NET.Ведь имена классов, их методы и параметрымогут дать тебе много интересной информациидля размышления. И ничто не мешает тебеиспользовать в своих приложениях результатытрудов других программистов. В общем, темаинтересная и надеюсь, что я тебя ею зацепил.Удачи!

Кодинг

Листинг 3. Функция ShowAboutInfo используетплагин///Получаем полный путь к файлуAboutLibrary. dll.

///Предполагаем, что он находится в папке,где и

///исполняемый файл

String AboutLibName =Path. Combine(Path. GetDirectoryName(Assembly. GetEntryAssembly( ) . Location) ,"AboutLibrary. dll" ) ;

if ( ! File. Exists(AboutLibName) ) {Console. Write("File not found" ) ; return; }

///Загружаем сборку

Assembly AboutAssembly =Assembly. LoadFrom(AboutLibName) ;

///в цикле проходим по всем public-типамсборки

foreach (Type t inAboutAssembly. GetExportedTypes( ) )

{

///если это класс, который реализуетинтерфейс IAboutInt,

///то это то, что нам нужно : )

if (t. IsClass &&typeof(IAboutInt) . IsAssignableFrom(t) )

{

///создаем объект полученного класса

IAboutIntabout=(IAboutInt) Activator. CreateInstance(t) ;

///вызываем его метод GetAboutText

Console. WriteLine(about. GetAboutText( ) ) ;

break;

}

}

Page 32: VR-Online (February 2011)

32

vr-on l ine | февраль 201 1

DelphiСохраняем класс в файл

Автор: Шаронов Александр aka Demi

Прочитав кучу статей о том, как полезно применять ООП и как здорово, что оно есть,решил, что пора пользоваться этим всеми прелестями, которое оно несёт. Прежде чемизобретать велосипед мной внимательно были искурены форумы, которыесодержали в себе слова: сериализация, XML и JSON.

Всё было прекрасно, хорошо документировано, но ощущение чего-то незаконченногоне покидало мое сознание.

Были пару робких попыток пристроить для своихцелей XML или JSON, но сталкивался с тем, чтонад реализацией хранения данных в этихформатах в каждом новом проекте уходило немало времени на написание методов сохраненияи загрузки. Всё-таки не даёт XML (и емуподобные) того уровня абстракции, который быхотелось иметь в наличии.

Истина где-то рядом

Пока вёл свои изыскания с XML, неоднократнонаталкивался на практику применения RTTI вделфи. Увы, это так и не прижилось. Разведениягетеров и сетеров для published свойств сильнозасоряло код. Хотя свои плюсы, несомненно,есть в этом подходе. Только смысл для не оченьсложного проекта, с простой системой классовразводить весь этот огород? В дальнейшем янаткнулся на коллекции и в принципе они хорошосправляются с возложенными на них задачами.Жаль, не хватает универсальностииспользования и монотонность одних и тех жедействий в разных проектах меня напрягало. Всёэто в итоге подвигло меня на написание своеговелосипеда.

Мне пришла в голову такая идея: есть некийсферический класс в вакууме, который имеетнекоторые свойства и, соответственно, значенияэтих свойств (см. рисунок 1 ):

Счастью не было бы предела, если создатьтакой класс, который мог бы сохранять класс-хранитель в файл, да ещё в разных форматах.

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

Теперь подумаем, как воплотить мечты вреальности. Для начала рассмотрим нашсферический класс.

Кодинг

Рисунок 1. Схема класса

Было бы здорово, если существовал класс,который хранил множество «сферических»классов (см. рисунок 2):

Рисунок 2. Класс-хранитель

TClassItem = class(TCollectionItem)

private

FName: String;

FProperty: TStringList;

FStorage: TClassItems;

FPrt: Integer;

public

ParentItem: TClassItem;

constructor Create(Collection: TCollection) ;override;

function GetPropAsHTML: String;

function GetAddress(separator: char) : String;

destructor Destroy; override;

published

property Name: String read FName write FName;

property Parent: Integer read FPrt writeFPrt;

property Prop: TStringList read FPropertywrite FProperty;

property Storage: TClassItems read FStoragewrite FStorage;

end;

Page 33: VR-Online (February 2011)

33

февраль 201 1 | vr-on l ine

Беглый взгляд показывает, что есть имя, естьродитель, стринглист с парой свойств «свойство-значение» и хранилище себе подобных. Сначалавзглянем на хранилище себе подобных. Это какраз тот «класс-хранитель», что был описанвыше.

Shkaf. Prop. Values[ ' H' ] : =' 1800' ;

Shkaf. Prop. Values[ ' D' ] : =' 300' ;

Sections: =Shkaf. Storage. AddOrGet( ' Sections' ) ;

Section: =Sections. Storage. AddOrGet( ' Section1' ) ;

Section. Prop. Values[ ' width' ] : =' 152' ;

Polka: =Section. Storage. AddOrGet( ' Polka1' ) ;

Polka. Prop. Values[ ' Position' ] : =' 450' ;

Polka: =Section. Storage. AddOrGet( ' Polka2' ) ;

Polka. Prop. Values[ ' Position' ] : =' 0' ;

Section: =Sections. Storage. AddOrGet( ' Section2' ) ;

Section. Prop. Values[ ' width' ] : =' 300' ;

sc. SaveToTextFile( ' sc. txt' ) ;

sc. SaveToFile( ' sc. bin' ) ;

sc. SaveToCompressFile( ' sc. z' ) ;

sc. Free;

sc: =TSaveClass. Create(Form1) ;

sc. LoadFromCompressFile( ' sc. z' ) ;

Shkaf: =sc. Storage. AddOrGet( ' Shkaf' ) ;

ToTreeViev(Shkaf, Nil) ;

end;

Кодинг

TClassItems = class(TCollection)

Private

ParentItem: TClassItem;

function GetItem(Index: Integer) : TClassItem;

procedure SetItem(Index: Integer; Value:TClassItem) ;

public

function AddOrGet(Name: String) : TClassItem;

function ItemExists(Name: String) : Boolean;

property Items[ Index: Integer] : TClassItemread GetItem write SetItem;

end;

Думаю тут всё более-менее понятно. Далеепосмотрим на реализацию класса, которыйобеспечивал бы хранение в файлах (Листинг 1 ).

Листинг 1. Реализация класса SaveClassTSaveClass = class(TComponent)

private

FStorage: TClassItems;

public

constructor Create(AOwner: TComponent) ;override;

destructor Destroy; override;

Procedure SaveToFile(FileName: String) ;

Procedure LoadFromFile(FileName: String) ;

procedure LoadFromTextFile(FileName: String) ;

procedure SaveToTextFile(FileName: String) ;

ProcedureSaveToCompressFile(FileName: String) ;

ProcedureLoadFromCompressFile(FileName: String) ;

FunctionGetItemFromAddress(Adr: String; separator: char): TClassItem;

published

property Storage: TClassItems read FStoragewrite FStorage;

end;

Не сложно заметить, что класс работает с тремятипами файлов — бинарные, текстовые и (надесерт) со сжатием. Теперь посмотримреальный пример работы. Его код я привел влистинге 2.

Листинг 2. Пример использование классаSaveClassprocedure TForm1. Button1Click(Sender:TObj ect) ;

varShkaf, Sections, Section, Polka: TClassItem;

beginsc: =TSaveClass. Create(nil) ;// Создание

Shkaf: =sc. Storage. AddOrGet( ' Shkaf' ) ;

Shkaf. Prop. Values[ ' W' ] : =' 3000' ;

В данном случае мне надо было сохранитьдовольно сложную структуру «Шкаф-купе». В нейпроизвольное количество секций. В каждойсекции - полки, ящики и прочие радости бытадомохозяек.

Рисунок 3. Программа в действии

Объективная реальность

Предложенное решение не претендует нашедевр, но согласись, создание приложенийсущественно ускорится. Да, я знаю, что TstringListне надо было использовать и RTTI не есть“светлый путь познания Дзен”, но всё же япользуюсь этим решением. Причина проста –работает все быстро, и главное я оперируюобъектами напрямую, используя один и тот жекод в разных проектах.

Page 34: VR-Online (February 2011)

34

vr-on l ine | февраль 201 1

AndroidАдаптеры в андройд

Автор: Дарья Ряжских | [email protected]: http: //darja.info

Нынешняя статья будет посвящена такой важной теме, как адаптеры. Всем, ктосталкивается с ListView, или Spinner, или там ListActivity волей-неволей приходитсязнакомиться с адаптерами. Итак, адаптеры. Это прослойка между контролом,реализующего интерфейс AdapterView, и данными, которые отображаются в этомконтроле. С помощью адаптеров можно настраивать способ отображения данных.Концепция весьма похожа на датабиндинг в WPF, хоть и не столь изящна. В статье мырассмотрим стандартные адаптеры и попробуем написать собственный.

AdapterView

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

• ListView — список;

• GridView — таблица;

• Gallery — галерея;

• Spinner — так почему-то называетсявыпадающий список;

• ExpandableListView — группированный список;

Кроме контролов, адаптеры используются внекоторых активностях. А именно, в ListActivity ив прозводных от нее — PreferenceActivity иLauncherActivity.

Стандартные адаптеры

Принцип работы всех адаптеров схож. Естьнабор объектов, и есть View. Также есть правило,в соответствии с которым каждый объектбиндится на этот View. Результат добавляется всоответствующий AdapterView.

SimpleAdapter

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

SimpleAdapter(Context context, List<? extendsMap<String, ?>> data, int resource, String[]from, int[] to)

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

параметре resource. Причем биндится не абыкак: значение хеша с ключом from[i]отображается в элементе с идентификаторомto[i] .

Из подобной схемы работы очевидно, что вмассиве from должны содержаться только тезначения, которые присутствуют в ключах всеххешей, а также, что в массиве to должно быть небольше элементов, чем в from. Невыполнениеэтих условий приведет к ошибкам. Рассмотримпример. В некоторой активности выведем списоксенсоров устройства (см. листинг 1 ).

Кодинг

Листинг 1. Выводим список сенсоров устройстваpublic class SimpleAdapterActivity extendsActivity

{

@Overrideprotected void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;setContentView(R. layout. listview) ;

SimpleAdapter adapter = newSimpleAdapter(this, createSensorsList( ) ,android. R. layout. simple_list_item_2,

new String[ ] { "title" , "vendor"} ,

new int[ ] { android. R. id. text1,android. R. id. text2} ) ;

ListView lv =(ListView) findViewById(R. id. list) ;

lv. setAdapter(adapter) ;

}

private List<Map<String, ?>>createSensorsList( )

{

SensorManager sensorManager =(SensorManager) getSystemService(Context. SENSOR_SERVICE) ;

List<Sensor> sensors =sensorManager. getSensorList(Sensor. TYPE_ALL) ;

Page 35: VR-Online (February 2011)

35

февраль 201 1 | vr-on l ine

List<Map<String, ?>> items = newArrayList<Map<String, ?>>( ) ;

for (Sensor s : sensors)

{

Map<String, Obj ect> map = newHashMap<String, Obj ect>( ) ;

map. put("title" , s. getName( ) ) ;

map. put("vendor" , s. getVendor( ) ) ;

items. add(map) ;

}

return items;

}

}

разработки, их нет. В документации жеперечислены только значения констант, от коихтолку мало. Так что, если захочетсяознакомиться с содержимым стандартнойразметки, придется брать git и сливать кодотсюда:git: //android.git.kernel.org/platform/frameworks/base.git. В полученном коде, в папке~\core\res\res\layout можно найти все, что нужно.

SimpleAdapter.ViewBinder

А теперь попробуем добавить в разметку что-нибудь отличное от TextView. К примеру, SeekBar.Свой вариант кода разметки я привела влистинге 2.

Кодинг

Результат работы такого кода на Desire приведенна рисунке 1 .

Рисунок 1. Список сенсорных устройств

Пара слов о волшебных разметках

В приведенном примере в качествеидентификатора разметки передана загадочнаяконстанта android.R. layout.simple_list_item_2.Помнится, увидев такое в первый раз вAppDemos, я не заметила слово android в началеи довольно долго пыталась понять, что это такоеи откуда взялось. Разгадка была простой. В SDKпоставляется набор стандартных разметок наразные случаи жизни. Довольно частоиспользуется android.R. layout.simple_list_item_1 ,представляющий собой простой TextView сидентификатором text1 , а также нашandroid.R. layout.simple_list_item_2, содержащийзаголовок с подзаголовком и идентификаторамиtext1 и text2.

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

Листинг 2. sensor_layout. xml<?xml version="1. 0" encoding="utf-8"?>

<LinearLayout

xmlns: android="http: //schemas. android. com/apk/res/android"

android: orientation="vertical"

android: layout_width="fill_parent"

android: layout_height="wrap_content">

<TwoLineListItemxmlns: android="http: //schemas. android. com/apk/res/android"

android: paddingTop="2dip"

android: paddingBottom="2dip"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: minHeight="?android: attr/listPreferredItemHeight"

android: mode="twoLine"

>

<TextView android: id="@id/title"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: layout_marginLeft="6dip"

android: layout_marginTop="6dip"

android: textAppearance="?android: attr/textAppearanceLarge"

/>

<TextView android: id="@id/content"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: layout_below="@id/title"

android: layout_alignLeft="@id/title"

android: textAppearance="?android: attr/textAppearanceSmall"

/>

</TwoLineListItem>

<SeekBar android: id="@id/range"android: layout_width="fill_parent"android: layout_height="wrap_content"android: max="100" />

</LinearLayout>

Саму активность приведем к виду третьеголистинга.

Page 36: VR-Online (February 2011)

36

vr-on l ine | февраль 201 1

Кодинг

Листинг 3. ViewBinderActivity. javapublic class ViewBinderActivity extendsActivity

{

@Overrideprotected void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;setContentView(R. layout. listview) ;

SimpleAdapter adapter = newSimpleAdapter(this, createSensorsList( ) ,R. layout. sensor_layout,

new String[ ] { "title" ,"vendor" , "power"} ,

new int[ ] { R. id. title,R. id. content, R. id. range} ) ;

ListView lv =(ListView) findViewById(R. id. list) ;

lv. setAdapter(adapter) ;

}

private List<Map<String, ?>>createSensorsList( )

{

SensorManager sensorManager =(SensorManager) getSystemService(Context. SENSOR_SERVICE) ;

List<Sensor> sensors =sensorManager. getSensorList(Sensor. TYPE_ALL) ;

List<Map<String, ?>> items = newArrayList<Map<String, ?>>( ) ;

for (Sensor s : sensors)

{

Map<String, Obj ect> map = newHashMap<String, Obj ect>( ) ;

map. put("title" , s. getName( ) ) ;

map. put("vendor" , s. getVendor( ) ) ;

map. put("power" ,Math. round(s. getPower( ) * 10) ) ;

items. add(map) ;

}

return items;

}

}

if (view. getId( ) == R. id. range)

{

( (SeekBar) view) . setProgress((Integer) data) ;

return true;

}

return false;

}

}

Запускаем и приложение торжественно падает.Что же не так? А дело вот в чем. НашSimpleAdapter умеет биндить только TextView,ImageView и контролы, реализующие Checkable.Для всего остального нужно писать костыль подназванием ViewBinder.

ViewBinder — внутренний интерфейс классаSimpleAdapter. У него есть всего один метод —setViewValue(android.view.View, Object, String), вкотором принимается решение, какие поляконтрола и как заполнять. Биндер для нашегослучая может выглядеть как в листинге 4.

Листинг 4. Биндерprivate static class SeekBarBinder implementsSimpleAdapter. ViewBinder

{

public boolean setViewValue(View view,Obj ect data, String textRepresentation)

{

Кроме того, после инициализации адаптеранужно будет написать:

adapter.setViewBinder(new SeekBarBinder());

Результат работы можно увидеть на рисунке 2.

Рисунок 2. Очередной тест удался

Отмечу, что логика работы SimpleAdapter такова,что он сначала применяет ViewBinder, если онопределен. Затем, если вернулся false, пытаетсязабиндить Checkable, потом TextView, потомImageView. Так что ViewBinder — хорошеерешение для случаев, когда нужно забиндитьчто-нибудь эдакое.

ArrayAdapter<T>

Адаптер, поставляющий контролу списокэлементов произвольного типа. Каждый элементсписка приводится к строке, и то, что получилось,выводится в TextView. Рассмотрим сигнатурыконструкторов:

• ArrayAdapter(Context context, int resource, inttextViewResourceId)

• ArrayAdapter(Context context, int resource, inttextViewResourceId, T[] objects)

Page 37: VR-Online (February 2011)

37

февраль 201 1 | vr-on l ine

• ArrayAdapter(Context context, int resource, inttextViewResourceId, List<T> objects)

• ArrayAdapter(Context context, int resource)

• ArrayAdapter(Context context, int resource, T[]objects)

• ArrayAdapter(Context context, int resource,List<T> objects)

В документации кое-где перепутаныобозначения. В последних трех сигнатурахвместо resource написали textViewResourceId.Основные параметры адаптера:

• context — текущий контекст;

• resource — идентификатор разметки, котораябудет применяться к элементам списка. Этаразметка должна содержать хотя бы одинTextView. Обязательный параметр;

• textViewResourceId — идентификатор TextView,к которому будут биндиться элементы списка.Если в разметке всего один TextView, этотпараметр можно не указывать. Если же ихнесколько, то указывать нужно обязательно,иначе вылезет ошибка;

• objects — список (или массив) отображаемыхобъектов;

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

корректной работы его отображения.

Кодинг

Листинг 5. Пример использования ArratAdapterpublic class ArrayAdapterActivity extendsActivity

{

@Overrideprotected void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;setContentView(R. layout. listview) ;

String[ ] strings = new String[ ] {"One" , "Two" , "Three" } ;

ArrayAdapter<String> adapter = newArrayAdapter<String>(this,android. R. layout. simple_list_item_1,android. R. id. text1, strings) ;

ListView list =(ListView) this. findViewById(R. id. list) ;

list. setAdapter(adapter) ;

}

}

Однако, хоть адаптер и громко называетсяArrayAdapter<T>, но биндить таким образомобъекты произвольного класса оказываетсябессмысленным, потому что получается ерундакак на рисунке 4.

В виденных мной примерах ArrayAdapterиспользуется либо для строк, либо для объектовклассов с перегруженным toString(). В общем-то,это тоже вариант, потому что код получаетсяменее громоздким, чем в случае SimpleAdapter.Но лично мне не нравится, что приходится вкласс с данными добавлять костыли для

Рисунок 3. Выводим произвольный список

Рисунок 4. А не получится так!

CursorAdapter

Адаптер, использующий в качестве источникаданных курсор. Курсоры в андроиде — этоотдельная история, достойная целой статьи.Вкратце, это инструмент для получения доступак результатам некоего запроса. Это может бытьзапрос к БД, либо обращение к внутреннемухранилищу данных в телефоне (контактов,

Page 38: VR-Online (February 2011)

38

vr-on l ine | февраль 201 1

Кодинг

звонков и другого). Базы мы рассматривать небудем, т.к. по ним и так статей изрядно. Выведемсписок контактов, имеющихся в телефоне.

Так как класс CursorAdapter являетсяабстрактным, будем использовать одну из егореализаций — SimpleCursorAdapter.Демонстрационный код как всегда ждет тебя влистинге. На этот раз в шестом.

которых содержится список. Соответственно,адаптер должен предоставлять все эти данные.В интерфейсе ExpandableListAdapter для этогоопределен ряд функций:

• getGroupCount() — получить количество групп;

• getGroup(int groupPosition) — получить объект,содержащийся в группе с заданным номером;

• getChildrenCount(int groupPosition) — получитьколичество элементов в группе с заданнымномером;

• getChild(int groupPosition, int chi ldPosition) —получить объект, содержащийся на заданномместе в списке у группы с определеннымномером (во, как!).

Пример полной реализацииExpandableListAdapter я приводить не буду. Какнетрудно догадаться, существует стандартныйадаптер SimpleExpandableListAdapter, которымможно обойтись во многих случаях. Посмотримна один из конструкторовSimpleExpandableListAdapter:

SimpleExpandableListAdapter(Context context,

List<? extends Map<String, ?>> groupData,

int groupLayout,

String[] groupFrom,

int[] groupTo,

List<? extends List<? extends Map<String,?>>> childData,

int childLayout,

String[] childFrom,

int[] childTo)

В остальных конструкторах то же самое, толькоеще можно задавать отдельные разметки длясвернутой или развернутой группы. Несложнозаметить, что тут код похож на тот, что писали вSimpleAdapter (только в двойном экземпляре).Сначала параметры groupData, groupLayout,groupFrom и groupTo используются для привязкигрупп (назначение параметров точно такое же,как и в SimpleAdapter). А потом для каждой i-йгруппы биндится ее выпадающий список,находящийся в childData[i] , с аналогичнымиспользованием параметров childLayout,chi ldFrom и childTo. В общем, тут все тольковыглядит страшно, а на самом деле все вполнепросто и логично. Мой пример можно посмотретьв седьмом листинге.

Листинг 6. Адаптер-курсорpublic class CursorAdapterActivity extendsActivity

{

@Overrideprotected void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;

setContentView(R. layout. cursor_adapter) ;

String[ ] proj ection = new String[ ] {ContactsContract. Contacts. DISPLAY_NAME } ;

Cursor cursor =managedQuery(ContactsContract. Contacts. CONTENT_URI, null, null, null, null) ;

SimpleCursorAdapter adapter = newSimpleCursorAdapter(this,

android. R. layout. simple_list_item_1,

cursor,

new String[ ] {ContactsContract. Contacts. DISPLAY_NAME } ,

new int[ ] {android. R. id. text1 } ) ;

AdapterView view =(AdapterView) findViewById(R. id. contacts_list);

view. setAdapter(adapter) ;

}

}

В целом тут все похоже на SimpleAdapter. Тольков качестве источника данных используется несписок, а курсор. Скажу пару слов про то, как мыздесь создавали курсор. Курсоры создаются спомощью метода query класса ContentResolverили метода managedQuery. Сигнатуры обоихметодов одинаковы. А разница в том, что впервом случае нужно будет вручную писать коддля закрытия и уничтожения курсора, а вовтором этого не нужно — активность самауправляет курсором.

Обрати внимание, для корректной работыданного примера в приложении должно бытьвыставлено разрешение на чтение контактов.Для этого в Permissions манифеста добавь UsesPermission под названиемandroid.permission.READ_CONTACTS.

Адаптеры для ExpandableList

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

Листинг 7.SimpleExpandableListAdapterActivitypublic classSimpleExpandableListAdapterActivity extendsExpandableListActivity

{

@Overrideprotected void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;

Page 39: VR-Online (February 2011)

39

февраль 201 1 | vr-on l ine

SimpleExpandableListAdapter adapter = newSimpleExpandableListAdapter(

this,createGroups( ) ,

R. layout. display_header,

new String[ ] { "name" } ,

new int[ ] { R. id. header1 } ,

createChildren( ) ,

R. layout. display_item,

new String[ ] { "name" } ,

new int[ ] { R. id. text1 } ) ;

setListAdapter(adapter) ;

}

public List<Map<String, ?>>createGroups( )

{

List<Map<String, ?>> list = newArrayList<Map<String, ?>>( ) ;

for (int i = 1; i <= 3; ++i)

{

Map<String, Obj ect> item = newHashMap<String, Obj ect>( ) ;

item. put("name" ,String. format("%d-th" , i * 10) ) ;

list. add(item) ;

}

return list;

}

public List<List<Map<String, ?>>>createChildren( )

{

List<List<Map<String, ?>>> list = newArrayList<List<Map<String, ?>>>( ) ;

for (int i = 1; i <= 3; ++i)

{

List<Map<String, ?>> itemList =new ArrayList<Map<String, ?>>( ) ;

for (int j = 0; j < 5; ++j )

{

Map<String, Obj ect> item =new HashMap<String, Obj ect>( ) ;

item. put("name" ,String. format("%d" , i * 10 + j ) ) ;

itemList. add(item) ;

}

list. add(itemList) ;

}

Результат работы примера, рассмотреного вседьмом листинге приведен на рисунке 4.

Кодинг

Рисунок 4.SimpleExpandableListAdapterActivity

А еще есть SimpleCursorTreeAdapter —абстрактный класс, унаследовавшись откоторого, и определив всего одну функцию,можно заполнить раскрывающийся список изкурсоров. Я уже не буду приводить здесь пример,его ты найдешь в исходниках к статье.

Заключение

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

return list;

}

}

Page 40: VR-Online (February 2011)

40

vr-on l ine | февраль 201 1

ПаттерныMVC, MVP и MVVM

Автор: Денис Гладких aka outcoldmanwww: http: //outcoldman.ru

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

В данной статье я хотел бы поговорить о различии паттернов MVC, MVP и MVVM.

Model-View-Controller

Начнем с первого главного – Model-View-Control ler – это фундаментальный паттерн,который нашел применение во многихтехнологиях. Он дал развитие новымтехнологиям, и каждый день облегчает жизньпрограммистам. Если ты спросишь архитекторово том, как реализовать данный паттерн, то, ядумаю, ты сможешь услышать несколько разныхответов и соответственно несколько разныхрешений.

Вообще, объединяет все эти паттерны –выделение User Interface (UI) от логикипрограммирования, что позволяет дизайнерамделать свою работу, не задумываясь о кодепрограммы. Если вспомнить школьное истуденческое программирование, то всплываеткартина огромного количества строчек,написанных в code behind интерфейсов, что неявляется хорошей практикой. Так жепредоставляется возможность выделениямодели данных, что дает разработчикамвозможность создания модульных тестов надними.

Из чего же состоит MVC

MVC состоит из трех компонент (см. рисунок 1 ):View (представление, пользовательскийинтерфейс), Model (модель, ваша бизнес логика)и Control ler (контроллер, содержит логику наизменение модели при определенных действияхпользователя, реализует Use Case). Основнаяидея этого паттерна в том, что и контроллер ипредставление зависят от модели, но модельникак не зависит от этих двух компонент. Это какраз и позволяет разрабатывать и тестироватьмодель, ничего не зная о представлении иконтроллерах.

В идеале контроллер так же ничего не должензнать о представлении (хотя на практике это невсегда так), и в идеале для одногопредставления можно переключать контроллеры,а так же один и тот же контроллер можно

использовать для разных представлений (так,например, контроллер может зависеть отпользователя, который вошел в систему).Пользователь видит представление, на нем жепроизводит какие-то действия, эти действияпредставление перенаправляет контроллеру иподписывается на изменение данных модели.

Кодинг

Рисунок 1. Архитектура MVC

Контроллер в свою очередь производитопределенные действия над моделью данных,представление получает последнее состояниемодели и отображает ее пользователю.Реализация в ASP.NET выглядит следующимобразом (пример взят с MSDN). Представление –это обычная aspx разметка:<html>

<body><form id="start" method="post"

Page 41: VR-Online (February 2011)

41

февраль 201 1 | vr-on l ine

runat="server"><asp: dropdownlist

id="recordingSelect" runat="server" /><asp: button runat="server"

text="Submit" OnClick="SubmitBtn_Click" /><asp: datagrid id="MyDataGrid"

runat="server"enableviewstate="false" />

</form></body>

</html>

Модель – отдельный класс, у которого естьметоды получения данных (модель вреализациях часто включает в себя так же и DataAccess Level):

public class DatabaseGateway{

public static DataSet GetRecordings(){

DataSet ds = . . .return ds;

}

public static DataSet GetTracks(stringrecordingId)

{DataSet ds = . . .return ds;

}}

Пример модели не самый удачный в данномслучае, но все-таки не всегда бываетнеобходимость иметь действительно описаннуюбизнес модель в классах, иногда хватает иработы с DataSet'ами. Самое интересное, этореализация контроллера, по сути это code behindaspx страницы.using System;using System. Data;using System. Collections;using System. Web. UI. WebControls;

public class Solution : System. Web. UI. Page{

private void Page_Load(object sender,System. EventArgs e)

{if(! IsPostBack){

DataSet ds =DatabaseGateway. GetRecordings() ;

recordingSelect. DataSource = ds;recordingSelect. DataTextField =

"title";recordingSelect. DataValueField =

"id";recordingSelect. DataBind() ;

}}

void SubmitBtn_Click(Object sender,EventArgs e)

{DataSet ds =

DatabaseGateway. GetTracks(

(string) recordingSelect. SelectedItem. Value) ;

MyDataGrid. DataSource = ds;MyDataGrid. DataBind() ;

}

#region Web Form Designer generated codeoverride protected void OnInit(EventArgs

e){

//// CODEGEN: This call is required by

the ASP. NET Web Form Designer.//InitializeComponent() ;base. OnInit(e) ;

}

/// <summary>/// Required method for Designer support -

do not modify/// the contents of this method with the

code editor./// </summary>private void InitializeComponent(){

this. submit. Click += newSystem. EventHandler(this. SubmitBtn_Click) ;

this. Load += newSystem. EventHandler(this. Page_Load) ;

}#endregion

}

Данный подход даст нам возможность слегкостью написать тесты для модели, но не дляконтроллера (конечно же, все возможно, нопридется постараться).[TestFixture]public class GatewayFixture{

[Test]public void Tracks1234Query(){

DataSet ds =DatabaseGateway. GetTracks("1234" ) ;

Assertion. AssertEquals(10,ds. Tables["Track" ] . Rows. Count) ;

}

[Test]public void Tracks2345Query(){

DataSet ds =DatabaseGateway. GetTracks("2345" ) ;

Assertion. AssertEquals(3,ds. Tables["Track" ] . Rows. Count) ;

}

[Test]public void Recordings(){

DataSet ds =DatabaseGateway. GetRecordings() ;

Assertion. AssertEquals(4,ds. Tables["Recording" ] . Rows. Count) ;

DataTable recording =ds. Tables["Recording" ] ;

Assertion. AssertEquals(4,recording. Rows. Count) ;

Кодинг

Page 42: VR-Online (February 2011)

42

vr-on l ine | февраль 201 1

Кодинг

DataRow firstRow = recording. Rows[0] ;string title =

(string) firstRow["title" ] ;Assertion. AssertEquals("Up",

title. Trim() ) ;}

}

Model-View-Presenter

Данный паттерн опять-таки состоит из трехкомпонент (см. рисунок 2). Только посмотрев наприведенную схему становится ясно, чтопредставлению нет надобности подписыватьсяна изменения модели, теперь контроллер,переименованный в Presenter дает знатьпредставлению об изменениях. Данный подходпозволяет создавать абстракцию представления.Реализовать данный паттерн можно при помощивынесения интерфейсов представления. Укаждого представления будут интерфейсы сопределенными наборами методов и свойств,необходимых презентеру.

public interface ISolutionView{

string SelectedRecord { get; }DataSet Recordings { set; }DataSet Tracks { set; }

}//Presenterpublic class SolutionPresenter{

private ISolutionView _view;

public SolutionPresenter(ISolutionViewview)

{_view = view;

}

public void ShowTracks(){

DataSet ds =DatabaseGateway. GetTracks(_view. SelectedRecord) ;

_view. Tracks = ds;}

public void Initialize(){

DataSet ds =DatabaseGateway. GetRecordings() ;

_view. Recordings = ds;}

}

//Viewpublic class Solution : System. Web. UI. Page,ISolutionView{

private SolutionPresenter _presenter;

private void Page_Load(object sender,System. EventArgs e)

{if(! IsPostBack){

_presenter. Initialize() ;}

}

override protected void OnInit(EventArgse)

{base. OnInit(e) ;_presenter = new

SolutionPresenter(this) ;submit. Click += delegate {

_presenter. ShowTracks() ; } ;}

public string SelectedRecord{

get { return(string) recordingSelect. SelectedItem. Value; }

}

public DataSet Recordings{

set{

recordingSelect. DataSource =

Рисунок 2. Архитектура MVP

Презентер в свою очередь инициализируется сданным интерфейсом, подписывается насобытия представления и по необходимостиподсовывает данные. Данный подход позволяетразрабатывать приложения с использованиемметодологии TDD (Test-driven development).Данный паттерн так же можно применить кASP.NET, давайте посмотрим на предыдущемпримере. Оставим представление и модель изпредыдущего примера, а code behind страницынемного распилим.//Abstract View

Page 43: VR-Online (February 2011)

43

февраль 201 1 | vr-on l ine

value;recordingSelect. DataTextField =

"title";recordingSelect. DataValueField =

"id";recordingSelect. DataBind() ;

}}

public DataSet Tracks{

set{

MyDataGrid. DataSource = value;MyDataGrid. DataBind() ;

}}

}

Хотя логика и слабая, но все же теперь она вся впрезентере, и мы можем тестировать отдельноSolutionPresenter вместе с ISolutionView,используя Mock’и(http: //en.wikipedia.org/wiki/Mock_object).

Model-View-ViewModel

Честно говоря, не знаю, используется ли данныйпаттерн где-то, кроме WPF и Silverl ight. Здесьопять присутствуют три компоненты: модель,представление и третий компонент –дополнительная модель под названиемViewModel. Данный паттерн подходит к такимтехнологиям, где присутствует двухстороннийбиндинг (синхронизация) элементов управленияна модель, как в WPF. Отличие от MVP паттерназаключается в том, что свойство SelectedRecord,из предыдущего примера, должно находится не впредставлении, а в контроллере (ViewModel).Кроме того, оно должно синхронизироваться снеобходимым полем в представлении. В этом изаключается основная идея WPF. ViewModel –это некоторый суперконвертор, которыйпреобразует данные модели в представление, внем описываются основные свойствапредставления, а так же логика взаимодействияс моделью.

Кодинг

Page 44: VR-Online (February 2011)

44

vr-on l ine | февраль 201 1

Пишем игру для AndroidЧасть 5. Хранение настроек

Автор: Дарья Ряжских | [email protected]: http: //darja.info

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

Ну первое мы еще с прошлой статьи умеем, так что особых сложностей быть недолжно. А вот второе следует рассмотреть подробнее.

Итак, приступим.

Окно приветствия

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

На нашей форме приветствия будет какая-нибудь картинка и три кнопки: "Начать игру","Настройки" и "Выход". Картинку в формате png,которую мы назовем start.png нужно положить впапку /res/drawable. Названия кнопок нужновынести в strings.xml (см. листинг 1 ), добавивследующие строки:

android: text="@string/start_title" />

<Button android: id="@+id/SettingsButton"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: textStyle="bold"

android: text="@string/settings_title"/>

<Button android: id="@+id/ExitButton"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: textStyle="bold"

android: text="@string/exit_title" />

</LinearLayout>

Кодинг

Листинг 1. res/values/strings. xml<resources>

<string name="app_name">PingPong</string>

<string name="start_title">StartGame</string>

<stringname="settings_title">Settings</string>

<string name="exit_title">Exit</string>

</resources>

Тогда разметка для новой формы будетвыглядеть так (см. листинг 2):

Листинг 2. res/layout/start. xml<?xml version="1. 0" encoding="utf-8"?>

<LinearLayoutxmlns: android="http: //schemas. android. com/apk/res/android"

android: orientation="vertical"

android: layout_width="fill_parent"

android: layout_height="fill_parent"

android: gravity="bottom"

android: background="@drawable/start"

android: padding="8dip">

<Button android: id="@+id/StartButton"

android: layout_width="fill_parent"

android: layout_height="wrap_content"

android: textStyle="bold"

Фоновое изображение можно задать экрану спомощью полезного свойства android:background.Собственно, так можно задавать фон и кнопкам,и вообще чему угодно. Получили вот такуюразметку (см рисунок 1 ):

Рисунок 1. Форма нашего приложения

Page 45: VR-Online (February 2011)

45

февраль 201 1 | vr-on l ine

Добавим соответствующий этой разметке классStartScreen. java (см. листинг 3). Сразуобработаем нажатия всех кнопок:

Осталось только зарегистрировать эту форму вприложении и сделать ее главной. Для этогоидем в AndroidManifest.xml (см. листинг 4):

Кодинг

Листинг 3. StartScreen. javapublic class StartScreen extends Activityimplements OnClickListener

{

@Overridepublic void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;setContentView(R. layout. start) ;

// Кнопка "Start"

Button startButton =(Button) findViewById(R. id. StartButton) ;

startButton. setOnClickListener(this) ;

// Кнопка "Exit"

Button exitButton =(Button) findViewById(R. id. ExitButton) ;

exitButton. setOnClickListener(this) ;

// Кнопка "Settings"

Button settingsButton =(Button) findViewById(R. id. SettingsButton) ;

settingsButton. setOnClickListener(this) ;}

/** Обработка нажатия кнопок */

public void onClick(View v)

{

switch (v. getId( ) )

{

case R. id. StartButton:

{

Intent intent = new Intent( ) ;

intent. setClass(this,GameScreen. class) ;

startActivity(intent) ;

break;

}

case R. id. SettingsButton:

{

break;

}

case R. id. ExitButton:

finish( ) ;

break;

default:break;

}

}

}

По нажатию на кнопку Start происходит переходна экран с игрой. Обрати внимание, чтоStartScreen при этом не закрывается. Это значит,что, когда закроется StartScreen, мы попадемобратно на экран приветствия. По нажатию наSettings пока что ничего не происходит, по Exit —приложение закрывается.

Листинг 4. AndroidManifest. xml<?xml version="1. 0" encoding="utf-8"?>

<manifestxmlns: android="http: //schemas. android. com/apk/res/android"

package="com. android. pingpong"

android: versionCode="1"

android: versionName="1. 0. 0">

<applicationandroid: icon="@drawable/icon"android: label="@string/app_name">

<activity android: name=". GameScreen"

android: label="@string/app_name">

<intent-filter>

<actionandroid: name="android. intent. action. MAIN" />

<categoryandroid: name="android. intent. category. LAUNCHER" />

<categoryandroid: name="android. intent. category. SAMPLE_CODE" />

</intent-filter>

</activity>

<activityandroid: name=". StartScreen">

<intent-filter>

<actionandroid: name="android. intent. action. MAIN" />

<categoryandroid: name="android. intent. category. LAUNCHER" />

</intent-filter>

</activity>

</application>

</manifest>

Теперь приложение начинается с StartScreen,все кнопки работают.

Настройки

Я сделаю в настройках два параметра —максимальное количество очков и сложность.Сложность игры будем менять, варьируяскорость мячика и ракеток.

Сама форма с настройками делается достаточнопросто. Есть специальный наследник классаActivity — PreferenceActivity, который именно дляэтого и предназначен. Когда мы хотим сделатьформу с настройками, нужно унаследоватьсяименно от него, и он возьмет на себя большуючасть рутины.

Разметка

Разметка для формы с настройками выглядитнесколько необычно (см. листинг 5):

Листинг 5. res/xml/preferences. xml<?xml version="1. 0" encoding="UTF-8"?>

<PreferenceScreen

xmlns: android="http: //schemas. android. com/apk/res/android" >

<PreferenceCategory

Page 46: VR-Online (February 2011)

46

vr-on l ine | февраль 201 1

Кодинг

android: title="@string/prefs_title">

<ListPreferenceandroid: key="@string/pref_difficulty"

android: title="@string/difficulty_title"

android: entries="@array/difficulty"

android: entryValues="@array/difficulty"

android: defaultValue="1"/>

<EditTextPreferenceandroid: key="@string/pref_max_score"

android: title="@string/score_title"

android: defaultValue="10"/>

</PreferenceCategory>

</PreferenceScreen>

А можно обойтись без групп: PreferenceScreenуже сам по себе является контейнером длянастроек. В нашем случае, например, настроекмало и группировать нечего. Но это я так, дляполноты картины.

Какие можно сделать настройки

Как видно даже на прошлой картинке, настройкимогут быть разными. И флажки, и текстовыеполя, и списки. Все они происходят от одногокласса Preference, и наследуют от него всякиеполезные атрибуты, которые можно задавать вразметке, как то:android: title

Заголовок настройки или контейнера настроек.android: summary

Краткое описание. Проще говоря, это - то, чтопишется под заголовком мелким шрифтом.android: defaultValue

Значение по умолчаниюandroid: key

Ключ, с которым данная настройка будетхраниться и с которым можно будет к нейобращаться.android: dependency

Задает зависимость от другого контрола.Например, можно поставить эдиторузависимость от флажка, и тогда, если флажок неустановлен, но эдитор будет неактивен.

Ну и еще кое-что. Рассмотрим некоторыеконкретные виды настроек.

CheckBoxPreference

Вот такой флажок (см. рисунок 3):

Настолько необычно, что, если поместить этотXML в папку layout, ecl ipse начнет ругаться, чтоне может разрезолвить такие классы.Собственно, это - не просто разметка: там такжесодержатся ключи настроек и значения поумолчанию. Поэтому мы создадим отдельнуюпапку xml, и поместим этот файл туда. А теперьобо всем по порядку.

PreferenceCategory

Ну, PreferenceScreen все понятно, а что такоеPreferenceCategory? Как ни удивительно, это -категория настроек. Например, у какой-нибудьигры могут быть настройки графики, настройкизвука, настройки сети и т.д. . . Удобно отобразитьих сгруппированными, вот так (см. рисунок 2):

Рисунок 2. Категория настроек

Рисунок 3. CheckBoxPreference

EditTextPreference

Редактор текста (см. рисунок 4).

Честно говоря, у редактора текста оченьхотелось бы валидатор, а еще лучше маску.Например, IP-адрес имеет специфическийформат, и хотелось бы запрещать пользователювводить там что попало. Но мне такуюфункциональность так и не удалось обнаружить.

ListPreference

Своеобразная реализация Dropdown-а. Хотя, нателефоне наверно и вправду так удобнее (см.рисунок 5).

На этом контроле хотелось бы остановитьсяподробнее. А конкретнее, рассказать, откуда он,собственно, берет элементы списка. А берет оних из ресурсов с помощью таких атрибутов.android: entries

Здесь хранится ссылка на ресурс, в которомхранятся отображаемые элементы списка. Все

Page 47: VR-Online (February 2011)

47

февраль 201 1 | vr-on l ine

значения, которые хочется вынести в ресурсы,хранятся в папке values.

следующее:<string-array name="performance">

<item>Best performance</item><item>Normal performance and

appearance</item><item>Best appearance</item>

</string-array>

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

Кстати говоря, в item-ах может быть ненепосредственно строка, а ссылка на строку вstrings.xml. Например, в нашем случае будет так(см. листинг 6) (разумеется, стоит добавитьсоответствующие значения в strings.xml):

Кодинг

Рисунок 4. EditTextPreference

Рисунок 5. ListPreference

До сих пор там была только одна XML-ка —strings.xml. Но теперь надо добавить еще одну —arrays.xml. И добавить в узел resources

Листинг 6. res/values/arrays. xml<?xml version="1. 0" encoding="utf-8"?>

<resources>

<string-array name="difficulty">

<item>@string/difficulty_easy</item>

<item>@string/difficulty_normal</item>

<item>@string/difficulty_hard</item>

</string-array>

</resources>

android: entryValues

Список действительных значений. Также ссылкана ресурс, и задавать можно так же. Если кодовбудет меньше, чем значений, приложение будетвалиться с исключением. Если больше — небудет. В нашем случае можно в entries иentryValues смело задавать одно и то же, нобывает, когда имеет смысл их разделять.

А еще мне никак не удалось победить уListPreference атрибут adnroid:defaultValue. Неработает и все.

RingtonePreference

Настройка звукового сигнала. В нашемприложении, например, можно было бы добавитьзвук, с которым мячик ударяется о стенку, ивыбирать этот звук с помощью такого контрола.Выглядит это так (см. рисунок 6):

Класс формы

Класс для формы с настройками будетвыглядеть так (см. листинг 7):

Листинг 7. SettingsScreen. javapublic class SettingsScreen extendsPreferenceActivity

{

@Overridepublic void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;// Настройки и их разметка

загружаются из XML-файла

addPreferencesFromResource(R. xml. preferences);

}

}

Page 48: VR-Online (February 2011)

48

vr-on l ine | февраль 201 1

Кодинг

Кстати, настройки необязательно загружать изXML-ки, можно добавлять все эти настройкипрямо в коде конструктора. В сэмплах, которыеидут с Android SDK, такие примеры есть.

Добавляем в StartScreen код для открытияформы настроек, прописываем SettingsScreen вAndroidManifest.xml. (Все выглядит точно так же,как и для GameScreen, так что листинги непривожу). И увидим мы следующее (см. рисунок7):

это сделать автоматически, я так и не нашла,пришлось все делать руками, используя дляэтого поле summary. Итак, summary настройкидолжно обновляться при изменении значения.По счастью, есть такое событиеOnPreferenceChange. Итак, пишем (см. листинг8):

Рисунок 6. RingtonePreference

Рисунок 7. Форма настроек

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

Листинг 8. SettingsScreen. javapublic class SettingsScreen extendsPreferenceActivity implementsPreference. OnPreferenceChangeListener

{

/* Called when the activity is firstcreated. */

@Overridepublic void onCreate(Bundle

savedInstanceState)

{

super. onCreate(savedInstanceState) ;

// Load the preferences from an XMLresource

addPreferencesFromResource(R. xml. preferences);

ListPreference difficulty =(ListPreference) this. findPreference("pref_difficulty" ) ;

difficulty. setSummary(difficulty. getEntry( ) ) ;

difficulty. setOnPreferenceChangeListener(this) ;

EditTextPreference maxScore =(EditTextPreference) this. findPreference("pref_max_score" ) ;

maxScore. setSummary(maxScore. getText( ) ) ;

maxScore. setOnPreferenceChangeListener(this) ;}

public booleanonPreferenceChange(Preference preference,Obj ect newValue)

{

preference. setSummary((CharSequence) newValue);

return true;

}

}

Думаю, все понятно без слов. Теперь мы видимтакую картину (см. рисунок 8):

И, если мы будем менять настройки, изменениясразу же будут отображаться в summary.

Использование настроек в других формах

Ну все, настройки мы сделали, они как-то самигде-то сохранились. Теперь возникланеобходимость их прочитать и что-нибудь с нимисделать. Читать и делать мы будем в классеGameManager, а конкретно, в конструкторе. Дляработы с сохраненными настройкамиприложения используется классSharedPreferences. Вся работа по чтению иприменению настроек выглядит так (см. листинг9):

Page 49: VR-Online (February 2011)

49

февраль 201 1 | vr-on l ine

SharedPreferences settings =PreferenceManager. getDefaultSharedPreferences(context) ;

String difficulty =settings. getString(res. getString(R. string. pref_difficulty) ,res. getString(R. string. difficulty_normal) ) ;

setDifficulty(difficulty) ;

int maxScore =Integer. parseInt(settings. getString(res. getString(R. string. pref_max_score) , "10" ) ) ;

setMaxScore(maxScore) ;

}

Кодинг

Рисунок 8. Сохранение настроек

Листинг 9. SettingsScreen. j ava

public GameManager(SurfaceHoldersurfaceHolder, Context context)

{

. . .

// стили для рисования игрового поля

. . .

// игровые объекты

. . .// игровые объекты

. . .

// применение настроек

Метод setDifficulty приводить не буду, там ничегоособо умного не написано.

Настройки из SharedPreferences можно читать спомощью методов getString, getInt, getBoolean ит.п. Все они принимают два параметра &mdahs;ключ к настройке (то, что мы задавали спомощью атрибута android:key) и значение поумолчанию. Однако, воспользоваться чем-токроме getString мне так и не удалось.

Заключение

Итак, мануал закончен. Получился он огромным,но при этом собственно про андроид оказалосьне так уж и много, что самое-то обидное :(Спасибо, если кто дочитал до конца. Буду радауслышать любые мнения.

Отдельное спасибо xeye и std.denis

Page 50: VR-Online (February 2011)

50

vr-on l ine | февраль 201 1

Защита программы от анализаНестандартные способы вызова функций.

Автор: Evgenij | evgenij .minsk@gmail .com

Иногда у программиста возникает необходимость защитить свою программу иликакие-либо алгоритмы используемые в ней от анализа и последующеговосстановления. В настоящее время существует множество упаковщиков,обфускаторов и другого софта, позволяющего в той или иной мере решать подобнуюзадачу, однако, все они относятся к так называемым внешним (или пристыковочным)методам защиты, то есть тем, которые применяются к уже разработанной программе.

В своей статье я хочу познакомить читателя снекоторыми внутренними методами запутывания(теми, которые применяются программистомвнутри программы), а именно нестандартнымиприемами вызова функций, которые вполнемогут загнать в тупик дизассемблер, отладчик, атакже взорвать мозг аналитику (крутому хакеру,решившему восстановить алгоритм работыпрограммы). Все примеры будут на языке C/C++,иногда будут проскакивать ассемблерныевставки.

Итак, поехали:

1 . Первый и самый простой способ – вызовфункции через указатель на нее:

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

Например, в простейшем случае это может бытьего уменьшение, а затем увеличение на одно итоже число:

Кодинг

pFunction = Function;

. . .

a = pFunction (x, y, z) ;

Вместо обычного вызова функции:

a = Function (x, y, z) ;

Обычный вызов транслируется в машинныекоманды:

push z

push y

push x

call Function

mov eax, a

а вызов функции через указатель транслируетсяв машинные команды:

push z

push y

push x

call [pFunction]

mov eax, a

Дизассемблеру, анализирующему данный

(DWORD) pFunction = (DWORD) Function - 68;

. . .

(DWORD) pFunction += 68;

a = pFunction (x, y, z) ;

2. Вызов функции с помощью машиннойкоманды ret, осуществляющей возврат изфункции:

push offset m

push Function

ret

m:

В этом примере сначала в стек помещаетсясмещение метки m, затем помещается адресфункции Function. После ret будет выполнятьсякод с адреса, помещенного последним в стек, тоесть функция Function. Когда в теле функцииFunction произойдет вызов команды ret,управление будет передано на код после меткиm.

3. Вызов функции через обработкуисключения – простой и в тоже времяинтересный способ запутать как аналитика,так и отладчик.

Например:

try

{

a = 1 / (a – a) ;

}

Page 51: VR-Online (February 2011)

51

февраль 201 1 | vr-on l ine

__except(TRUE)

{

a = Function (x, y, z) ;

}

обработчик этого сообщения, который и вызоветфункцию Function. Аналогичным образом длявызова функции Function можно использоватьфункцию SendMessageCallback.

7. Вызов функции по таймеру(предполагается, что текущий поток несоздает никаких окон, g_s – глобальнаяструктура):

Кодинг

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

__try

{

_asm int 3;

}

__except(TRUE)

{

a = Function (x, y, z) ;

}

Обычно отладчик, в процессе отладки методомStep-Trace (пошагово) последовательноустанавливает в код программы команду int 3(программная точка останова), а прерывание сномером 3 обрабатывается отладчиком. Еслипроделать приведенный пример под отладчиком,то отработает блок __try и никакого исключенияне возникнет, то есть программа не пойдет в блокexcept и функция вызвана не будет =).

4. Вызов функции в отдельном потоке.

Пример:

s. x = x;

s. y = y;

s. z = z;

hThread = CreateThread (NULL, 0, Function,&s, 0, &dw) ;

WaitForSingleObj ect (hThread, TIMEOUT) ;

GetExitCodeThread (hThread, &a) ;

CloseHandle (hThread) ;

5. вызов функции через пул потоков WaitThread:

s. x = x;

s. y = y;

s. z = z;

s. ret = &a;

RtlRegisterWait (&hWait, hEvent1, Function,&s, TIMEOUT1, 0) ;

SetEvent (hEvent1) ;

WaitForSingleObj ect (hEvent2, TIMEOUT2) ;

Функция Function перед возвратом управлениядолжна сделать системный вызов SetEvent(hEvent2);

6. Вызов функции через передачу некоторомуокну нестандартного сообщения:

s. x = x;

s. y = y;

s. z = z;

a = SendMessage (hwnd, WM_USER +HIDDEN_CALLS_GATE, Function, &s) ;

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

g_s. x = x;

g_s. y = y;

g_s. z = z;

g_s. ret = &a;

n = SetTimer (NULL, 0, USER_TIMER_MINIMUM,Function) ;

GetMessage (&msg, NULL, 0, 0) ;

DispatchMessage (&msg) ;

KillTimer (n) ;

8. Вызов функции через перечислениедочерних окон окна, содержащегоединственное дочернее окно:

s. x = x;

s. y = y;

s. z = z;

s. ret = &a;

EnumChildWindows (hwndWithSingleChild,Function, &s) ;

В результате один раз будет вызвана функцияFunction.

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

s. x = x;

s. y = y;

s. z = z;

s. ret = &a;

EnumThreadWindows (GetCurrentThreadId ( ) ,Function, &s) ;

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

s. x = x;

s. y = y;

s. z = z;

s. ret = &a;

EnumPageFiles (Function, &s) ;

11 . вызов функции через асинхронный ввод-вывод:

s. x = x;

s. y = y;

s. z = z;

s. ret = &a;

memset (&o, 0, sizeof(OVERLAPPED) ) ;

o. hEvent = &s;

ReadFileEx (hFile, p, 0, &o, Function) ;

Page 52: VR-Online (February 2011)

52

vr-on l ine | февраль 201 1

Кодинг

Здесь hFile – любой файловый объект, открытыйв асинхронном режиме, p – произвольный адреспамяти, доступный для записи. ВместоReadFileEx можно использовать функцииWriteFileEx, NtReadFile, NtWriteFile,NtDeviceIoControlFi le;

На этом нестандартные способы вызова функцийне заканчиваются. Практически любую

системную функцию, использующую CallBack-функции можно адаптировать под наши нужды,то есть с помощью нее скрыто вызвать туфункцию, которая нам необходима.

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

Page 53: VR-Online (February 2011)

53

февраль 201 1 | vr-on l ine

Программируем на С++Сетевое программирование. Часть 1

Автор: Сергей Дубовик aka sd

Сетевое программирование... Я думаю, что актуальность этой темы не стоитобъяснять, и так понятно, что сегодня сетевые технологии находятся на достаточновысоком уровне развития. А это значит, что программисты в этой области нужны неменее чем в других областях. Вообще, сетевое программирование кажется легче, чемоно есть на самом деле. WinSock функции, которые ты будешь использовать длякоммуникации через сеть, довольно просты в использовании, но многие забывают,что просто вызов функции не сделает всю работу.

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

Сетевое программирование - это больше чемпросто получение или отправление данных.Например, тебе придется столкнуться ссинхронизацией: все ли данные отправлены (илиполучены)? Готова ли программа принятьследующую "порцию" данных? Другая проблема -сверка полученных данных, разбор этих данных,предотвращение угроз безопасности и многоедругое.

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

Весь материал сфокусирован на аспектахсетевого программирования. Я предполагаю, чтоты достаточно хорошо владеешь языкомпрограммирования (С++), что бы успешнопродвигаться по материалу. Что ж. . .приступим.

Сети и протоколы

Любой из вас уже знает что-нибудь про сети,серверы, клиенты и т.д. Но все же я решилначать с введения в организацию и принципработы компьютерных сетей, чтобы бытьуверенным, что ты знаешь достаточно длясетевого программирования. Для сетевогопрограммирования тебе не понадобятся вседетали, упомянутые ниже в этом разделе, нолишними эти знания точно не будут.

Ты, наверное, знаешь, что такое «сеть». Это -несколько компьютеров, соединенных междусобой таким образом, что они могутобмениваться данными. Существует несколькотипов сетей, такие как LAN (Local Area Network),WAN (Wide Area Network) и, конечно же, Internet.

Что бы удостоверится, что весь трафик проходит

без искажений, сети полагаются на протоколы.Протокол – это набор правил, согласно которымданные передаются по сети. Из определенияпонятно, что протокол описывает, как«общаться» через сеть. Протокол подобенчеловеческому языку: почти каждый человек срождения может издавать и слышать какие-тозвуки (электронные сигналы), но люди не будутпонимать друг друга, если они не общаются всоответствии с определенным языком, которыйпонятен им обоим (протокол).

Ethernet

Ethernet — это протокол канального уровня,используемый подавляющим большинствомсовременных локальных сетей. Сеть используетнесколько слоев протокола, каждый из которыхвыполняет свою задачу в коммуникационномпроцессе. Наиболее используемая конфигурациятаких протоколов - ethernet LAN с TCP/IP.

MAC

Низший слой Ethernet интерфейса. Это -аппаратный уровень, называемый уровнеммедиа доступа (Media Access Layer, сокращенноMAC). Этим слоем чаще всего является сетеваякарта, которая заботится о конвертации данных вэлектронные сигналы и передаче их в нужноеместо. Естественно, что пакеты, отправленныепо сети, должны преодолеть определенноерасстояние до нужного адресата. Разные слоипротокола Ethernet имеют разные методыадресации. На нижнем, MAC уровне, адресацияосуществляется с помощью MAC-адресов. MAC-адрес – это 48-битовый идентификатор,«вшитый» в каждую сетевую карту. Проще говоря,MAC-адрес – это физический адрес сетевойкарты. Обычно MAC-адреса записываются ввиде разделенных шестнадцатеричных чисел:1 4:74:A0:1 7:95:D7.

Чтобы отправить данные на другую сетевуюкарту, данные должны включать в себя MAC-адрес получателя. В локальных сетях (LANs)используется простой метод отправки данных

Кодинг

Page 54: VR-Online (February 2011)

54

vr-on l ine | февраль 201 1

Кодинг

нужному адресату: широковещание(broadcasting). Это значит, что твоя сетеваякарта посылает пакет всем другим сетевымадаптерам, которые могут его принять.Каждый принявший адаптер «смотрит» наMAC-адрес конечного адресата и только вслучае совпадения этого MAC-адреса сосвоим собственным сохраняет данные вбуфер. По очевидным причинам запределами LAN (WAN и Internet) этот методне используется.

IP

Сразу над аппаратным уровнем расположен IPуровень. Так же как и MAC уровень, IP тожеимеет свой способ адресации. Для опознаниякомпьютеров на этом слое используются IPадреса. IP адрес состоит из 4-х чисел от 0 до225, разделенных точками. В отличии от MACадресов IP адреса устанавливаются напрограммном, а не аппаратном, уровне. Подобнопредшествующему уровню (забегая вперед,скажу, что и последующим тоже) на IP уровне котправляемым данным прикрепляется IP адресполучателя (и отправителя).

TCP

Следующий слой – TCP слой (или, в качествеальтернативы, UDP). В дополнении к адресу,TCP добавляет порт, по которому должна бытьпередана информация. Если IP-адресаиспользуются для определения компьютера,которому надо передать данные, то портопределяет, какой запущенный процесс долженпринять эти данные. Номер порта 1 6битовый, поэтому ограничен 65536 значениями.

Множество портов связаны с определеннымислужбами. Например, www использует 80 порт,FTP – 21 , e-mail использует 25 (SMTP) и 1 01(POP). Но ничего не мешает выбрать тебе любойдругой порт. Хорошим стилем считаетсяиспользование в своем приложении портов,начиная от 1 024.

В отличии от IP уровня, который не заботится обуспешной передаче, TCP уровень делает именноэто. TCP слой обеспечивает не толькоприбытие данных по назначению, но исохранность этих данных в ходе передачи. Такжеэтот слой позволяет получателю контролироватьпоток данных, т.е. получатель может решить,когда получать данные. Если данные«потерялись» во время передачи, TCPотправляет эти данные заново. Еще однойособенностью TCP является возможностьупорядочивать пакеты, в случае если онипришли не в том порядке, в котором былиотправлены. Это делает нашу жизнь легче, т.к.мы уверены, что данные не только придут, но ипридут в нужном порядке. UDP, как альтернативаTCP, не обладает такими свойствами и не можетгарантировать полную передачу данных. Н UDPобладает рядом других полезных свойств,которых лишен TCP. Поэтому этот протокол тожеимеет право на жизнь. Я не буду писать про UDPв этом разделе, т.к. это не входит в ряднеобходимой, для понимания этого материла,

информации.

Программное обеспечение

Последний уровень - это сетевое ПО. В Windowsтвое приложении взаимодействует с TCP ненапрямую, а с помощью WinSock API .Программный уровень обеспечивает оченьпростой и удобный способ взаимодействия ссетью. Благодаря всем нижележащим слоям,тебе не надо волноваться о пакетах, размерахпакетов, повреждении или потере данных и т.д.За тебя все сделает ОС.

Стек интерфейса Ethernet

Рисунок 1. Процесс передачи данных по сети

На рисунке 1 показана инкапсуляция каждогослоя в протоколе Ethernet. Все начинается спрограммного уровня, в котором содержатсяданные для передачи по сети. Сначала этиданные достигают TCP уровня, на котором к ним(данным) добавляется начальный и конечныйномер порта. Потом IP слой добавляетначальный и конечный адреса. В конце концов,данные подключают к себе MAC адресаотправителя и получателя. Т.е. на картинкепоказан процесс передачи данных по проводам.Как ты мог заметить, этот процесс переполняетпередаваемые данные (на входе у нас один«прямоугольник», а на выходе четыре). Этопереполнение может быть минимизировано спомощью выделения достаточно большогообъема памяти для этих данных. К счастьюWinSock сделает это за нас.

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

DNS

Аббревиатура DNS расшифровывается какDomain Name System (система доменных имен).Эта система применяется для преобразованияимени сервера в его IP адрес. Поскольку не всеми не всегда легко запомнить IP адрес, быласоздана другая система наименований. Теперьвместо IP адреса определенного компьютера всети можно использовать его имя (аналогичнаяситуация с сайтами в интернете). Когда тыподключаешься к какому-нибудь сайту, тебетребуется его IP адрес. То есть, если в строку

Page 55: VR-Online (February 2011)

55

февраль 201 1 | vr-on l ine

браузера ты ввел имя сервера, как напримерwww.google.com, то сначала будет произведенпоиск IP адреса, соответствующего имени google.Это как раз тот момент, когда в дело вступаетDNS. Твой компьютер отправляет поисковойзапрос с именем сервера в DNS твоегопровайдера. Если DNS может обнаружить имясервера, то тебе отправляется соответствующийIP адрес.

Интернет соединения

TCP/IP – протокол, ориентированный насоединении. Соединение осуществляется междудвумя устройствами, каждое из которыхиспользует собственный IP адрес и порт (см.рисунок 2). Обычно одно устройство называютклиентом, другое – сервером.

примерно следующее: TCP xxx.xxx.xxx.xxx:267274.1 25.79.1 47:80 ESTABLISHED. xxx.xxx.xxx.xxx -это мой IP адрес, 74.1 25.79.1 47 – адрес google,значение после двоеточия – номер порта. Как тыможешь заметить, сервер использует порт 80, вто время как клиент использует случайный номерпорта. Каждый подключенный клиент должениметь разный номер порта, т.к. каждоесоединение связано с разными клиентами.

Как итог этого раздела, выделим дваопределения:

Клиент – программа, устанавливающаясоединение и отправляющая запрос.

Сервер – программа, ожидающая входящиесоединения, принимающая их и отвечающая всоответствии с запросами клиента. IP адрес иномер порта сервера должны быть известныклиенту, перед тем как тот (клиент) установитсоединение с сервером.

Снова протоколы

Ранее я затронул несколько протоколов наразных уровнях сетевого интерфейса. Теперьосталось обсудить протоколы, работающие напрограммном уровне, например HTTP, FTP,POP3, SMTP. Большинство этих протоколовработают по типу клиент-сервер. Это значит, чтоклиент отправляет запрос, а сервер на негоотвечает. Точный формат запроса и ответа нанего описан в этих протоколах. Я не буду сейчасобсуждать эти протоколы, но позже, когда тыбудешь знать основы WinSock, мы к нимвернемся.

Сокеты

WinSock (Windows Socket) – это Windows API ,который взаимодействует с сетью. Примечание:Socket переводится с английского языка как«гнездо». Но поскольку употребление русскоговарианта этого слова не совсем вписывается втему этого материала, то я буду использоватьанглийское значение этого слова.

Как говорилось ранее, тебе придется работать ссоединением клиент-сервер. Конечными точкамиэтого соединения являются socket’ы. И у клиента,и у сервера есть socket. Socket связан сопределенным IP адресом и номером порта.Почти все WinSock функции оперируютsocket’ами. С помощью socket’а ты будешьуправлять соединением. Обе «стороны»соединения используют socket’ы, и они (socket’ы)платформенно- независимы. Это значит, чтомашина с Windows может «общаться» по сети сUnix машиной, используя сокеты. По socket’амданные могут передаваться и приниматься.

Выделяют два типа socket’ов: потоковый socket(SOCK_STREAM) и, так называемый,дейтаграммный socket (datagram socket,SOCK_DGRAM). Потоковый вариант разработандля приложений, нуждающихся в надежномсоединении и часто использующемпродолжительные потоки данных. Протокол,использующийся для данного типа socket’ов –TCP. В этом материале будет использоватьсятолько потоковый тип socket’ов, т.к. он чаще

Кодинг

Рисунок 2. Соединение

Клиент – это «сторона» соединения, котораязапрашивает определенные данные, а серверотвечает в соответствии с этими запросами.Например, когда открывается сайт, интернет-обозреватель выступает в роли клиента, асервер, на котором расположен сайт, - в ролисервера. Обозреватель устанавливаетсоединение с сервером и запрашиваетопределенные данные. В ответ на это серверпосылает обратно запрос и запрашиваемуюинформацию.

Сервер непрерывно ждет поступающиесоединения. Это называется прослушиванием(l istening), которое всегда происходит поопределенному IP адресу и порту. Клиент всеголишь подключается, когда необходимо, т.к.клиент всегда инициатор соединения иотправитель запросов. Чтобы создатьсоединение, клиент должен знать IP адрес иномер порта, по которым сервер производитпрослушивание.

И клиент, и сервер используют определенные IPадрес и номер порта, но обычно у сервера портфиксированный. Стандартный порт для сайтов –80. Например, на момент написания статьи, усайта www.google.ru был IP адрес 74.1 25.79.1 47и порт 80. Каждый подключившийся к сайтуклиент устанавливал соединение с этим IPадресом по 80-му порту. Таким образом, серверможет принимать множество клиентов по одномупорту. На клиентской «стороне» соединения портневажен, т.е. может быть использован любойпорт. Некоторые думают, что номер порта с обеих«сторон» соединения должен быть одинаков. Этоне так. Введи в командной строке «netstat –an»после того как зайдешь на сайт. Ты увидишь

Page 56: VR-Online (February 2011)

56

vr-on l ine | февраль 201 1

Кодинг

всего используется в хорошо известныхпротоколах, таких как SMTP, POP3, HTTP,TCP.

Дейтаграммные socket’ы используют UDPпротокол и имеют низкий сигнал соединенияи большой размер буфера данных. Ониприменяются в приложениях, которыеотправляют данные малых размеров и ненуждаются в идеальной надежности. Вотличии от потоковых socket’ов,дейтаграммные socket’ы не гарантируютстопроцентной передачи данныхполучателю, как и не гарантируют передачиданных в нужном порядке. Данный типsocket’ов полезнее для приложений, гденадежность не является высокимприоритетом, таким как скорость (напримераудио или видео трансляция). Вприложениях, которые нуждаются внадежности, целесообразней использоватьпотоковые сокеты.

Связывание (binding) socket’ов

Связать socket значит «прикрепить»определенный адрес (IP адрес и номер порта) кданному socket’у. Это можно сделать вручную,используя связывающую функцию, но внекоторых случаем WinSock сам автоматическисвяжет socket. Более подробно об этом будетрассказано далее в этом разделе.

Соединение

Способ использования socket’ов зависит от того,где ты их используешь: на клиентской илисерверной части. Клиентская часть создаетсоединение путем создания socket’а и вызовомсоединяющей функции с определенной адреснойинформацией. До того как socket не соединится,он не будет связан с адресом. Это связано с тем,что клиент может использовать любой адрес (IPадрес и номер порта) для соединения ссервером.

Когда соединение вызвано, WinSock выберет IPадрес и номер порта для соединения и свяжет сними socket до того, как клиент фактическисоединится с сервером. Номером порта можетбыть любой номер, который свободен в моментсоединения, с выбором IP адреса надо бытьаккуратнее. Компьютеры могут иметь болееодного IP адреса. Например, компьютер,подключенный к локальной сети и к интернету,имеет три IP адреса: внешний дляиспользования интернета; адрес в локальнойсети (1 92.1 68.x.x или 1 0.0.x.x и т.д.); адрес, такназываемой «внутренней петли»(loopback), дляобозначения «локального хоста» в сети из одногокомпьютера (1 27.0.0.1 ). Здесь выбор IP адреса, скоторым связан socket, имеет значение, т.к. такжеопределяет сеть, которую ты используешь длясоединения. Если ты хочешь подключиться клокальному компьютеру 1 92.1 68.0.4, ты несможешь сделать это через сеть интернетпровайдера. Тебе потребуется связать socket сВашим IP адресом в такой же сети (1 92.1 68.0.1 ,например).

К счастью, WinSock сам выберет IP адрес на

твоем компьютере, который можетиспользоваться для соединения с нужнымадресом. Ничего не мешает тебе связать socketсамостоятельно, но помнишь, что ты долженвзять ситуацию, описанную выше, во внимание.Так же связывающая функция даетпользователю возможность установить IP адресили номер порта в нулевое значение. В этомслучаем нулевое значение значит «пускайWinSock выберет что-нибудь для меня». Этополезно, когда ты хочешь подключиться,используя определенный IP адрес, но, неуказывая значение порта.

Прослушивание

На «стороне» сервера дела обстоят немногоиначе. Сервер ждет входящих соединений иклиенту необходимо знать IP адрес и номерпорта сервера, чтобы установить соединение.Чтобы упростить дело, на сервере всегдаиспользуется фиксированный номер порта(обычно это - порт, предусмотренный протоколомпо умолчанию).

Ожидание входящего соединения поопределенному адресу называетсяпрослушиванием (l istening). Обычно, перед темкак «войти» в режим прослушивания, socketдолжен быть связан с определенным адресом.Когда номер порта этого адреса установлен изафиксирован (т.е. не изменится), серверначинает ждать входящие соединения по этомупорту. Например, 80 порт (порт по умолчаниюдля HTTP) прослушивается большинствомсерверов.

Когда клиент запрашивает соединение ссервером, сервер разрешит ему (или нет) ипородит новый socket, который будет конечнойточкой связи. Благодаря этому, socket, покоторому происходило прослушивание, неиспользуется для передачи данных и можетнаходиться в режиме прослушивания дальше,«принимая» новых клиентов.

Соединения: примеры

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

1 ) Создание socket’а для сервера

Рисунок 3. Создание socket’ а для сервера

Сервер создает новый socket. Вновь созданныйsocket еще не связан с IP адресом и портом.

2) Связь socket’а (см. рисунок 4)

Так как наш сервер является сервером какого-нибудь сайта, то порт установлен 80 (порт поумолчанию для HTTP). Однако IP адрес

Page 57: VR-Online (February 2011)

57

февраль 201 1 | vr-on l ine

установлен «нулевой», указывая на то, чтосервер готов получить соединение от любого IPадреса, доступного компьютеру, на котором онзапущен. В этом примере мы предполагаем, чтоу сервера есть три IP адреса: внешний,внутренний и адрес «внутренней петли».

снизу на рисунке) , связывая его с одним изадресов, который может «достичь» клиент (внашем примере клиент и сервер в однойлокальной сети, поэтому IP любой в диапазоне1 92.1 68.x.x). Socket клиента и socket сервера дляподключения (подключенный socket на рисунке)будут осуществлять передачу данных друг другу,в то время как прослушивающий socket будетждать новое соединение. Заметь, что socketклиента связан с IP адресом и номером портаклиента пока клиент подключен к серверу. Сераяпунктирная линия на рисунке являетсяразделительной линией между серверной иклиентской стороной.

7) Подключение других клиентов (см. рисунок 9)

Кодинг

Рисунок 4. Связь socket’ а

3) Сервер в режиме прослушивания

Рисунок 5. Сервер в режиме прослушивания

После того как socket связан с определеннымадресом, он «переходит» в режимпрослушивания и ждет входящих соединений по80ому порту.

4) Создание socket’а для клиента

Рисунок 6. Создание socket’ а для клиента

Предположим, что клиент и сервер находятся водной локальной сети. Клиент хочет запроситьстраницу с сервера. Чтобы передача данныхосуществлялась, клиенту необходим socket,поэтому он и создает его.

5) Подключение клиента к серверу

Рисунок 7. Подключение клиента к серверу

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

6) Сервер принимает соединение (см. рисунок 8)

Прослушивающий socket замечает, что кто-топытается подключиться. Он разрешаетподключение, создавая новый socket (справа

Рисунок 8. Сервер принимает соединение

Рисунок 9. Подключение других клиентов

Если другой клиент (из внешней сети)подключается, сервер создает еще один socketдля взаимодействия с ним (новым клиентом).Заметь, что IP адрес, с которым связываетсятолько что созданный socket, отличается от того,с которым связался первый socket. Этовозможно, потому что прослушивающий socketсервера не связан с определенным IP адресом.Если бы он был связан с адресом 1 92.1 68.0.8, товторой клиент не смог бы подключится.

Блокирование

Возможны ситуации, когда при подключении ксерверу, используя соединительную функцию,эта функция не завершится, пока соединение небудет установлено (или провалено). Такимобразом твоя программа будет «висеть»

Page 58: VR-Online (February 2011)

58

vr-on l ine | февраль 201 1

Кодинг

некоторое время. Это - не проблема, еслииспользуется единственное соединение вконсольном приложении, но в Windowsприложениях это является недопустимойситуацией. В любом оконном приложении естьпроцедура, которая всегда должна выполняться.Остановка этой процедуры задержала бы вводпользовательских данных, прорисовку окна,уведомления программы и другие сообщения. Ав то время, в использовании соединительнойфункции возникли какие-то проблемы,произойдет именно это.

Для решения этой проблемы WinSock позволяетустанавливать socket’ы в блокирующий (blocking)и не блокирующий (non-blocking) режим. Первыйрежим не позволит переключиться к основнойзадаче программы, пока не завершится функциясоединения (это практически заблокирует твоеприложение). Второй режим обычноиспользуется в windows приложениях. Прииспользовании неблокирующей функции,функция будет пытаться завершиться как можнобыстрее, даже если она не может завершитьсямгновенно. По завершении функции в программубудет послано уведомление, что операциязакончена, позволяя программе работать внормальном режиме, в то время как функцияеще не завершилась.

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

Версии WinSock

В большинстве случаев используется версияWinSock 2.х, обычно называемая WinSock 2, т.к.различия небольшие. Последней популярнойверсией до второй, был WinSock 1 .1 . Некоторыемогут сказать, что надо использовать именно этуверсию, т.к. Windows 95 поддерживает только ее,но кто в наши дни пользуется Windows 95?Поэтому я рекомендую тебе использоватьWinSock версии 2. Две основных версии WinSock«проживают» в двух .DLL - wsock32.dl l иws2_32.dl l . В первой – версия 1 .1 , а во второй –WinSock2. В С++ достаточно подключитьwindows.h и winsock2.h для использованияфункций WinSock в своей программе. Далее вматериале будет рассмотрен WinSock второйверсии.

Архитектура WinSock

WinSock обеспечивает два интерфейса: API иSPI(Service Provider Interface – ИнтерфейсОбеспечения Служб). В этом материале будетрассмотрен только API , в нем содержатся всенеобходимые функции для использованиянужный протоколов. SPI – интерфейс, которыйдобавляет «поставщиков передачи данных»(Data Transport Providers) как, например TCP/IPили IPX/SPX. Также SPI добавляет «поставщиковименных служб» (Name Space Service Providers),таких как DNS. Но все эти добавления«прозрачны» для пользователей API и не видныим.

В этом разделе я расскажу про базовые WinSock

функции, которые производят различныеоперации над socket’ами. Важно помнить, чтоэтот раздел всего лишь введение в WinSockфункции, что бы Вы могли без каких-либонепонятных моментов перейти к следующемуразделу.

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

Этот раздел будет довольно длинным, и тыможешь не запомнить весь материал, но это нестрашно. Просто читайте этот разделвнимательно, что бы Вы понимали, о чем я будуговорить в следующих главах. Вы всегда можетевернуться назад и посмотреть информацию о,нужной Вам, функции.WSAStartup и WSACleanupint WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData) ;int WSACleanup() ;

Перед вызовом любой WinSock функции, Выдолжны инициализировать библиотекуWs2_32.dl l . Это делается с помощьюWSAStartup. Функция принимает два параметра:wVersionRequested

Максимальная версия Windows Socket, которуюможет использовать вызывающая программа.Старший байт содержит младшую часть номераверсии, младший байт содержит старшую частьномера версии.lpWSAData

Указатель на структуру WSADATA, которая, врезультате выполнения функции, будетсодержать детали реализации Windows Sockets.

Как я говорил ранее, я буду использоватьWinSock2. Это значит, что младший байт первогопараметра мне надо указать 2, а старший можетбыть и нулем. Структура WSDATA, определеннаяпараметром lpWSAData, получит информацию оверсии WinSock, установленной на Вашемкомпьютере.

В случае успешного выполнения, функцияWSAStartup возвращает 0. В противном случае,возвращается один из кодов ошибки,приведенных в таблице. Если выполнениефункции WSAStartup окончилось неудачей, вы несможете определить код ошибки с помощьюWSAGetLastError. Это получается потому, что вслучае сбоя, библиотека Ws2_32.dl l не будетзагружена, и область памяти, где сохраняетсяинформация о последней ошибке, не доступна.Но при желании можно попробовать получитькод ошибки с помощью API функции GetLastError.

Однако, Вы можете не получить, нужную Вам,версию в параметр wVersionRequested. Дело вто, что приложение, вызвавшее WSAStartup, ибиблиотека Ws2_32.dl l обмениваются номерамимаксимальной версии, которую ониподдерживают. Ws2_32.dl l проверяет версию,

Page 59: VR-Online (February 2011)

59

февраль 201 1 | vr-on l ine

требуемую приложением. Если эта версияравна или выше чем низшая версия,поддерживаемая библиотекой, то вызовсчитается успешным и библиотекавозвращает в wHighVersion номер самойвысшей версии, которую она поддерживает ив wVersion номер версии, котораяпредлагается приложению. Если значениепараметра wVersion структуры WSADATAнеприемлемо для приложения, то онодолжно вызвать функцию WSACleanup иискать другую Ws2_32.dl l или вернуть сбойинициализации.

Это справедливо для приложений,написанных с использованием младшихверсий, для успешной работы со старшимиверсиями библиотеки. В этом случаеприложение гарантирует доступ только кфункциональности, совместимой посинтаксису с текущей версией. Для полногодоступа к новому синтаксису будущихреализаций, приложение должно полностьюсоответствовать этой реализации -откомпилировано с новыми заголовочнымифайлами, слинковано с новымибиблиотеками.

Выше я упомянул функцию WSACleanup.Каждому вызову функции WSAStartupдолжен соответствовать вызов WSACleanup,которая освобождает ресурсы, полученные уWindows для работы с WinSock.

Пример использования этих функций (см.листинг 1 ):

socket()SOCKET socket(int af, int type, intprotocol) ;

Функция socket() создает новый socket ивозвращает его дескриптор. Тип этогодескриптора SOCKET и он используется во всехфункциях, работающих с socket’ами.Единственным недействительным значениемдескриптора socket’а является INVALID_SOCKET.

Функция принимает три параметра:

af - address family, так называемое, адресноесемейство. Этот параметр накладываетопределенные ограничения на форматиспользуемых процессом адресов и ихинтерпретацию. Установите этот параметр взначение AF_INET, что бы использовать TCP иUDP «семейство».

type – тип создаваемого socket’а. ИспользуйтеSOCK_STREAM для создания потоковогоsocket’а и SOCK_DGRAM для созданиядейтаграммного socket’а.

protocol – протокол, который будетиспользоваться socket’ом. Этот параметрзависит от «адресного семейства». Что бысоздать TCP socket, Вам нужно указатьIPPROTO_TCP.

Функция возвращает дескриптор созданногоsocket’а, или INVALID_SOCKET, если что тослучилось не так.

Функцию socket() можно использоватьследующим образом (см. листинг 2):

Кодинг

Листинг 1. Пример использования WSAStartup иWSACleanup

const int iReqWinsockVer = 2; //Минимальная требуемая версия

WSADATA wsaData;

if (WSAStartup(MAKEWORD(iReqWinsockVer, 0) ,&wsaData) ==0)

{

// Проверяем если старшая версия большеили равна требуемой

if (LOBYTE(wsaData. wVersion) >=iReqWinsockVer)

{

/* Вызываем тут различные WinSockфункции */

}

else{

// Требуемая версия недоступна.

}

// Освобождаем WinSock

if (WSACleanup( ) ! =0)

{

// Освобождение не удалось

}

}

else{

// Инициализация не удалась

}

Листинг 2. Пример использования функцииsocket()

SOCKET hSocket;

hSocket = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP) ;

if (hSocket==INVALID_SOCKET)

{

// Действия в случае ошибки

}

closesocketint closesocket(SOCKET s) ;

Как понятно из названия, эта функция закрываетsocket. Функция возвращает ноль, если всепрошло успешно, иначе результатом выполненияфункции будет SOCKET_ERROR. Каждыйсозданный Вами socket с помощью функцииsocket(), должен быть закрыт с помощьюфункции closesocket().

В функцию передается единственный параметр –дескриптор socket’а, который необходимозакрыть. Не пытайтесь использовать этот socketпосле вызова функции closesocket(). В лучшемслучае компилятор заметит ошибку.

Использование этой функции довольно простое(см. листинг 3).

Однако, в реальный ситуациях, необходимо

Page 60: VR-Online (February 2011)

60

vr-on l ine | февраль 201 1

Кодинг

немного больше операций, что бы закрыть socketдолжным образом. Это мы рассмотрим немногопозднее.

наше число 0x1 2345678 будет храниться в такойпоследовательности: 0x78, 0x56, 0x34, 0x1 2(порядок байтов от младшего к старшему, англ.l ittle-endian). Однако большинство машиниспользуют противоположный порядок, т.е. болеезначимый байт хранится вначале. В такихмашинах наше число будет храниться в виде0x1 2, 0x34, 0x56, 0x78. Поскольку протоколы, покоторым будут переданы данные между двумякомпьютерами, могут иметь разные байтовыепорядки, то необходим стандарт, чтобыпрепятствовать передаче данных неправильнымобразом.

Поскольку такие протоколы, как TCP/IP работаютмежду разными системами с разным порядкомбайтов, то был разработан стандарт - порядок отстаршего к младшему (big-endian). Записьначинается со старшего байта и заканчиваетсямладшим. Например, 1 6-битовый номер порта1 2345 (0x3039) в этом представлении будетвыглядеть так: сначала 0x30, потом 0x39, т.е.более значимый байт идет сначала. 32-битовыйIP адрес хранится аналогичным образом: каждаячасть IP адреса хранится в одном байте, ипервая часть хранится в первом байте.Например IP адрес 21 6.239.51 .1 00 будетхраниться в такой последовательности байтов:21 6,239,51 ,1 00. Этот порядок являетсястандартным для протоколов TCP/IP, ониспользуется в заголовках пакетов данных и вомногих протоколах более высокого уровня,разработанных для использования поверхTCP/IP. Поэтому, порядок байтов от старшего кмладшему часто называют сетевым порядкомбайтов (network byte order).

Кроме параметров sin_family и sa_family вструктурах sockaddr_in и sockaddrсоответственно, которые не являются частьюпротокола, но говорят WinSock, какое «адресноесемейство» использовать, все остальные поляэтих структура хранятся в сетевом порядкебайтов.

WinSock обеспечивает несколько функций дляпреобразования порядка байтов локальноймашины в сетевой порядок байтов (см. листинг6):

Листинг 3. Пример использования функцииclosesocket()

closesocket(hSocket) ;

sockaddr и порядок байт

WinSock был разработан таким образом, что быон мог взаимодействовать с разнымипротоколами, включая те, которые должны бытьдобавлены позднее. Поэтому был разработанобщий способ адресации. Например TCP/IPиспользует IP адрес и номер порта дляопределения адреса, но другие протоколы могутделать это по-другому. Если бы WinScokпридерживался определенного типа адресации,то добавление других протоколов было быневозможным.

Первый вариант решения этой проблемы –использование структуры sockaddr (см. листинг4):

Листинг 4. Структура sockaddrstruct sockaddr

{

u_short sa_family;

char sa_data[ 14] ;

} ;

Первое поле этой структуры определяет«адресное семейство» адреса. Данные,хранящиеся в переменной sa_data, могутменяться в зависимости от «адресногосемейства». В этом материале мы будемиспользовать только интернет-«адресноесемейство». В WinSock определена структураsockaddr_in, которая является TCP/IP версиейструктуры sockaddr (см. листинг 5).

Листинг 5. Структура sockaddr_instruct sockaddr_in {

short sin_family;

unsigned short sin_port;

struct in_addr sin_addr;

char sin_zero[ 8] ;

} ;

Последние 8 байт структуры не используются.Они предусмотрены для того, что бы датьструктуре нужный размер (такой же как уструктуры sockaddr) .

Перед тем, как двигаться дальше, необходимознать про сетевой порядок байт. Под «порядкомбайт» будем понимать последовательность, вкоторой хранятся значения, охватывающиенесколько байт. Например, 32-битовоецелочисленное значение 0x1 2345678 охватывает4 8-битовых байта. Некоторые компьютерыиспользуют порядок байт, в котором менеезначимые байты сохранены сначала. То есть

Листинг 6. Функции для преобразования порядкабайтов// Преобразует u_short из порядка байтовлокальной машины в сетевой порядок байтов

u_short htons(u_short hostshort) ;

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

u_long htonl(u_long hostlong) ;

// Преобразует u_shorth из сетевого порядкабайтов в порядок байтов локальной машины

u_short ntohs(u_short netshort) ;

// Преобразует u_long из сетевого порядкабайтов в порядок байтов локальной машины

u_long ntohl(u_long netlong) ;

Вы можете спросить, зачем нам надо четыре API

Page 61: VR-Online (February 2011)

61

февраль 201 1 | vr-on l ine

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

Вернемся к структуре sockaddr_in. Как писалосьвыше, все параметры кроме sin_family имеютсетевой порядок байтов. Этот параметр у насиспользуется в значении AF_INET. sin_port – это1 6-битовый номер порта, sin_addr – 32-битовыйIP адрес. sin_zero не используется, этотпараметр нужен что бы придать структуренужный размер.

Вот пример заполнения полей структурыsockaddr_in (см. листинг 7):

namelen – размер структуры, в которойсодержится имя.

Первый параметр – это клиентский socket,использующий соединение, например, только чтосозданный socket с помощью функции socket().Остальные два параметра, name и namelen,используются для адресации удаленного socket’а(socket сервера, который находится в режимепрослушивания).

Эту функцию применяют для соединения ссервером. Что бы обратиться к серверу, Выможете использовать структуру sockaddr_in,заполнив ее IP адресом и номером портасервера. Вы можете поинтересоваться, какполучить IP адрес сервера, например, www.vr-onl ine.ru. Позже я покажу как это сделать. Покачто просто представьте, что вы его знаете.

Представим, что сервер запущен в локальнойсети, на компьютере с IP адресом 1 92.1 68.0.5,используя HTTP порт по умолчанию (80). Код,позволяющий подключится к этому серверу,выглядит примерно так (см. листинг 8):

Кодинг

Листинг 7. Заполнения полей структурыsockaddr_insockaddr_in sockAddr1, sockAddr2;

// Устанавливаем адресное семейство

sockAddr1. sin_family = AF_INET;

// Преобразуем номер порта 80 в сетевойпорядок байтов

sockAddr1. sin_port = htons(80) ;

/* inet_addr преобразует строку с IP адресомв long значение,

которое является IP адресом в сетевомпорядке байтов.

sin_addr. S_un. S_addr определяет longзначение в адресном объединении */

sockAddr1. sin_addr. S_un. S_addr =inet_addr("127. 0. 0. 1" ) ;

// Устанавливаем адрес sockAddr2,устанавливая значение каждой из 4 байтовойчасти:

sockAddr2. sin_addr. S_un. S_un_b. s_b1 = 127;

sockAddr2. sin_addr. S_un. S_un_b. s_b2 = 0;

sockAddr2. sin_addr. S_un. S_un_b. s_b3 = 0;

sockAddr2. sin_addr. S_un. S_un_b. s_b4 = 1;

Функция inet_addr, в вышеприведенном примере,преобразует строковое значение IP адреса(записанного в «точечном» формате) всоответствующее 32-битовое значение в сетевомпорядке байтов. Также существует функцияinet_ntoa, которая делает тоже самое, тольконаоборот.connectint connect(SOCKET s, const struct sockaddr*name, int namelen) ;

Функция connect соединят socket с удаленнымsocket’ом. Эта функция используется наклиентской стороне подключения, т.к. именноклиент является инициатором подключения.

Краткое описание параметров этой функции:

s – неподключенный socket, который Вы быхотели подключить.

name - указатель на структуру sockaddr, вкоторой содержится имя (адрес) удаленногоsocket’а, к которому необходимо подключится.

Листинг 8. Подключение к серверу// Этот код подразумевает, что socket былсоздан, и его дескриптор хранится в hSocket

sockaddr_in sockAddr;

sockAddr. sin_family = AF_INET;

sockAddr. sin_port = htons(80) ;

sockAddr. sin_addr. S_un. S_addr =inet_addr("192. 168. 0. 5" ) ;

// Подключаемся к серверу

if (connect(hSocket, (sockaddr*) (&sockAddr) ,sizeof(sockAddr) ) ! =0)

{

// Действия в случае неудачногоподключения

}

/* Замечение: приведение (sockaddr*)необхадимо, т. к. соединение требуетпеременную типа

sockaddr, а тип переменной sockAddrsockaddr_in. Преобразование безопасно, т. к.оба типа имеют схожую структуру, нокомпилятор видит их как два разных типа*/

bindint bind(SOCKET s, const struct sockaddr*name, int namelen) ;

Связывание socket’а было рассмотрено впредыдущих главах. Напомню, что эта функциясвязывает адрес с socket’ом.

Параметры:

s – несвязанный socket, который требуетсясвязать.

name – указатель на структуру sockaddr, вкоторой содержится адрес необходимогоsocket’а.

namelen – размер структуры, в которойсодержится имя.

Page 62: VR-Online (February 2011)

62

vr-on l ine | февраль 201 1

Кодинг

Для TCP/IP структура sockaddr_in может бытьиспользована как обычно. Давайте сначалавзглянем на пример (см. листинг 9):

Например, если Вы связали socket с 80 портом, ипоставили его в режим прослушивания, то все,входящие по 80 порту, подключения будутнаправлены в Ваше приложение. Что быразрешить соединение, должна быть вызванафункция accept. Она будет рассмотрена далее.

Следующий фрагмент кода показывает, каквызвать функцию listen для связанного socket’а(см. листинг 1 0).

Листинг 9. Пример использования функции bindsockaddr_in sockAddr;

sockAddr. sin_family = AF_INET;

sockAddr. sin_port = htons(80) ;

sockAddr. sin_addr. S_un. S_addr = INADDR_ANY;// используем адрес по умолчанию (т. е. любой)

// Связываемся в 80 портом

if (bind(hSocket, (sockaddr*) (&sockAddr) ,sizeof(sockAddr) ) ! =0)

{

// Действия в случае ошибки

}

Как Вы можете заметить, структура sockaddr_inзаполняется необходимой информацией.«Адресное семейство» используется AF_INETдля TCP/IP. В этом примере мы связали socket с80 портом, но не с IP адресом. УказываяINADDR_ANY в качестве значение IP адреса,WinSock выберет адрес за Вас. Это может бытьполезно на компьютерах с несколькимисетевыми адаптерами (в нашем примерерассматривается именно такой компьютер) илиподключениями. Если Вы сами хотите указать IPадрес, просто преобразуйте его в DWORD ссетевым порядков байтов и присвойте этозначение соответствующему полю структуры.Подобное возможно проделать и с номеромпорта; если вы укажите нулевое значение порта,то WinSock подберет уникальный номер порта, сзначением между 1 024 и 5000. Однако, вбольшинстве случаев Вам придется указыватьномер порта самостоятельно.

Связывание socket’а обычно производится передтем, как он (socket) перейдет в режимпрослушивания, что бы socket прослушивалнужный порт.listenint listen(SOCKET s, int backlog) ;

Эта функция устанавливает socket в режимпрослушивания. Она получает два параметра:

s – связанный, неподключенный socket, которыйВы хотите установить в режим прослушки

backlog – максимальное количество ожидаемыхсоединений.

Максимальное количество, передаваемое впараметр backlog, сильно зависит от платформы.В linux оно обрезается до SOMAXCONN. В win32,если передано SOMAXCONN, провайдерсервиса отвечает за установку backlog socket’а вмаксимальное разумное значение. На этойплатформе нет стандарта для установкиреального backlog-значения. Так как мыиспользует Windows, то мы смело можемустановить этот параметр в значениеSOMAXCONN.

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

Листинг 10. Пример использования функцииlisten// Этот код подразумевает, что socket былсоздан, и его дескриптор хранится в hSocket

if (listen(hSocket, SOMAXCONN) ! =0)

{

// Действия в случае ошибки

}

acceptSOCKET accept(SOCKET s, struct sockaddr*addr, int *addrlen) ;

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

s – socket, который был установлен в режимпросулшивания.

addr – указатель на буфер, который получаетадрес удаленного socket’а. Этот параметр –указатель на структуру sockaddr, но он требуетструктуру, определенную «адреснымсемейством».

addrlen – указатель на целое число, котороесодержит длину addr. Перед вызовом функции,этот параметр должен иметь размер буфера, накоторый указывает addr. По завершениифункции, в этом параметре будет хранитьсяразмер полученных данных.

Как Вы уже знаете, если соединение былоразрешено, на сервере создается новый socket.Этот новый socket соединяется с socket’омклиента и все операции между сервером иклиентом проводятся именно по этому socket’у.Socket, который находился в режимепрослушивания, продолжает ждать новыесоединения (см. листинг 11 ).

Листинг 11. Пример использования функцииacceptsockaddr_in remoteAddr;

int iRemoteAddrLen;

SOCKET hRemoteSocket;

iRemoteAddrLen = sizeof(remoteAddr) ;

hRemoteSocket = accept(hSocket,(sockaddr*) &remoteAddr, &iRemoteAddrLen) ;

if (hRemoteSocket==INVALID_SOCKET)

{

// Действия в случае ошибки

}

При успешном завершении функции,возвращаемое значение – дескриптор нового

Page 63: VR-Online (February 2011)

63

февраль 201 1 | vr-on l ine

socket’а.send and recvint send(SOCKET s, const char *buf, int len,int flags) ;

s – подключенный socket, для передачи данных.

buf – буфер, содержащий данные для отправки.

len – размер данных для передачи.

flags – определяет способ передачи данных.

int recv(SOCKET s, char *buf, int len, int flags);

s – подключенный socket, для получения данных.

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

len – размер полученных данных.

flags – определяет способ получения данных.

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

В блокирующем режиме функция send«заблокирует» Ваше приложение, пока вседанные не будут переданы.

Хотя на первый взгляд эти функции кажутсяпростыми, они становятся сложнее для работы внеблокирующем режиме. Когда socket находитсяв неблокирующем режиме, эти функции могут невыполнить операцию полностью. В следующейглаве эта проблема будет рассмотренадетальным образом, а пока что примериспользования этих функций в блокирующемрежиме (в этом примере будут отправленыполученные данные) (см. листинг 1 2):

Листинг 12. Пример использования функций sendи recvchar buffer[ 128] ;

while(true){

// Получаем данные

int bytesReceived = recv(hRemoteSocket,buffer, sizeof(buffer) , 0) ;

if (bytesReceived==0) // соединениезакрыто

{

break;

}

else if (bytesReceived==SOCKET_ERROR)

{

// Действия при ошибке

}

// Отправляем полученные данные обратно

if (send(hRemoteSocket, buffer,bytesReceived, 0) ==SOCKET_ERROR)

{

// Действия при ошибке

}

}

Кодинг

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

Как отмечалось в начале главы, это был всеголишь обзор основных WinSock функций. Однакознать, как и что делают эти функции недостаточно для корректной работы с ними. Вследующих главах мы научимся правильноработать с этими функциями, рассмотрим какиесуществуют «входные/выходные модели» (I /OModels) и узнаем как работают блокирующий ине блокирующий режимы.

Page 64: VR-Online (February 2011)

64

vr-on l ine | февраль 201 1

Программируем на C++Делаем свою секцию данных в PE

Автор: Голубниченко Юрий aka Ghost Rider

PE (Portable Executable) - формат исполняемых файлов, объектного кода идинамических библиотек, используемый в 32- и 64-битных версиях операционнойсистемы Microsoft Windows. Формат PE представляет собой структуру данных,содержащую всю информацию, необходимую PE загрузчику для проецированияфайла в память (по материалам Wikipedia). Сегодня мы поговорим о том как сделатьсобственную секцию данных в PE файле.

А зачем?

Во-первых, некоторые компиляторы вольнывставлять строковые данные в сегмент кода, темсамым засоряя его. Насколько мне известно,компиляторы, некогда существовавшей Borlandособенно этим грешили.

Во-вторых, это хороший способ спрятать своиданные от юных крэкеров, а в совокупности схорошим крипто алгоритмом можно отпугнуть икрэкера средней руки. Профи этим, конечно жене остановить и тут надо хорошенько “поломатьголову”, но это уже другая история. И так давайпроведем пару экспериментов и посмотрим, чтоиз этого выйдет. Для опытов нам потребуется:

1 . Компилятор C++ (Майкрософсткий). Я будуиспользовать Visual Studio 2005;

2. IDA Pro. Можно использовать dumpbin (входитв поставку Visual Studio). Если ни того ни другогоу тебя нет, то можно использовать любой HEXредактор, ну или утилиту для просмотра секцийPE файла. Для наглядности я буду применятьIDA Pro.

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

{

char buffer_nik[ 50] ; //буфер под вводника

char buffer_pas[ 20] ; //буфер под вводпароля

//Ввод ника

printf("Vvedite nik: > " ) ;

fgets(&buffer_nik[ 0] , 50, stdin) ;

//ввод пароля

printf("Vvedite parol: > " ) ;

fgets(&buffer_pas[ 0] , 20, stdin) ;

//сравнение введенных данных сконстантами

if( (strcmp(&buffer_nik[ 0] , UserName) ) &(strcmp(&buffer_pas[ 0] , Password) ) )

printf("OK. " ) ;else

printf("Wrong Pas or Nik" ) ;

return 0;

}

Кодинг

Листинг 1. Простая программа на C++#include "stdafx. h"

#include "windows. h"

//Объявляем константы

#define UserName "Ghost Rider";

#define Password "12345" ;

//Левые данные

#define Login_for_Admin "Super Admin";

#define Password_Admin "AdminPassword=12345" ;

int _tmain(int argc, _TCHAR* argv[ ] )

Не будем подробно рассматривать этот код (всепояснения я привел в комментариях), а сразуоткомпилируем его, а затем откроемполучившийся exe’шник в IDA Pro. Послеанализа файла, IDA любезно предоставит тебевсю необходимую информацию. Однако насинтересуют секции данных, поэтому щелкай повкладке “String window”. Ты увидишьизображение как на рисунке 1 .

На рисунке 1 нам видно, что все наши данныехранятся в открытом виде в секции .rdata(следует заметить, что названия секций невсегда предваряются точкой, просто такпринято).

И про dumpbin я не забыл

В командной строке набирай dumpbin (не забудьнабрать полный путь к dumpbin)

Page 65: VR-Online (February 2011)

65

февраль 201 1 | vr-on l ine

/RAWDATA:BYTES /SECTION:.rdata example.exe(путь к нашему exe’шнику). Эта командапозволяет вывести содержимое определеннойсекции. Выходную информацию можноперенаправить в файл (так проще разбираться).Для этого дописываем в конце example.exe>fi le. txt. Если опустить параметр/RAWDATA:BYTES, то dumpbin выведетинформацию о секции .rdata - смещение, адрессекции (см. рисунок 2) и т.д.

информации обратись к документациииспользуемого компилятора). Однако общиеправила все же есть:

- Секции . idata, .data, .rdata – содержат данныепрограммы (строки, числа и все остальное, чтоне жалко);

- . text – сам код программы. В секции .bss обычнонаходятся неинициализированные переменные ивсе в этом духе.

Поскольку мы воспользовались компиляторомC++, то все ниже описанное будет работатьтолько в нем (однако принцип для всех и всяодин и тот же, лишь реализация разная, но содной оговоркой, если компилятор вообщеподдерживает создание новых секций). Если жеты столкнулся с таким компилятором, то я знаютолько два пути решения проблемы с созданиемновой секции. Первый - сменить компилятор,второй - взять в руки дизассемблер + другие“низкоуровневые” инструменты и вручнуюначинать ковырять свежеиспеченный exe’шник.Для того чтобы создать новую секцию данных вC++ воспользуемся программой data_seg.Запишем данные во вновь созданную секцию ивернемся к старой секции (см. листинг 2).

Кодинг

Рисунок 1. Смотрим секции данных в Ida Pro

Рисунок 2. Секция . rdata

Чтобы узнать названия всех секций надо простонабрать dumpbin example.exe (см. рисунок 3).

Рисунок 3. Названия секций

Чтобы узнать все используемые опции и ихописания набери dumpbin /?. Ладно, с этим вродебы разобрались, идем дальше. А дальше у наспо плану создание собственной секции иразмещение в ней данных.

Создание новых секций, да и распределениеданных по ним никак не оговорено в стандартах,поэтому каждый компилятор сам себе хозяин вэтом плане (для получения подробной

Листинг 2. Создание новой секции#include "stdafx. h"

#include "windows. h"

//Объявляем данные в новой секции

#pragma data_seg(" . Ghost_Rider" )

char UserName[ ] ="Ghost Rider";

char Password[ ] ="12345" ;

//возвращаемся к старой секции ( . rdata внашем случае, по умолчанию вообще-то . data )

#pragma data_seg( )

//Левые данные

char Login_for_Admin[ ] ="Super Admin";

char Password_Admin[ ] ="Admin Password=12345" ;

int _tmain(int argc, _TCHAR* argv[ ] )

{

char buffer_nik[ 50] ; //буфер под вводника

char buffer_pas[ 20] ; //буфер под вводпароля

//Ввод ника

printf("Vvedite nik: > " ) ;

fgets(&buffer_nik[ 0] , 50, stdin) ;

//ввод пароля

printf("Vvedite parol: > " ) ;

fgets(&buffer_pas[ 0] , 20, stdin) ;

//сравнение введенных данных сконстантами

if( (strcmp(&buffer_nik[ 0] , UserName) ) &(strcmp(&buffer_pas[ 0] , Password) ) )

printf("OK. " ) ;else

printf("Wrong Pas or Nik" ) ;

return 0;

}

Page 66: VR-Online (February 2011)

66

vr-on l ine | февраль 201 1

Кодинг

Выполняй компилирование и открывайполученный бинарник в IDA Pro (см. рисунок 4).

Новая секция готова

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

Рисунок 4. Новая секция (Ida Pro)

На рисунке 4 я выделил нашу новую секцию иданные в ней. Помнишь, я говорил, что вотношении секций данных компилятор сам себехозяин. Это прямое тому подтверждение – в кодемы назвали секцию Ghost_Rider, а вдизассемблированном виде получаем Ghost_R(компилятор обрезает длинные имена секций).Давай посмотрим через dumpbin все нашисекции (см. рисунок 5).

Рисунок 5. Секция . Ghost_R

Page 67: VR-Online (February 2011)

67

февраль 201 1 | vr-on l ine

Сетикет, нетикет -этикет в сети Интернет

Автор: Сергей Дианов aka Darth_Vaider | sdianoff@mail . ru

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

Так что же следует помнить, общаясь с помощьюИнтернета?

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

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

Пишите грамотно. Я ничего не говорю просетевые сокращения вроде IMHO, LOL, ASAP итому подобное, использование оных конструкцийникак не возбраняется. Но словечки типа"разришение", "кагбудьто", "птицы готовилиськотлету" (к отлёту), а также нецензурныевыражения - признак малокультурного человека.

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

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

Можно не отвечать, если:

1 . Сообщение содержит фразу: "Сообщениеотправлено автоматически. Отвечать на него не

нужно".

2. Сообщение содержит рекламу.

3. Сообщение содержит опасные объекты - о нихВы узнаете по реакции антивируса илифайрвола.

Обращайтесь за помощью на форум толькокогда это действительно необходимо -относитесь бережно к времени вашихсобеседников. Если всё же Вы не справились сзадачей самостоятельно и решили обратиться запомощью - старайтесь выглядеть достойно. Непритворяйтесь блондинкой, не называйте темуна манер "Курсач горит, помогите плз", "Помогитес лабой, завтра сдавать". Участники форума необязаны Вам помогать. Но и вы если получилиподобное сообщение, не спешите игнорироватьего: собеседники бывают разные и нужно бытьтолерантным к их недостаткам.

Не пересылайте файлы большого объёма безпредварительной договорённости. Помните, чтоу собеседника интернет не такой быстрый, как уВас, и пересылка тяжёлых архивов можетнегативно отразиться на скачивании другихфайлов - пропускная способность канала нерезиновая.

Кроме того, следует ознакомиться с правиламитого сервиса, которым пользуетесь (на этообычно все забивают). Если Вы этого не сделали- не удивляйтесь, почему ваш вопрос был удалёнмодератором.

НЕ ЗЛОУПОТРЕБЛЯЙТЕ КЛАВИШЕЙ CAPSLOCK!! ! Думаю, для Вас не секрет, чтосуществует общество противников даннойклавиши. И их мнение вполне обосновано:писать большими буквами означает КРИЧАТЬ. Авам приятно, когда на вас кричат?

Ну, и последние, всем известные правила. Ненужно флудить, флеймить, писать оффтоп,рассылать спам.

Без рамки

Page 68: VR-Online (February 2011)

68

vr-on l ine | февраль 201 1

VR-ONLINE в лицахVR-жители в нашем журнале и у всех на глазах

Без рамки

AgRuMa Anthony Soprano

Ghost Rider

Free mind

Page 69: VR-Online (February 2011)

69

февраль 201 1 | vr-on l ine

Без рамки

Inshi_Ker lerochka-z

Александр Иванишко aka ivanishko Алексей Стуликов aka A.S

Page 70: VR-Online (February 2011)

70

vr-on l ine | февраль 201 1

Без рамки

Астровский Евгений aka Rashking Евгений Плахов aka plaha

Кирилл Щербатов aka Dr.Kirill ius Сергей Дианов aka Darth_Vaider

Page 71: VR-Online (February 2011)

71

февраль 201 1 | vr-on l ine

Ткаченко Константин aka psycho-coder Андрей Петрикин aka Zanuda25

Строкин Владимир aka Va-Bank Лупсяков Дмитрий aka LDA

Page 72: VR-Online (February 2011)
Page 73: VR-Online (February 2011)

73

февраль 201 1 | vr-on l ine

Разговор о программированииЧасть 2

Автор: Голубниченко Юрий aka Ghost Rider

В первой части статьи “Разговор о программировании” я сравнивал программистовс писателями, говорили, что это такое же искусство и каждый “творческий” человек

вне зависимости от профессии – это творец.

Творец “в своей области”.

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

1 . Языки программирования – всего лишьинструменты;

2. Тест Джоэла;

3. Как стать программистом – размышления;

4. Литература;

5. Заключение.

Хочу сразу сказать, все здесь написанное этомои мысли и размышления. Они ни к чему тебяне привязывают и не обязывают. Вам решать чтоtrue, а что false, ведь никто кроме тебя не знает,что для тебя будет хорошо, а что плохо. Что жпредлагаю начать нашу беседу.

Языки программирования – всего лишьинструменты

Основная задача языка программирования -помочь программисту в совершенствовании

его искусства(Хоар)

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

Никто не спорит, что есть “мощные” языкипрограммирования, позволяющие решатьширокий круг задач, а естьузкоспециализированные заточенные подопределенные задачи. Но это опять-таки лишьинструменты. Здесь важна сама суть - сутьпрограммирования. А суть программированияочень проста и состоит из твоего способамышления и умения составлять алгоритмы длярешения поставленных задач. Поняв это, вопросо том, какой язык программирования лучшеотпадет сам собой. Однако появятся другиевопросы. Вопросы эффективности,быстродействия, но мне кажется это вопросывторостепенной важности.

Приведу небольшой пример, который как янадеюсь, поможет понять суть сказанного. Внебольшом городе (название которого для неимеет значения) жил некий Самоделкин, которыйувлекался тюнингом машин. Любая машина,пройдя через его руки, превращалась в“конфетку” (хотя использовались подручныесредства). Многие спрашивали, как ему этоудается, на что он отвечал: “Ничего особенногоздесь нет, просто я сначала представляю себе -как это будет выглядеть. Если необходимо делаюзарисовки, строю чертежи и т.д. Делаюпредварительный план своих работ и вперед”.“Но ведь из такого материала, который у тебя подрукой невозможно делать такие шедевры” – неунимались “вопрошатели”. “Нет ничегоневозможного, надо только захотеть поверить в

Без рамки

Рисунок 1. Все мы творцы

Page 74: VR-Online (February 2011)

74

vr-on l ine | февраль 201 1

Без рамки

это. А что касается материалов, ну что тутскажешь, что есть, то есть. Были бынормальные детали, работа бы делаласьбыстрее и эффективнее”.

Надеюсь, суть понятна – главное уметьсоставлять алгоритмы, а реализация делотехники. Если у тебя в голове уже“нарисован” идеальный алгоритм решениязадачи, что тебе мешает реализовать его наDelphi (как пример)? И работать он будетбыстрее, чем на Сях (ну это вряд ли – прим.редактора). Даa Алгоритм – это сила.Понимание эффективности алгоритма лежитв основе, в архитектуре ПК, процессоре.

Тест Джоэла

“Программирование” – как и “любовь”Одно слово, за которым скрывается

бесконечное множество занятий(Д. Вейнберг)

Наверняка многие, кто читал книгу ДжоэлаСпольски “О программировании” или его блог,знакомы с “тестом Джоэла“. Это тест для оценкиэффективности работы команды разработчиков.И состоит он из 1 2-ти вопросов, на которые надоответить “да” или “нет”. Поговорим о некоторыхвопросах теста, а точнее о вещах, которые этивопросы заставляют делать.

3. Набросай себе график работы. Немаловажнаячасть работы над проектом. Правильноспланированный график работы, да и вообщепланирование, распределение задач иобязанностей между группой программистоврешает, чуть ли не половину всей работы.Составь себе небольшую табличку (можно опятьже создать небольшую БД, но это уже, наверное,будет, чересчур), в которую будешь записыватьрешаемую задачу, напротив, записывай время,отводимое на ее решение, и время котороеосталось на решение этой задачи. Повозможности делай тщательное планирование.Оставляй время на отладку и “непредвиденные”ситуации.

4. Исправляй ошибки прежде, чем писать новыйкод. Представь себе что ты пишешь код, затемкомпилируешь его и бац – “выпадает” ошибка. Тыудачно ее закомментируешь и идешь дальше. Современем накапливается большая куча“мертвого кода”. Поди разберись в листинге изнескольких десятков страниц, что есть что. Такчто старайся исправлять ошибки сразу и всеподряд. Будь то error или даже warning.

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

Как стать программистом – размышления

Первую половину жизни мы работаем на имя,Потом оно работает на нас

(Народная мудрость)

Самый, что ни на есть “животрепещущий” вопросновичков – “Как стать программистом?”.Попробую привести несколько простых советов.Ну а вообще все зависит только от тебя. Никтоне мешает тебе стать первокласснымспециалистом (и так не только впрограммировании). От тебя требуется толькожелание и упорство (+ свободное время). Итак,ниже перечислю свои советы:

1 . Нишевание. Мы часто хватаемся за много делсразу и редко доводим все до конца. Так и впрограммировании – хочется изучить и то, и это,и третье. Вот и получается, что мы знаем все дани о чем. Никто не отрицает, свой кругозоррасширять, безусловно, надо. Но бытьпрофессионалом во всех областях ты никак, увы,не сможешь. Остановись на чем-то одном: WEB– программирование, базы данных,информационные системы. В этом и состоит сутьнишевания. Это и то, что тебя выделяет изтолпы программистов.

2. Если ты пишешь ПО под заказ, активновзаимодействуй с заказчиком. Составляйтехническое задание на программный продукт(чтоб потом не было придирок со сторонызаказчика).

3. Программируй каждый день (набивай руку).Постоянная практика и совершенствованиеверный путь к успеху. Кодируй и изучай новыетехнологии каждый день. Ставь себе задачи и

1 . Используй CVS и другие системы контроляверсий исходного кода. Если вы работаете вкоманде программистов, то система контроляверсий тебе просто необходима, иначе современем твоя работа превратится в хаос.Контроль версий исходного кода позволит тебепри обнаружении ошибки вернуться к рабочейверсии. Также все изменения, сделанные однимпрограммистом, становятся видны другимпрограммистам. И несомненный плюс –исходники проекта будут загружаться накомпьютер каждого программиста, то есть укаждого будет своя копия исходного кодапроекта.

2. Веди базу данных ошибок в программе. Да, ясогласен - это требует определенного времени иотвлекает от работы, но однажды такая вещьпоможет сэкономить кучу времени потраченноена поиски ошибок и выяснения, откуда онивзялись. Не обязательно создавать сложную базуданных по ошибкам, можно просто вести логошибок.

Page 75: VR-Online (February 2011)

75

февраль 201 1 | vr-on l ine

решай их. Можно даже сделать кому-топроект на халяву – чисто для резюме.

существование.

11 . Используй псевдокод на начальном этаперазработки. Удобство такого кода в том, что егопотом очень легко перевести на любой языкпрограммирования (например, ЕСЛИ a>0 ТО априсвоить a+a ИНАЧЕ, и тд.).

Литература

Люди перестают мыслить,Когда перестают читать

(Д. Дидро)

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

1 . Джоэл Спольски “О программировании” –замечательная книжка, основанная на записяхблога Джоэла. Я здесь не буду расписывать еедостоинства, и давать какие-либо оценки, ведьвсе уже это сделал Игорь Антонов akaSpider_NET, вот его рецензия на книгуhttp: //www.vr-onl ine.ru/content/dzhojel-o-programmirovanii-1 889. Если ктозаинтересовался, можете посетить блог Джоэла(www.joelonsoftware.com), также есть переводнекоторых его записей с блога(http: //russian. joelonsoftware.com иlocal. joelonsoftware.com/wiki/Russian)

2. Джоэл Спольски “И снова опрограммировании”. И снова я вас отправляючитать рецензию Игоря Антонова - http: //www.vr-onl ine.ru/content/dzhojel-snova-o-programmirovanii-3007

3. Питер Гудлиф “Ремесло программиста” – книгао том, как правильно программировать, вреальной жизни. Автор очень занимательнорассказывает о стиле программирования,технологиях разработки, безопасности, выбореимен переменных, дает полезные советы ирекомендации всем разработчикам.

4. Роберт Гласс “Факты и заблужденияпрофессионального программирования” – авторповествует нам о 55-ти фактах и 1 0-тизаблуждениях, которые относятся к жизненномуциклу ПО, качеству, исследованиям иобразовании в сфере разработки ПО.

5. Стив Макконнелл “Профессиональнаяразработка программного обеспечения” – книгадля тех, кто хочет подняться на новый уровень всоздании ПО. Рассказывается о корпоративныхметодиках, призванных увеличить количествопрофессиональных проектов, о лицензировании(кстати, о лицензировании, есть статья от АнтонаКозлова aka Jimmy Jonnezz www.vr-onl ine.ru/content/l icenzirovanie-trudov-svoej-tvorcheskoj-raboty-3048 ), об индустрии ПО вцелом.

6. Стив Макконнелл “Совершенный код.Практическое руководство по разработкепрограммного обеспечения” – еще одназамечательная книга от Стива. Рассказывается осовременных тенденциях и технологиях,эффективных методиках создания ПО, обискусстве программирования.

Без рамки

Начинать учиться никогда ни рано

4. Оставь “копипаст”. Набирай кодсамостоятельно, без копировать-вставить.Экспериментируй с кодом (не бойся), чембольше ты будешь работать самостоятельно,тем больше ты получишь опыта. Как говоритьсяодин раз сделай, сто раз услышь.

5. Не пренебрегай отладкой. Любая программаперед вводом в эксплуатацию должна быть“отдебажена”. Отладка позволит тебе выявитьошибки в твоем проекте, проследить за ходомвыполнения программы. Так что тренируйся какможно больше. Отладка тоже своего рода наука.

6. Не пренебрегай тестированием. Проводивсестороннее тестирование своего приложения,привлекай сторонних людей к тестированию.

7. Проектирование – основа проекта. Передкодированием займись проектированием.Набросай примерную схему на бумаге. Распиши,что к чему (используй блок-схемы длянаглядности). Определи основные задачипроекта. Разбей эти задачи на более мелкие(более простые) – подзадачи. Определи, чтодолжна делать твоя программа и как этого можнодостичь.

8. Программируй стильно. Не забывай про стильпрограммирования (кодирования). Существуетдовольно много стилей программирования икаждый из них по-своему уникален. У каждогосвои достоинства и недостатки, однако, ни кто неограничивает тебя лишь ими. Вырасти свойстиль программирования, и следуй ему напротяжении всего проекта (это позволит тебеизбежать путаницы при разборе кода и упроститчтение и отладку).

9. Не изобретай велосипед. Просмотри другиеподобные проекты, возможно в них ужереализована та или иная функция, котораянужна тебе. Используй шаблоны, библиотекикода (например, STL для программистов на C++).

1 0. Не используй устаревшие конструкции языка.Рано или поздно они прекратят свое

Page 76: VR-Online (February 2011)

76

vr-on l ine | февраль 201 1

Без рамки

В заключение приведу одну ссылку www.vr-onl ine.ru – если ты еще не с нами, то тымногое потерял. Заходи и убедись в этом.

Заключение

Вот и подошла к своему завершению нашабеседа.

Сказано было ни мало, но и многое осталось зарамками. Говорить о программировании можнобесконечно - обсуждать различные проблемы,связанные с разработкой ПО, анализомалгоритмов, эффективности и т.д. Я жепопытался затронуть самое важное. До встречи!

Page 77: VR-Online (February 2011)

77

февраль 201 1 | vr-on l ine

Меня тошнит!Выплескиваем негатив

Меня тошнит!

Потерял интерес к компьютерам, плюс к этому возникшие осложнения созрением. Стараюсь чаще отдаляться от компьютеров и компьютернойтехники. Надоел весь этот технический прогресс, хочется вырваться воткрытое пространство, хочется единения с природой. Дико разгорелосьжелание уйти от всего, что меня окружает — заботы, обязанности, правила,ограничения. Хочется выйти из этого замороженного состояния, т.к. J immyне очень жалует эту душевную серость и внутренний «не уют». Со всемэтим трудовым процессом сник мной внутренний вихрь, что давал мне сил«сворачивать горы» и меня тошнит оттого, что не могу найти в себе «рычаг»и запустить механизм подзарядки. Может. . .

Jimmy Jonezz:

В канун нового года поступило предложение от моего знакомого. Нашемусамому крупному провайдеру требуется парочка новых работников наполставки. Как раз к парам будем освобождаться. Плюс получение опыта,новых знакомств и дополнительного источника, каких ни каких, но все жеденег. Благодаря связям, мы двое первые в списке. Все документы собраны,проверены и даже отправлены в область. Недлинный разговор инаставления нового начальства о предстоящей работе, а потом и ееожидание в ближайшую неделю. Однако спустя даже месяц никакихновостей. Знакомый рассказал, что у них не выполнен план по увольнению.Афигеть! Оказывается и такие планы есть. Так что, до новых сотрудников уних интерес пропал. В принципе ничего страшного. Мне всего-то хотелосьполучить опыт работы в крупной организации. Но просто ощущение такоегнусное, что нас тупо кинули.

Kastor:

Page 78: VR-Online (February 2011)

78

vr-on l ine | февраль 201 1

Сравнительный обзор наушниковв категории до 100$

Автор: Овчинников Михаил aka Night_StormEmail : [email protected]

WWW: http: //nstorm.blogspot.com

Я уже писал о своем приобретении наушников(http: //nstorm.blogspot.com/201 0/1 2/sennheiser-hd21 5.html). Также я упомянул, чтопрослушал многие наушники (спасибо продавцам их магазина Элекс, которыетерпеливо по 1 0 раз упаковывали и распаковывали все требуемые модели), из тех,которые можно найти в городе, и я решил, что будет очень несправедливо с моейстороны умолчать, и не представить вам свою точку зрения на все это безобразие.

Как я уже говорил, прослушивание проводилосьна ресивере Yamaha, а для оценки звучания напортативе использовался мой плеер SamsungYP-R1 . Прошу помнить, что здесь представленомое субъективное мнение, а конечное решениевсегда останется за вашими ушами.

Sennheiser HD 485

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

Sennheiser HD 465

Обзоры от VR

Хорошее глубокое, достаточносбалансированное звучание, удобно сидят наголове (хотя, признаться, мне немного давило науши). Мне не понравился немного выпирающийбасс где-то в области 1 00-200 Гц, то естьполучалось так, что бас-гитара звучала хорошо ировно, а вот "бочка" смотрелась рядом с нейвяло и практически не читалась. Высокиечастоты хорошо читаемы, но "скромны", нехватает искорки, которая заставляет бежатьмурашки по телу от чувственных соло и нотоквокала. На высокой громкости никакихособенных искажений я не услышал, трек звучалочень естественно. Не понравился цвет "детскойнеожиданности" и непрактичные поролоновыеамбушюры, которые определенно очень быстросомнутся, и наушники перестанут радоватьсочностью и плотностью звучания. Проводотсоединяется, и при желании его можнозаменить на более качественный, хотя я думаю,что толку от этого мало будет, а вот заменить егона более короткий явно было бы не лишним,потому что 3 метра провода – это даже для дома

Данные наушники в плане звука практически неуступают предыдущей, старшей модели.Субъективно мне показалось, что в силунесколько иного строения амбушюр они сидят наголове несколько удобнее, хотя и не так плотно,но уши явно чувствовали себя свободнее и нетак сдавленно. Но раз уж я заговорил о них, тохочется опять же отметить невысокое качествопоролона, которые вызывает вопросы о егонадежности, а еще ушам довольно жарко, хотядля тех, кто предпочитает ходить в такихнаушниках по улице это скорее плюс.Относительно звука уже упомянутый минус свыпиранием баса здесь проявлен еще больше –когда басист начинает играть “слэпом”, взвуковой картине перестают различатьсяостальные инструменты. Хотя, возможно простоя не любитель сильных басов. А так в целом звукочень достойный и свою цену наушникиоправдывают.

Sennheiser HD 205

Page 79: VR-Online (February 2011)

79

февраль 201 1 | vr-on l ine

Относительно звука, здесь применимопрактически все, что я писал про свои наушники.Скажем так, это - максимально удешевленнаямодификация HD21 5. Таким образом, здесьпоявилась неудобная конструкция, давящая наголову, (хотя с другой стороны, благодаря этому,бас кажется несколько более упругим) и тонкийшнур. Советовать их не могу (хотя мне кажется,что людям с небольшой головой они будутвполне удобны), если нет денег на что-то еще,лучше подождать, покопить.

Sennheiser HD 201

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

Philips SHP8500

Обзоры от VR

Самые дешевые наушники из сенхайзеров. Я неожидал здесь ничего услышатьсверхъестественного, но, признаться, наушники"отработали" весьма прилично на средних ивысоких частотах, в басах же наблюдался явныйнедостаток, хотя они присутствовали и быливполне читаемы. На высоком уровне громкостиконструкция начинала неприятно резонировать, ипоявлялись искажения на верхних частотах. Нопри всем при этом стоит отметить хорошуюзвукоизоляцию для наушников такой ценовойкатегории: конечно, для шумного метро ее явноне хватит, но в условиях маленькой квартиры выточно никого не побеспокоите, да и вас тоже. Вцелом, будучи весьма ограниченными в

В немецкую братию затесались и вот такиенаушники. Признаться, на фоне своих типичных"бытовых" собратьев эти филипсы смотрятсяочень достойно. Помимо хорошего дизайна,крепкой на вид конструкции и удобной посадкина голове они обладают весьма достойнымзвуком. Конечно, в нем чересчур завышенынизкие и высокие частоты, что весьма обедняетсередину и некоторые жанры музыки слушатьвесьма непривычно, а некоторые простоневозможно – от ухающих басов закладываетуши, а мозг "сверлит" назойливый хэт. Хотя опятьже, это - мое мнение, как человека любящего вовсем золотую середину, а между тем многиеприходят в восторг от такого звучания. Зато могуточно сказать, что для любителей фильмов и игртут просто раздолье: выстрелы, взрывы, звукибитого стекла – все будет очень явно иреалистично. Сильных грехов на повышенныхуровнях громкости не наблюдалось, если несчитать, что немного возрастал уровень высокихчастот. В целом соотношение цена/качествоздесь также весьма хорошее и большинствонеискушенных, скажем так, рядовыхпользователей найдут их весьмапривлекательными и будут правы.

Конечно, невозможно рассмотреть все. Я не сталговорить про кучи китайских Sony, Technics иPanasonic в категории "до 1 500р" которые ятакже послушал при выборе – они все звучатприблизительно одинаково: весьма бедный низ смутноватым звучанием баса, нечеткие"пластмассовые" верха, резонансы конструкции иискажения на высоких уровнях громкости. Вобщем, типичные "бытовые" наушники, которыхнаверное, у каждого была куча. Конечно,советовать такие вещи очень тяжело, потому чтоне только о вкусах не спорят, но и чисто сфизической точки зрения у людей различаетсяформа ушной раковины, с возрастом сужаетсявоспринимаемый диапазон частот, и выборстановится строго субъективным. Второй момент– это, конечно, качество источника звучания.Часто люди втыкают такие наушники в дешевый

Page 80: VR-Online (February 2011)

80

vr-on l ine | февраль 201 1

Обзоры от VR

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

Обзор наушников Sennheiser HD21 5

Сегодня, уважаемый читатель, я расскажу тебе,пожалуй, о самом мучительном выборе в своейжизни – выборе наушников. Будучи весьмаограниченным в бюджете (<1 00$) я отчаялсянайти что-либо качественное. Облазив всемагазины в городе и переслушав бесчисленноеколичество разнообразных ушей, выбор былостановлен на наушниках фирмы Sennheiser, ну,думаю, это вполне логично. Были при выборееще прослушаны весьма неплохие Phil ipsSHP8500 и 8900, но были забракованы из-засомнительной честности их звучания (избытокбасов и назойливые верхи). Нет, если ты -любитель фильмов и игр, то упомянутые моделиPhil ips отлично подойдут тебе – острыеощущения обеспечены, но я помимо простогопрослушивания также записываю на досугемузыку, и мне предельно важна ровная АЧХ идетальный звук.

При покупке наушники тестировались наресивере Yamaha (модель не помню, ксожалению) в качестве жанра был довольнокачественный джаз, и в качестве "независимогоэксперта" выступал мой плеер Samsung YP-R1 cзаряженным в него сборником Карлоса Сантаныво flac и последнего альбома Pendulum в mp3 ибитрейтом 320 кбит\с. Затем дома я провел дляних тест "с точки зрения обычного пользователя",подключив их к моему нетбуку Acer 721 , тутиспользовался следующий набор: Roger Waters -Radio K.A.O.S во flac, Карандаш – Живи БыстроУмри Молодым в mp3 320 кбит\с, и несколькопесен Стигматы и других металкор-команд.Никакие эквалайзеры и "улучшайзеры" неприменялись

Я не буду перечислять, сколько наушников япереслушал. Сразу перейду к делу. HD 21 5позиционируются фирмой, как наушники для ди-джеев, о чем свидетельствует возможностьповорота чашек и витой "телефонный" шнур. Вкомплекте также идет переходник на "большойджек" (который навинчивается, а не втыкается,как у более дешевых моделей) и удобныйвместительный чехол из качественногокожзаменителя. Конечно, довольно сомнительно,что ди-джеи будут использовать такие наушникиначального уровня, но для домашнего музыкантаони могут стать достойным приобретением.Кратко основные характеристики:

В целом звук очень детализированный, всечастоты воспроизводятся честно без особыхприкрас. С увеличением громкости искаженийзвука практически не появляется, только насовсем большом уровне, когда уже слушатьбыло решительно невозможно, сталипрослушиваться хрипы в басах. Иногда, когдаслушаешь какой-нибудь джаз, очень хочетсядобавить баса, так как бочка слушается несовсем уверенно, также когда барабанщик играет"щеточками" им не хватает "искорки", то есть онинормально читаются в миксе, но хочется ихслышать более хлестко. Но эти претензииотпадают, если слушать современный металкорили электронную музыку, то никакого недостаткани в верхних, ни в нижних частотах неощущается – при этом остается отличнаячитаемость и детализация, как на низких, так ина высоких уровнях громкости: ни однатарелочка или эффект не исчезают из звуковойкартины. Кто-то назовет такой звук "плоским" или"тусклым", но это - именно то, что я искал.Потому что если звукорежиссер в студиипотрудился на славу, то это будет звучать, а еслинет, то можно взять самые дорогие наушники, нотрек этим не спасешь. Да, согласен, чтонаушники нейтральны и "не имеют характера", ноглупо было бы ждать чего-то такого в этомценовом диапазоне. В целом я остался доволенсвоей покупкой. Наушники честно отрабатываютсвои деньги, удобно сидят на голове (правда уменя голова не особенно большая, возможно улюдей с большой головой могут возникнутьнекоторые неудобства), я надеюсь, что они будутслужить мне верой и правдой и долгими зимнимивечерами и короткими летними ночами. Всеостальные замечания и впечатления, по ходуэксплуатации будут непременно появляться вмоем твиттере, так что вы сможете держать рукуна пульсе и после прочтения данного поста.

Page 81: VR-Online (February 2011)

81

февраль 201 1 | vr-on l ine

Обзор книги: "Доступный UNIX"Linux, FreeBSD, DragonFlyBSD, NetBSD, OpenBSD

Автор: Роман Костенко | Lord_of_fear

Вот и созрел я написать пару слов про последнюю книгу о Unix, из тех, что я когда-либо читал. Закончил читать я ее, честно говоря, давно, но пишу этот обзор толькосейчас. Сразу скажу, что эта книга для начинающих. Автором не поднимается ниодного серьезного вопроса в плане администрирования Unix систем. Всяинформация в основном для новичка.

Книга посвящена описанию свободных UNIX-подобных операционных систем,представителями которых являются Linux,FreeBSD и другие члены BSD-семейства, а такжеих использованию в качестве универсальнойплатформы общего (в том числе и домашнего)назначения. Материал книги не привязан к какой-либо конкретной ОС или дистрибутиву Linux, асодержит описание общих принципов установки,настройки и эксплуатации любого изпредставителей этого семейства. С позицииконечного пользователя рассмотрены вопросыидеологии и истории UNIX-подобных систем,изложены основные принципы, на которых онибазируются.

Качество изложение материала простосуперское. Я бы сказал: читать интересно, а вкакой-то мере даже захватывающе. Автор – нашсоотечественник. Я очень рад, что наши авторыумеют так писать. Первая половина книгичитается просто взахлёб. Вторая половина былапо большей части мною просто пролистана, т.к. яэто всё уже знаю.

Этой книге уже можно поставить пять с плюсомтолько за то, как преподнесен материал поидеологии и истории Posix-совместимых систем(да, все Unix системы гораздо правильнееназывать именно так). В плане жеадминистрирования даются лишь начальныезнания. Как раз то, что нужно новичку.

Так же хочется отметить факт того, что автор вкниге рассказывает, чем же именно отличаютсяразные ОС. Например: FreeBSD и OpenBSD.

Причем как в плане истории, так и в планевнутреннего устройства. Любому пользователюUnix систем будет полезно почитать раздел“Физика файловых систем”. Очень полезнаяинформация.

Рекомендую всем для чтения. Не пожалеетепотраченного времени.

Обзоры от VR

От издателя:

Книга посвящена описанию свободных UNIX-подобных операционных систем, представителямикоторых являются Linux, FreeBSD и другие члены BSD-семейства, а также их использованию вкачестве универсальной платформы общего (в том числе и домашнего) назначения. Материалкниги не привязан к какой-либо конкретной ОС или дистрибутиву Linux, а содержит описаниеобщих принципов установки, настройки и эксплуатации любого из представителей этогосемейства. С позиции конечного пользователя рассмотрены вопросы идеологии и истории UNIX-подобных систем, изложены основные принципы, на которых они базируются, такие как понятияфайлов, процессов, учетных записей пользователей, режимов и интерфейсов, даны приемырешения повседневных пользовательских задач.

Page 82: VR-Online (February 2011)

82

vr-on l ine | февраль 201 1

Я прусь!Делимся позитивом

Я прусь!

В этом месяце (февраль) у меня по-особому странное состояние - я какробот утром встаю, иду работать, с работы на учебу, домой и спасть.Никакого отдыха, никаких развлечений, никакой отвлеченности от работы,так сказать весь в рабочем процессе. Нет сил на вечерние посиделки в кафес друзьями, на походы в бильярдную, забыты походы на ледовый каток,давно не выходил на вечернюю прогулку. Потерял контакт с любимой мнеособой. Одним словом «движуха» на нуле — не хочу ничего. И так напротяжении месяца. Зимние праздники прошли как одно мгновение, я дажепонять не успел, что они были. Единственное, вспоминаю, как прошелНовогодний вечер — куча подарков, положительных и яркий эмоций,радостных счастливых воскликов. Это было клево. От этих воспоминанийтеплится огонек в моей душе, дожидаясь весенних деньков, чтобывзорваться в диком пламени.

Jimmy Jonezz:

Февраль стал для меня по-настоящему горячим месяцем. Былозапланировано много дел, которые к счастью удалось завершить. А этолучший повод посмотреть на себя и сказать: «А ведь ты молодец, тысправился!». Вот от этого я прусь в этом месяце. Еще я счастлив, что явновь стал заниматься web-программированием. Выпуск новой версииCodeIgniter меня нехило вдохновил и теперь я каждый день ставлюэксперименты с этим продуктом и с удовольствием пишу об этом в свойблог. Ну, разве не замечательно?

Spider_NET:

Хочется закрыть глаза. Это нормально. На часах 01 :05 ночи. Отлично, ещеминуток десять придавлю подушку, балансируя на грани сна, и сяду за комп.К утру, эта небольшая программка должна быть дописана. В темной комнатетолько два источника света: это включенный монитор и лампа, стоящаярядом. Я подвигаю к себе клавиатуру и первым делом запускаю онлайнрадио. Приятный транс, через наушники, вливается в мое сознание. Оченьинтересно осознавать, что город спит. Спят его жители, спят коммунальныеслужбы и органы правопорядка. Спят, в отличие от меня и моегокомпьютера, который соединен с всемирной паутиной знаний иинформации. Музыка льется параллельно моим мыслям, абсолютно немешая. Я принимаюсь за работуa

Готовое решение отправляется заказчику. Его пока нет в сети, но я уверен,он появится в ближайший час или два. В данной ситуации у меня нетобязательств, но я подожду. Вероятно это оправдание, что бы провестилишнее время за компьютером. На часах почти семь утра, а я и не заметил,как в комнате стало светло. Пожалуй, лампу можно уже выключить. Мнеспать вовсе не хочется. В отличие от моего организма, который привык кполусонному состоянию. Следующие полтора часа пролетают за чтениемрассказов на компьютерные темы. Это помогает мне отвлечься,расслабиться. Заказчик объявился в сети. Рассчитался и забрал свой архив.Что ж, пожалуй, на сегодня все. Хм, как странно звучит. Ведь сегодня тольконачинается. Через четыре часа пора на пары. А к черту их! Сегодняшняяночь была куда интереснее, чем предстоящие три лекции. Ложусь на диван,под одеяло, и на пару с компьютером ухожу в спящий режимa

Kastor:

Page 83: VR-Online (February 2011)

83

февраль 201 1 | vr-on l ine

Я прусь!

Наконец то, к нам приходит весна. Для меня это – самая любимая пора.Самое то будет, когда уже можно будет снять шапку и выбраться на природуна шашлычки. Всё таки, смена времен года очень положительно влияет надушевное состояние человека. После жаркого лета хочется прохладнойосени, после холодной зимы жаждешь тепла и весеннего солнца. Такимобразом, смена времен года вносит разнообразие в нашу жизнь. Аоднообразие приводит сначала к какой-то меланхолии, а потом можетначаться и депрессия. Вот и я устал от этой зимы. Она получиласьотвратительная. Снега было много, дороги чистили плохо. 5 раз за этозимнее время приходилось ходить полностью пешком от работы до дома.Но теперь в свои права вступает весна. =)

Lord_of_fear:

Page 84: VR-Online (February 2011)

84

vr-on l ine | февраль 201 1

FliMP: LightTPD + MySQL + PHPУстановка и настройка cвоими руками

Автор: Gh[]st HackLabbs [Team]

В этой небольшой статье я бы хотел поделиться опытом установкисвязки LightTPD + MySQL + PHP (через FastCGI интерфейс) под

управлением FreeBSD.

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

Начать свое повествование мне хотелось бы смини обзора LightTPD. Это довольно лёгкий игибкий веб-сервер. Его разработка началась вцелях написания отказоустойчивого http-сервера.В реале Lighty способен выдержать нагрузкусвыше 1 000000 подключений, т. к. в отличии отApache он использует асинхронный I/O, а непотоки.

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

Начнём установку с MySQL. Версия 5.1 ,находящаяся в портах, мне не понравилась,запустить её удалось лишь в safe_mode.Разбираться в причине неудачи у меня не быложелания. Да и зачем, если есть MySQL 5.0,которого нам хватит за глаза? В общем, ставимпятый мускул. Перед выполнением этогодействия не забудь обновить порты:# portsnap fetch update

Далее переходим непосредственно к установкеMySQL Server. Выполняем несколько команд:# cd /usr/ports/databases/mysql50-server/# make install clean

Отлично, мускул установлен. Теперь засетапимдля работы с ним. Делается это так:# cd /usr/ports/databases/mysql50-scripts# make install clean

Все, скрипты и сам сервер БД установлен,теперь нужно его правильно сконфигурировать.Для начала проинициализируем директориимускула:# mysql_install_db

Далее установим пароль root`а:# mysqladmin -u root -h localhost password' new-password'

В команде используется ряд ключей, их описаниея привел ниже:

- u - указывает пользователя, который будетвходить в систему (в данном случае – root);

- h указывает узел сети (обычно это localhost,если вы настраиваете не удаленный сервер);

После выполнения команды для доступа ксерверу БД мне придется вводить в качествелогина root и “new-password” в качестве пароля.Не забудь, что в боевых условиях нужнопридумать пароль посерьезней.

Следующим шагом создадим конфигурационныйфайл. Опять нужно выполнить одну команду:# ee /usr/local/etc/my. cnf

Приблизительное содержание файла смотриниже.[client]#password = your_passwordport = 3306socket = /tmp/mysql. sock# Here follows entries for some specificprograms# The MySQL server[mysqld]port = 3306bind_address = 127. 0. 0. 1socket = /tmp/mysql. sockskip-lockingkey_buffer = 16Kmax_allowed_packet = 1Mtable_cache = 4sort_buffer_size = 64Kread_buffer_size = 256Kread_rnd_buffer_size = 256Knet_buffer_length = 2Kthread_stack = 128Kdefault-character-set = utf8log = /var/log/mysql. loglanguage = /usr/local/share/mysql/russian/

MySQL должен автоматически запускаться пристарте системе. Раз так, то нужно поместить егов автозагрузку:# ee /etc/rc. confmysql_enable=”YES”

Теперь попробуем запустить MySQL. Для этоговыполни команду:# /usr/local/etc/rc. d/mysql-server start

Админинг

Page 85: VR-Online (February 2011)

85

февраль 201 1 | vr-on l ine

Админинг

На этом можно считать установку сервера базданных оконченной. Время браться за PHP. Намомент написания статьи последней версиейбыла 5.3.5. Ее и будем ставить. Вбиваем вконсоле несколько команд:# cd /usr/ports/lang/php5# make config

В появившемся окне (если это можно назватьокном) обязательно выбираем CLI ,CGI .

официальном сайте (php.net). Я лишь посоветуютебе сазу задать временную зону:[Date]date. timezone = Europe/Minsk

Устанавливаем LightTPD

PHP и MySQL полностью в боевой готовности.Пришло время заняться главным виновникомторжества – web-сервером LightTPD. Итак, дляустановки выполняем:# cd /usr/ports/www/lighttpd# make config

В качестве опций обязательно выбираемSPAWNFCGI.

Рисунок 1. Определяем опции для PHP

# make install clean

С этим справились. Теперь установимрасширения для PHP, без которых, наверное, ниодин продвинутый движок работать не будет.# cd /usr/ports/lang/php5-extensions# make config

В обязательном порядке выбираем нижеперечисленные расширения. Остальные ставьна свое усмотрение: Ctype, curl , dom, gd, imap,mbstring, mcrypt, mysql, mysqli , pcre, posix,session, simplexml, xml, xmlreader, xmlwriter, zl ib,fi leinfo.

Рисунок 2. Выбираем расширения для PHP

Следующей командой для выполнения у насбудет:# make install clean

Все, PHP установлен, но без небольшого твикаработать он у нас не будет. Опять вбиваемнесколько команд:# cp /usr/local/etc/php. ini-production/usr/local/etc/php. ini# ee /usr/local/etc/php. ini

Углубляться в тонкости php. ini я не стану.Описание всех директив ты найдешь на

Рисунок 3. Опции для lighttpd

Нажимаем «Ок» и сразу же вбиваем еще однукоманду:# make install clean

На этом установка завершена. Пора переходитьк настройке. Подтягивай клавиатуру поближе искомандуй чертям:# cp/usr/local/etc/lighttpd/lighttpd. conf. sample/usr/local/etc/lighttpd/lighttpd. conf

Редактирование конфигурационного файлаоставляю на твое усмотрение. Чтобы тебе былопроще сориентироваться, в папке с журналом тынайдешь мой конфигурационный файл. Смеюзаметить, это реальный конфиг сервера. На нему меня крутится портал и торрент-трэкер.

После внесения изменений не забудь сохранитьконфигурационный файл. После этого можносразу переходить к тестированию - запускуlighttpd. Для старта убийцы Apache воспользуйсякомандой:# /usr/local/etc/rc. d/lighttpd start

Если не запустился, то первым делом проверь,созданы ли лог-файлы и выставь права доступана них. Теперь попробуем полноценно затеститьработоспособность нашей связки. Для этогосоздадим файл, index.php и напишем в неговсего лишь одну строчку кода:"<?php phpinfo() ; ?>"

Помещаем это файл в server.document-root (уменя это "/var/www" ). Открываем браузер ипытаемся обратиться к ip_сервера/index.php.Если все компоненты были установлены инастроены верно, то ты увидишь картинкупохожую на рисунок 4.

Page 86: VR-Online (February 2011)

86

vr-on l ine | февраль 201 1

<?php/** В phpMyAdmin для авторизации может

использоваться проверка cookies или httpсессии. Я предпочитаю больше второе, но еслиты собираешься использовать кукисы, то тебепридется заполнить переменную blowfish_secretслучайным набором символов.*/$cfg[' blowfish_secret' ] =

' blablablablablablablablablablabla' ;/** Конфигурация серверов.* Одну копию phpMyAdmin можно использовать

для подключения к нескольким серверам MySQL.Для этого нужно определить настройки дляподключения к каждому серверу. Насколько японял, при использовании нескольких серверовследует использовать авторизацию только черезcookie.*/$i = 0;

/* *** Опишем первый сервер *** */$i++;

/** Метод авторизации.* Чаще всего применяют cookies или http . . .*/$cfg[' Servers' ] [$i] [ ' auth_type' ] = ' cookie' ;

/** Параметры для подключения к серверу.* - адрес хоста*/$cfg[' Servers' ] [$i] [ ' host' ] = ' localhost' ;

/* - порт (если не указан, то используетсядефолтный 3306) */$cfg[' Servers' ] [$i] [ ' port' ] = ' ' ;

/* Тип соединения с базой данных.* Может быть socket, а может быть tcp.*/$cfg[' Servers' ] [$i] [ ' connect_type' ] = ' tcp' ;

/** Если в предыдущем случае указан socket, то

по умолчанию, применяется путь к сокету/tmp/mysql. sock. Если у тебя сокет базыданных в другом месте, его следует указать вследующей переменной.*/$cfg[' Servers' ] [$i] [ ' socket' ] =

' /tmp/mysql. sock' ;/** Использовать ли для подключения к БД

шифрование SSL?* У меня стоит «не использовать».*/$cfg[' Servers' ] [$i] [ ' ssl' ] = false;

/** Применять сжатие? Может быть true (да) или

false (нет)*/$cfg[' Servers' ] [$i] [ ' compress' ] = false;

/** Конфигурации для второго, третьего,

десятого серверов можно подключить поаналогии с первым. Настройки следующегосервера должны начинаться с $i++. Прииспользовании настроек для несколькихсерверов на странице входа в phpMyAdminпоявится выпадающий список для выборасервера.

Админинг

Рисунок 4. Тестируем Lighttpd в связке с PHP

Рисунок 5. Убеждаемся, что работаем именно сLighttpd

Будем считать, что у тебя все заработало.Теперь нужно обеспечить наш web-серверавтоматическим запуском. Для этого выполняйкоманду:# echo ' lighttpd_enable=”YES”' >>/etc/rc. conf

Устанавливаем phpMyAdmin

Как настроить lighttpd в связке с php/mysql я теберассказал. На этом можно считать, что моямиссия на сегодня окончена. Но я тут подумал,что тебе в любом случае на серверепонадобится phpMyAdmin. Этот продукт ужедавно стал стандартом в качестве программыдля работы базами данных хостингах и будет нехорошо обделить его присутствием свой сервер.К тому же, установка и конфигурированиеphpMyAdmin много времени не займет. Ладно,хватит лишней болтовни. Займемся делом.Быстренько вбивай в консоли:# cd /usr/ports/databases/phpmyadmin# make config

После этого появится экран конфигурации, накотором нужно выбрать опции. Обрати внимание,что нужно убрать опцию PDF,GD (они нам покане нужны). Отлично, вбиваем:# make install clean

Все, установка завершена. Как я и говорил, всене просто, а очень просто. В строке alias.url =(“/pma” => “/usr/local/www.phpMyAdmin”), сказано,что обратившись по адресу: ip_сервер/pm мыпопадем в phpMyAdmin. Сам конфигурационныйфайл phpMyAdmin расположен по пути: файл/usr/local/www/phpMyAdmin/config. inc.php. Ниже япривел код конфигурационного файла, которыйснабжен изрядным количеством комментариев.

Page 87: VR-Online (February 2011)

87

февраль 201 1 | vr-on l ine

Админинг

*/

/** Каталоги для загрузки и сохранения файлов.

Можно ничего не указывать, а можно прописатьсюда свой путь. Каталоги должны быть доступнына запись пользователю www (от которогозапущен веб-сервер) .*/$cfg[' UploadDir' ] = ' ' ;$cfg[' SaveDir' ] = ' ' ;

?>

Install complete

Установка FliMP’а завершена. Все системыработают нормально, и ты увидел как легко ипросто можно поднять компактный ивысокопроизводительный web-сервер.Надеюсь, ты найдешь ему должноеприменение. На этом мой рассказ завершен.Удачи!

Page 88: VR-Online (February 2011)

88

vr-on l ine | февраль 201 1

Inskape:Диско-шар своими руками

Автор: Елена Гохадзе aka helurWWW: http: //vector.wolfempire.net/

Замечательный векторный редактор Inkscape имеет множество функций,использование которых способно значительно облегчить труд пользователя,создающего свои векторные шедевры. Сегодня мы познакомимся с двумя такимифункциями, "живущими" в пункте меню "Расширения". Результатом наших старанийдолжен оказаться симпатичный зеркальный диско-шар.

Готовы? Поехали!

1 . Первым делом нарисуем каркас будущегошара. Собственно, рисовать ничего не придется -Inkscape все сделает за нас. Выполняем"Расширения"=>"Отрисовка"=>"Каркасная сфера"с настройками, указанными на рисунке, иполучаем почти готовый шарик.

3. Теперь объединяем это множество контуров водин - Ctrl+K. Где-нибудь рядом рисуем круг,задаем ему размеры 200 на 200 пикселей,обводку в 1 пиксель и заливаем желаемымцветом. Располагаем этот круг точно подшариком, используя панель "Выровнять ирасставить" (Ctrl+Shift+А).

Креатиff

2. Inkscape нарисовал нам шар, состоящий изкругов и полукругов. Обратите внимание -обводка всех объектов должна быть шириной в 1пиксель. Для дальнейшей работы нам нужно двараза разгруппировать шарик (Ctrl+Shift+G) и одинраз оконтурить (Ctrl+Shift+C).

4. Выделяем оба объекта и выполняем"Контур"=>"Разделить". Шарик "разбился" намного граней.

Page 89: VR-Online (February 2011)

89

февраль 201 1 | vr-on l ine

Креатиff

5. Пора красить наш шарик. Идем"Расширения"=>"Цвет"=>"Случайные значения".Можете поэкспериментировать и попробоватьразные настройки, я же оставила одну галочку -Яркость.

7. Можно также нарисовать один или несколькобликов, используя инструмент "Рисовать звездыи прямоугольники". Let's dance! ; )

6. Вот наш шарик и готов. Для удобствавыделяем все его части и группируем. Теперьможно добавить ему объема. Рисуем круг 200 на200, заливаем его радиальным градиентом отпрозрачного к темно-розовому и задаем кругупрозрачность 64. Размещаем круг поверхшарика.

Рассмотренную функцию отрисовки каркаснойсферы можно применять очень широко - начинаяот рисования елочных шаров, и заканчиваясозданием дизайнерских моделей земного шара(один такой шар, отрисованный в Inkscape, Выимеете счастье наблюдать на обложке этоговыпуска нашего журнала). Удачных Вам решенийи безграничной фантазии!

Page 90: VR-Online (February 2011)

90

vr-on l ine | февраль 201 1

VR-МНЕНИЕ

VR-МНЕНИЕVR рассуждает о интернет-планшетах

Если имеются в виду планшеты, которые без подключения к Инетупрактически не работают - такого счастья мне не нужно. А вот если внутриесть неплохая мобильная ОС и возможность подключения по Wi-Fi - куплюлегко и запросто. Сначала думал, что моя проблема написания постов вмаршрутке решится с покупкой нетбука - оказалось, что нет. Все-такинеудобно держать нетбук в скачущей по кочкам маршрутке. К тому жепланшетник может спокойно лежать в сумке с прочими вещами.

Как вариант, конечно, есть коммуникатор. Но весь его функционал мне ненужен - очень уж симпатичным телефоном я обзавелся в январе. К тому же,например, серфить по Инету с планшета гораздо удобнее, чем скоммуникатора, IMO. Что же касается сенсорной клавиатуры - к ней япривык еще на коммуникаторе.

При выборе планшета первым делом буду отталкиваться от ОС,установленной на нем. Возможно это будет Android, хотя хочется что-тоDebian'оподобное. Хотя бы Ubuntu.

А вообще, планшеты - это, конечно, не только дорогие цифровые фоторамки:) Но и ждать от них чего-то сверхъестественного - лично я не жду.Воспринимаю как звено между коммуникаторами и нетбуками. И лично мнеименно такого звена в жизни и не хватает.

ZeroXor:

У меня часто возникает потребность в компактной обустроенности своейкомнаты и рабочего места. Десктопный компьютер я поменял на ноутбук иэтому очень рад, т.к. избавился от кучи мешающих / свисающих /болтающихся проводов. Интернет-планшеты это более компактныйвариант, чем ноутбук и подобные ему девайсы (нетбуки, неттопы и т.д. ).Здесь правда есть свои ограничения: технические характеристики,подключение периферийных устройств, особенность работы с планшетоми т.д. Однозначно, я бы его приобрел, но необходимость в нем, на данныймомент, у меня отсутствует. Техническое оснащение, что у меня сейчасимеется, позволяет в полном объеме решать повседневные задачи безкаких-либо неудобств. Интернет — планшет, на данный момент, для менявидится как игрушка или как некий гаджет, который не несет в себеосновной необходимости.

Jimmy Jonezz:

Интернет - планшеты довольно таки интересные, удобные и актуальные внаше время "игрушки". Однако лично для меня это всего лишь среднеезвено между смартфоном и нетбуком, балансирующее на грани "удобства"и "функциональности". Интернет - планшет вещь, несомненно, удобнаядля чтения электронных книг, серфинга интернета, работы с электроннойпочтой, больше плюсов для себя я, к сожалению не усмотрел. Что касаетсявопроса приобретения такой игрушки, то тут я пожалуй пока воздержусь. Идело вовсе не в цене (я бы не сказал, что цены на них заоблачные, хотяесть "особые" экземпляры), просто я не вижу смысла в их приобретении. Кпримеру, для всего вышеперечисленного (серфинга инета, почта и тд.),мне вполне хватает моего ноута, а дорога на работу занимает не так уж имного времени, да к тому же автобус на котором я еду на работу набитхомосапиенс до отказа, попробуй там сам "развернуться", не то, что спланшетом. Но это вовсе не значит, что я вас отговариваю от его покупки,это всего лишь мое IMHO.

Ghost Rider:

Page 91: VR-Online (February 2011)

91

февраль 201 1 | vr-on l ine

VR-МНЕНИЕ

Я жду не дождусь, когда на рынке появятся планшеты с оптимальнымсоотношением цена/качество. Увы, пока разнообразия не наблюдается итолько этот факт останавливает меня от покупки этого чудо девайса. Ячертовски люблю мобильные гаджеты и думаю, что планшет для меняпросто необходимая вещь. Раньше я сходил с ума по нетбукам, но споявлением интернет-планшетов, я с удовольствием изменю своемустарому увлечению. Планшет еще мобильнее, легче и его удобнее брать ссобой. А мне именно это и нужно. Причем считаю, что оптимальнымвариантом является не эталон в лице iPad, а 7 дюймовые представители(вроде Samsung Galaxy Tab). Чем меньше – тем лучше (в разумныхпределах, конечно).

Сегодня мы можем наблюдать, как планшеты уже начали вытеснять нетбуки.Думаю в будущем (особенно после релиза iPad 2) этот процесс толькоускориться. А оно и понятно, зачем большинство пользователей (гиков врасчет не берем) приобретали нетбуки? Правильно, чтобы можно было ихбрать с собой и читать почту/серфить web и выполнять другие мелкиезадачи. Планшеты в этом плане выглядят куда привлекательней. Они ещелегче, компактней и не в функциональном плане ничуть не уступаютнетбкукам. Так, что мобильное будущее за планшетами.

Spider_NET:

Kastor: Я считаю, что у меня с мобильностью все в порядке. Если не нетбук, то КПКточно всегда со мной. Поэтому просмотреть электронный документ илипроверить почту не проблема. Для меня планшет это уже излишество. Иесли честно, я не сильно ими проникся. Да, прикольные девайсы. Но быстротекст не напечатать, клавы то нет. Держать на весу стремно (это мое личноемнение). Я бы ремешок с задней стороны приделал, что бы ладонь тудапросовывать. Думаю, так бы планшет увереннее лежал в руке. Хотя чистодля домашнего пользования, штука вполне подходящая. Кстати, вот нанашем сайте, совсем недавно была новость о новом планшете, пригодномбольше для рисования по нему стилусом. С виду так вообще обычнаядощечка с парой кнопочек. Учитывая обещанную стоимость не выше 1 00$, ябы такой купил не раздумывая. Была бы у меня универсальная тетрадь слекциями по всем предметам.

Page 92: VR-Online (February 2011)

92

vr-on l ine | февраль 201 1

CodeIgniter 2.0:Быстрая разработка web-сайтов. Часть 1

Автор: Игорь Антонов aka Spider_NETEmail : [email protected]

В последнее время мне на почту приходит куча писем с различными вопросамикасательно программирования на PHP. Честно говоря, я не знаю с чем это связано.Все-таки я уже давно не писал статей по web-программированию, т.к. моя основнаяработа с web’ом не связана, а для VR-Online мы используем Drupal. К счастью, для

него приходится что-то дописывать редко (хотя нет, просто в последнее время мы невнедряем новых фишек для сайта, поэтому ничего и не приходится кодить).

Поскольку я уже устал отвечать на однотипныевопросы, мне пришла в голову идея сделать циклзаметок, посвященных web-разработке. Мне нехотелось повторяться и в очередной разрассматривать голый php. Про это уже и такнаписано много статей/заметок. Мне показалось,что будет интересней (и полезней) познакомитьтебя с каким-нибудь framework’ом. Готовыекаркасы существенно упрощают разработку web-приложений. Они избавляют разработчика отнаписания рутинного кода, тем самымсущественно экономят время.

За всю практику web-программирования, мнедовелось поработать с тремя cmf (contentmanagement framework): CodeIgniter, Kohana иAdept. Больше всего мне понравилисьCodeIgniter и Kohana. Правда, с Kohan’ой я лишьуспел бегло познакомиться, а вот на CodeIgniterумудрился собрать несколько простенькихсайтиков. Adept мне изначально понравился, нопотом он перестал развиваться и пришлось пронего забыть. Соответственно больше всегоопыта у меня есть в работе с CodeIgniter,следовательно, цикл заметок будет посвященименно ему.

Когда-то я писал статью (http: //www.vr-onl ine.ru/content/codeigniter-obzor-frejmvorka-dl ja-php-635) про CodeIgniter для журнала IT-Спец. Вней я рассказал об основных возможностяхCodeIgniter’а, затронул теорию паттерна MVC ипривел простенький пример использованияфреймворка. К сожалению, впихнуть в статьювсе, что хотелось - не получилось. Поэтому ярекомендую тебе сначала прочитать статью, ауже потом переходить к чтению заметок.

Что мы будем делать

Заметки по CodeIgniter’у будут состоять из двухсюжетных линий. Первая – основная. В ней ябуду по шагам рассказывать про созданиепростенького движка для блога. Во второй я будупросто приводить решения различных задач,возникающих при разработке web-приложений.

Ты запросто сможешь использовать код и идеииз второй сюжетной линии, для улучшения блога,создание которого мы будем рассматривать восновной серии заметок. В общем, все должнобыть интересно. Главное не стесняйсякомментировать. Возникли вопросы – задавай.Есть предложения – пиши. Только при хорошейобратной связи мне удастся сделатьдействительно интересные заметки.

Готовим рабочее место

Для того, чтобы начать создавать приложения наоснове фреймворка CodeIgniter (далее CI), намнеобходимо подготовить рабочее место.Поскольку CI написан на php, то это ужеподразумевает, что нам потребуетсяинтерпретатор языка php, а также настроенныйApache и сервер баз данных MySQL. Установку инастройку этих компонент я рассматривать небуду, т.к. подобных мануалов уже написано нунереально много. Google – тебе в помощь. Ясразу перейду к установке CI .

В чем писать код

Тут все точно так же как и при разработке на php.Можешь писать код хоть в notepad’е, а можешьприбегнуть к услугам какой-нибудь навороченнойIDE. Из сред разработке я бы тебе посоветовалобратить внимание на Eclipse + PDD. Еслигромоздкие инструменты не твой стайл, топрисмотрись к бесплатному редакторуnotepad++. В нем есть все необходимое дляработы с php (и не только) кодом: подсветкасинтаксиса, свертка блоков кода, нумерациястрок и т.д.

Устанавливаем CI

Заходим на официальный сайтhttp: //codeigniter.com/ и качаем последнююверсию фреймворка (на момент написаниязаметки 2.0.0). Обрати внимание, что начиная совторой версии, CodeIgniter требует для работыPHP не ниже версии 5.1 .6.

Школа

Page 93: VR-Online (February 2011)

93

февраль 201 1 | vr-on l ine

Школа

Как сольешь CodeIgniter, распакуй его всоответствующую директорию на своем web-сервере (т.е. в корень). Перед тем какоткрыть свой браузер для теста, немногоотредактируй файл конфигурационный файлсвоего первого web-приложения. Оннаходится по пути:/application/config/config.php. Открой файл втекстовом редакторе и измени значениеприсвоенное в $config['base_url '] . Впишу тудакорректный url. Если ты тестируешьCodeIgniter на реальном хосте (с доменнымименем), то тебе нужно вписать сюда, что-товроде: http: //mydomain/. Я все тесты провожупод виртуалкой. К моему виртуальному хоступривязан псевдо домен – web.rf.Следовательно в $config[‘base_url ‘] мнепришлось вписать: http: //web.rf.

Теперь открывай браузер и обращайся ксвоему хосту. Если все компоненты былинастроены верно, то ты увидишь страницукак на рисунке 1 .

CodeIgniter установлен и готов к бою.

А дальше?

Продолжение цикла заметок по разработке блогас использованием CodeIgniter смотри на нашемсайте (http: //vr-onl ine.ru) и в следующем номережурнала. Все вопросы принимаю на мыло.

Рисунок 1. CodeIgniter успешно установлен

Page 94: VR-Online (February 2011)

94

vr-on l ine | февраль 201 1

CodeIgniter 2.0:Отправка электронной почты

Автор: Игорь Антонов aka Spider_NETEmail : [email protected]

В прошлой заметке я рассказал тебе о своих планах касательно циклапостов о CodeIgniter и описал процесс установки этого фреймворка.

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

Поскольку тема этой заметки не входит восновную сюжетную линию (см. предыдущуюстатью), то я не буду расписывать все по шагам,а сразу перейду к делу. Если прочитав этот постты не сможешь воспроизвести пример – неотчаивайся. Отложи его ненадолго в сторону иподожди заметок основной серии или обратисько мне с вопросом на мыло.

Для облегчения процесса отправки электроннойпочты в CodeIgniter’е имеется класс Email . В немреализованы все необходимые свойства иметоды, позволяющие сделать процесс отправкикорреспонденции максимально простым. Небудем ходить вокруг да около, а сразу посмотримна список имеющихся свойств/методов. Начнемсо свойств.

Свойства класса Email

- useragent – Программа отправитель. Значениепо умолчанию равно CodeIgniter.

- protocol – Протокол, используемый дляотправки почты. По умолчанию установленозначение ‘mail ’ . Что подразумеваетиспользование php’шной функции mail(). Помимоmail , тебе также доступны следующие варианты:sendmail (для пересылки будет использоватьсяsendmail) и smtp (старый добрый simple mailtransfer protocol).

- mailpath – путь к sendmail . По умолчанию равен/usr/sbin/sendmail .

- smtp_host – адрес smtp сервера;

- smtp_user – имя пользователя на smtp сервере.

- smtp_pass - пароль пользователя на smtpсервере.

- smtp_port - порт smtp-сервера;

- smtp_timeout – таймаут в секундах;

- wordwrap – автоматический перенос строк. Поумолчанию принимает TRUE (включен);

- wrapchars – количество символов, после

которого должен выполнятся перенос (значниепо умолчанию 76);

- mailtype – Тип почтового сообщения. Доступнодва варианта: text и html. По умолчаниюпринимает значение text (т.е. текстовое).

- charset – кодировка письма. Значение поумолчанию utf-8.

- val idate – требуется ли производить проверкуадреса электронной почты. Значение поумолчанию FALSE;

- priority – приоритет письма. Возможныезначения: 1 – наивысший; 5 – наименьший; 3 –обычный;

- crlf - символы первода каретки. Значение поумолчанию \n. Для соответствия спецификацииRFC 822 необходимо использовать значение \r\n;

- newline – символ новой строки. Значение поумолчанию \n. Для соответствия спецификацииRFC 822 необходимо использовать значение \r\n;

- bcc_batch_mode – включения режима BCC Bath.Значение по умолчанию FALSE;

- bcc_batch_size – количество email-адресов вBCC Bath. Значение по умолчанию 200;

Методы класса email

- from (email отправителя, ‘Имя отправителя’) –устанавливает адрес и имя отправителя письма;

- reply_to (email , ‘Имя отправителя’) – методустанавливает адрес и имя отправителя,который будет использоваться при ответе написьмо;

- to (‘адрес/список адресов через запятую’) –метод выполняет установку адресовполучателей. Ты можешь указать как адрес оногополучателя, так и нескольких (через запятую).Кроме того, в качестве параметра методу можнопередать массив с адресами;

- cc(‘адрес или список адресов’) – метод

Школа

Page 95: VR-Online (February 2011)

95

февраль 201 1 | vr-on l ine

Школа

устанавливает адреса для поля «Копия». Тутдействуют все те же правила, что и на метод to();

- bcc(‘адрес или список адресов’) – методустанавливает адреса для поля «BCC». Опятьже, действуют все правила как для метода to();

- subject(‘тема письма’) – метод устанавливаеттему письма;

- message(‘тело письма’) – метод устанавливаеттело письма;

- set_alt_message(‘альтернативное тело письма’)– метод устанавливает альтернативное телописьма. Используй этот метод если хочешь бытьуверенным, что твое сообщение прочитают всепользователи. Например, можешь в message()передать красивое оформленное телосообщения (с использованием html), а вalt_message текствый вариант. Если клиентпользователя не поддерживает отображение htmlписем, то он увидит альтернативный текстписьма.

- clear() – метод приводит все поля сообщения висходное состояние. Другими словами – методвыполняет очистку все заполненных полей;

- send() – метод выполняет отправку письма.Если отправка выполнится успешно, торезультатом будет TRUE. Иначе FALSE.

- attach(‘путь к прекрепляемому файлу’) – методпозволяет прикрепить к письму произвольныефайлы;

- print_debbuger() – метод возвращает строку,содержащую сообщения сервера, заголовкисообщения, а также текст сообщения. Методполезно использовать во время отладки;

Практический пример

Свойства и методы класса email мы рассмотрелии теперь самое время закрепить полученныезнания на практике. Я не буду создавать какой-тонавороченный примерчик, а просто создамновый контроллер и опишу в нем метод send-email . При обращении на эту страницу будетсформировано и отправлено письмо на мойemail . Итак, начнем по порядку.

1 . Создаем новый контроллер. Я его назвал test.Изначальный код контроллера выглядит так:class Mycontroller extends Controller { }

Весь этот код у меня располагается в файле сименем mycontrol ler.php.

2. Описываем в контроллере Mycontrol ler новыйметод send-email :function send() {//загружаем библиотеку email$this -> load -> library (' email' ) ;

//выполняем инициализацию и заполняем всенеобходимые поля$this -> email -> initialize() ;

$this -> email -> mailtype = ' html' ;$this -> email ->from(' antonov. igor@live. ru' , ' Antonov Igor' ) ;$this -> email ->to(' antonov. igor. khv@gmail. com' ) ;$this -> email -> subject(' Проверка отправкипочты из CodeIgniter' ) ;$this -> email -> message(' Hi! ! ! This istest! ' ) ;

if (! $this -> email -> send() ) {echo (' Не удалось выполнить отправку

письма! ' ) ;} else {

echo (' Письмо было успешноотправлено! ' ) ;}}

3. Сохраняем весь набранный код изагружаемый контроллер на сервер. Затемоткрываем браузер и пробуем обратиться кнашему контроллеру -http: //mysite/mycontrol ler/send.

Если вышеописанные действия были проделаныправильно, то ты увидишь картинку как нарисунке 1 .

Рисунок 1. Результат работы кода

Изображение свидетельствует о том, что кодвыполнился корректно и можно заглянуть в свойпочтовый ящик для проверки наличия письма(см. рисунок 2).

Рисунок 2. А вот и письмо!

Письма все отправлены

Вот таким образом можно выполнять отправкупочты средствами CodeIgniter. Полный исходникконтроллера в архиве с журналом. Как обычно,при возникновении вопросов – пиши.

Page 96: VR-Online (February 2011)

96

vr-on l ine | февраль 201 1

1С Предприятие 8Часть 8. Документы

Автор: Игорь Антонов aka Spider_NET

В нашей прошлой статье из цикла 1С, мы рассказали тебе о Справочниках.

Ты узнал что это такое и как их можно использовать для своих целей.

Сегодня ты узнаешь о еще одном объекте, который называется Документ.

Любая учетная система должна уметь отражатькакие-либо события своей деятельности, дляэтих целей в 1 С и используются документы. Посвоей сути они очень близки бумажнымдокументам. Например, поступил нам товар,поставщик отдает нам Накладную, в базе мысоздаем документ "Приходная накладная",который увеличивает наши остатки на складах.Или наоборот, мы продали некому Иванову И.И.товары, в базе мы создаем документ "Расходнаянакладная", заполняем список товаров, печатаеми отдаем напечатанные документы Иванову, аостатков в нашей базе стало меньше.

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

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

Классификация, приведенная нанижеследующем рисунке принята в учебныхматериалах фирмы 1 С.

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

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

Сами учетные данные хранятся в регистрах.Регистры - это те объекты учетной системы,которые накапливают информацию, и позволяютв дальнейшем делать различные анализы, неперебирая каждый документ в отдельности. Какпример регистра можно привести "Остаткитовара", "Продажи" или "Взаиморасчеты склиентами". Но разбираться с регистрами сейчасмы не будем, оставим на потом. Скажу только,что это один из главных инструментов1 С:Предприятия, во многом упрощающийразработку прикладных решений.

Отчеты позволяют представить информацию изрегистров в удобном для пользователя виде.Обработки, в отличие от отчетов, предназначеныдля изменения данных в системе, они могутизменять справочники, документы, регистры.Использование обработок позволяетавтоматизировать рутинные операции по вводу иизменению документов. Различие междуотчетами и обработками условное, выраженноетолько в их предназначении. Технически ониочень похожи, и ничто не мешает обработкевыводить отчет, а отчету изменять данные.

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

Школа

Рисунок 1

На рисунке справочники, константы,перечисления, и планы (планы счетов, планывидов расчета, планы видов характеристик)выделены в группу условно постоянной

Page 97: VR-Online (February 2011)

97

февраль 201 1 | vr-on l ine

Школа

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

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

число с точностью до 2 знаков после запятой.Поле клиент предлагает выбрать значения изсправочника Клиенты.

Рисунок 2

На закладке "Основные" нужно заполнить поле"Имя" (обратите внимание, что использоватьпробелы в имени нельзя), должно получиться какна рисунке 2. Затем переходите на закладку"Данные".

На ней мы добавим два реквизита: Клиент иСумма платежа. Для этого на верхней панели,где написано "Реквизиты", нажмите ужезнакомую кнопку с зеленым крестиком, справаоткроется панель свойств (похожая на панельсвойств в Visual Studio). Для каждого реквизитанадо заполнить поля "Имя" и "Тип".

Первый реквизит будет "Клиент" (см. рисунок 3).Заполните имя (помня что в имени нельзяиспользовать пробелы), синоним изменитьсяавтоматически. В поле тип есть кнопка с тремяточками нажмите ее, откроется формасодержащая все типы нашей конфигурации,раскройте ветку "СправочникСсылка" и поставьтегалочку напротив надписи "Клиенты".

Теперь добавим второй реквизит"СуммаПлатежа". В форме выбора типаВыберите "Число", обратите внимание, что внизуформы можно указать длину и точность длянашего реквизита, установите точность 2 - этопозволит нам указывать сумму платежа сточностью до копеек.

Запустим конфигурацию в пользовательскомрежиме.

Откроем наш документ с помощью меню(Операции - Документы - Приходный кассовыйордер). Создадим новый документ.

В форме документа представлено четыре поляДата, Номер, Клиент и Сумма платежа. Каквидим, поле сумма платежа предлагает ввести

Рисунок 3

Поля Дата и Номер - это предопределенныеполя, которые создаются для каждого документа,так же как поля Код и Наименования длясправочника. Эти поля созданы, потому чтодокумент в, большинстве случаев имеютпривязку к определенной дате и времени (тот жеприходный кассовый ордер), и так ужисторически сложилось, что документамприсваивают номера, а не коды (разница тольков названии, с технической точки зрения одниодинаковые).

Заполните документ и нажмите кнопку"Записать", потом "Закрыть".

Затем создайте новый документ, заполните его инажмите кнопку "ОК". Видите разницу.

Рисунок 4

При нажатии кнопку "ОК", документ "проводится",а при нажатии "Записать", только сохраняется,не проводясь. Это еще одна фишка документов.

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

Page 98: VR-Online (February 2011)

98

vr-on l ine | февраль 201 1

на учетные данные. Но ведь бывает, чтодокумент ну очень большой, несколько сотенстрок. Чтобы ввести документы пары секунднедостаточно, и может потребоваться сохранитьрабочую версию документа, не внося измененияв учетные данные. Например если не успелзаполнить документ, а рабочий день закончисля,или обед, или отвлекли другой работой. А можетбыть, что следует создать черновую версиюдокумента, чтобы подготовиться к приходуклиента.

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

А теперь давайте создадим более сложныйдокумент "Реализация товаров", в котором будемуказывать клиента и списком товаров, которыеон у нас купил.

Но для этого нам понадобиться создатьСправочник "Номенклатура", чтобы хранитьперечень товаров, которые мы продаем. Вконфигураторе откроем дерево конфигурации,перейдем на закладку Справочники, нажмем"Добавить"(зеленый крестик), назовемсправочник "Номенклатура", затем перейдем назакладку "Данные" и добавим реквизит "Цена" стипом "Число" и точностью 2.

Справочник готов. Запустим программу впользовательском режиме и откроем наш новыйсправочник (Операции - Справочники -Номенклатура).

Заполните справочник данными. Заметьте, чтокроме наименование у справочника есть еще ицена.

"СправочникСсылка.Клиенты". В нижнейполовине формы есть область "Табличныечасти", нажмите кнопку "Добавить табличнуючасть"(чуть выше этой области). Добавитьсяновая табличная часть, задайте ей название"Товары". Затем нажмите кнопку "Добавитьреквизит"(находится там же). Добавится реквизитв табличную часть. Добавившемуся реквизитуназначьте имя "Номенклатура" и тип"СправочникСсылка.Номенклатура". Такжедобавьте реквизиты "Цена", "Количество" и"Сумма" с типом Число и точностью 2 знака.

Документ готов, откройте программу впользовательском режиме и создайте новыйдокумент. Заметили, в документе появиласьтаблица, со структурой колонок, которую мызадали (Номенклатура, Цена, Количество,Сумма). Заполните документ. Не очень удобносчитать сумму в документе, не правда ли? Да ицену товару мы уже назначили в справочникеНоменклатура, было бы неплохоавтоматизировать процесс заполнения.

Да и еще есть предложение считать итоговуюсумму документа и выводить ее в спискедокументов.

Возвращаемся в режим конфигуратора,открываем документ "Реализация товаров",закладку "Данные". Добавим реквизит "Суммадокумента" (не путайте с реквизитом табличнойчасти) типа "Число" и точностью 2.

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

Формы в 1 С:Предприятие аналогичны формам сДелфи и Visual Studio, но есть некоторыеотличия. Формам в 1 С на уровне платформыдобавлены некоторые действия связанные сданными, отображение, сохранение. Например,вам не нужно указывать какое поле отвечает закакой реквизит. Платформа уже сама настроилаэту связь. И таблица на форме уже связана сданными открываемого документа. Также естьопределенные действия, такие как сохранение ипроведение, которые будут выполняться принажатии соответствующих кнопок и которые вамописывать не нужно.

Но в то же время формы в 1 С событие-ориентированные, т.е. у каждого поля естьсобытия, которые вызываются при определенныхусловиях, и разработчик может указатьобработчики этих событий. Экран формы можноразделить на две составляющих: диалог имодуль. В диалоге настраивается расположениеэлементов, в модуле располагается кодобработчиков событий.

В диалоге удалите элемент "Сумма документа",мы не хотим его редактировать вручную.

Затем выделите двойным щелчком мыши поле втаблице, под надписью "Номенклатура". Воткрывшейся панели свойств в самом низу естьраздел "События", найдите событие "Приизменении", напротив есть кнопка с лупой,

Школа

Рисунок 5

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

Вы уже умеет добавлять реквизиты в документ,добавьте реквизит "Клиент" типа

Page 99: VR-Online (February 2011)

99

февраль 201 1 | vr-on l ine

Школа

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

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

Заходите в конфигуратор, открывайте формудокумента "Реализация товаров", на закладке"Диалог" дважды щелкните мышкой по заголовкуформы (см. рис. 7)

Листинг1ПроцедураТоварыНоменклатураПриИзменении(Элемент)

Данные =ЭлементыФормы. Товары. ТекущиеДанные;

Данные. Цена = Данные. Номенклатура. Цена;

Данные. Сумма = Данные. Цена *Данные. Количество;

КонецПроцедуры

Поясним смысл этих строк. Через переменнуюЭлементыФормы мы получаем доступ к даннымвведенным в форму, в частности в таблицуТовары. В свойстве ТекущиеДанные содержитсяструктура данных активной строки таблицы.Через это свойство можно как получать данные,так и устанавливать. Таким образом, мы можемустановить значение в поля "Цена" и "Сумма".

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

Листинг2Процедура ТоварыЦенаПриИзменении(Элемент)

Данные =ЭлементыФормы. Товары. ТекущиеДанные;

Данные. Сумма = Данные. Цена *Данные. Количество;

КонецПроцедуры

ПроцедураТоварыКоличествоПриИзменении(Элемент)

Данные =ЭлементыФормы. Товары. ТекущиеДанные;

Данные. Сумма = Данные. Цена *Данные. Количество;

КонецПроцедуры

Рисунок 6

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

Рисунок 7

В открывшейся панели свойств найдите событие"Перед записью". Это событие самой формы.Оно сработает перед записью данных в базу.Создайте обработчик события. Код будет такой.

листинг 3Процедура ПередЗаписью(Отказ, РежимЗаписи,РежимПроведения)

СуммаДокумента = Товары. Итог("Сумма" ) ;

КонецПроцедуры

В форме списка реквизит "Сумма документа" ужеприсутствует, добавлять его не надо. Поэтомубольше ничего менять не нужно. Откройтепрограмму в пользовательском режиме ипротестируйте внесенные изменения. На этомсегодняшний урок закончим, надеюсь былоинтересно, и вы узнали что-то новое. И какобычно дадим вам домашнее задание, ведьчтобы научиться, нужно что-то делать самому.

1 ) Создайте документ "Оприходование товаров"с табличной частью Товары (Номенклатура,Количество), он будет оприходовать товары вдальнейшем.

2) В документ "Реализация товаров" сделайтеследующее изменение. Добавьте колонку скидкатипа "Число". В нее будет устанавливатьсяскидка в процентах (от 0 до 1 00) и сумма строкидолжна пересчитываться при изменении этогополя. Учтите, что нужно изменить алгоритмы приизменении Номенклатуры, Количества и Цены,чтобы они тоже учитывали скидку.

3) Следующее занятие будет про регистрынакопления, поэтому, если есть желание,попробуйте самостоятельно создать регистрнакопления "товары на складах" и сделать так,чтобы документ "Реализация" делал движенияпо этому регистру.

Подсказка. В документе есть закладка"Движения", а в ней кнопка "Конструктордвижений".