Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1291 сообщений
Cообщения с меткой

delphi - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

[Из песочницы] Пишем клавиатурный шпион на Делфи 7

Четверг, 19 Мая 2016 г. 17:29 (ссылка)


Это моя первая статья, потому не буду многословным и постараюсь как можно короче описать разработку клавиатурного шпиона на Делфи. Использовать мы будем функцию WinApi (getasynckeystate), осуществляющую глобальный перехват нажатия клавиш клавиатуры.



Описание: function GetAsyncKeyState(Key: Integer): Integer;

Опpеделяет состояние виpтуальной клавиши.

Параметры: Key: Код виpтуальной клавиши.

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



Также нам понадобиться функция GetForegroundWindow — возвращает дескриптор приоритетного окна (окна, с которым пользователь в настоящее время работает). Система присваивает немного более высокий приоритет потоку, который создает приоритетное окно, чем тот, который она дает другим потокам.



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



Начнём по порядку: открываем Делфи, заранее сохраняем наш проект, заходим в обработчик событий нашей формы вкладка Events и находим событие OnShow, два раза щёлкаем левой клавишей мыши на событие и пишем код.

Читать дальше →

https://habrahabr.ru/post/301232/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Delphi. Что таит в себе TDictionary

Среда, 04 Мая 2016 г. 09:18 (ссылка)



Доброго времени суток.

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

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





1. Как устроена хеш таблица.

Если вы отлично знаете как устроена хеш таблица, и что такое linear probing — можете смело переходить ко второй части.



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

Итак мы подготовили массив из скажем 10 bucket-ов. Теперь мы готовы складывать значения в наш массив. Мы берем хеш от нашего ключа. Например хеш оказался 32 битным целым числом M. Чтобы определить, в какой bucket мы будем ложить наше значение — мы берем остаток от деления: Index := M mod 10. И ложим в bucket[Index] := NewKeyValuePair.

Рано или поздно мы столкнемся с тем, что в bucket[Index] уже будет лежать какое-то значение. И нам нужно будет что-то с этим делать. Такой случай называется разрешением коллизий (Collision resolution). Существует несколько техник разрешения коллизий. Вот основные:



Separate chaining или closed addressing


В простейшем случае этот метод представляет вот что. Каждый bucket — это ссылка на голову связанного списка (linked list). Когда возникает коллизия — мы просто добавляем в linked list еще один элемент. Чтобы наш список не выродился в несколько линейных linked list-ов вводят такое понятие как load factor. То есть когда количество элементов на один bucket превышает некоторое число (load factor) — создается новый массив bucket-ов, и все элементы из старого распихиваются по новым. Процедура называется rehash.

Недостатки этого подхода в том, что для каждой пары <ключ, значение> мы создаем объект, который надо добавить в linked list.

Этот подход можно улучшить. Например если вместо bucket-ов хранить пару <ключ, значение> + ссылку на голову linked list-а. Установив load factor в 1 или даже 0.75 можно практически избежать создания элементов linked list-а. А bucket-ы, которые есть массив — очень дружелюбно ложаться на кеш процессора. p.s. На данный момент я считаю это лучшим способом разрешения коллизий.



Open addressing


Для этого метода у нас все bucket-ы — это массив <ключ, значение>, и абсолютно все элементы хеш таблицы хранятся в bucket-ах. По одному элементу на bucket. Попытка вставить элемент в такую хеш таблицу называется probe. Наиболее известны такие методы проб: Linear probing, Quadratic probing, Double hashing.

Давайте посмотрим как работает Linear probing.

Вот мы попали в ситуацию, когда bucket уже занят другим элементом:



Тогда мы просто прибавляем к bucket-у единицу, и ложим элемент в соседний:



Снова попали в этот же bucket? Теперь придется перешагнуть аж 3 элемента:



А вот совсем неудачно получилось:



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

Попытка обойти неудачную хеш функцию — это Quadratic probing и Double hashing. Суть Quadratic probing в том, что следующая probe будет через 1, 2, 4, 8 и т.д. элементов. Суть Double hashing в том, что размер прыжка для следующей probe выбирается с помощью хеш функции. Либо отличной от первой, либо той же, но хеш берется от индекса bucket в который только что пытались положить.

Но самое главное в Open addressing то, что даже если мы 10000 элементов заполнили без единой коллизии, то добавление 10001-го может привести к тому, что мы переберем все 10000 уже находящихся там элементов. Но самое страшное, что когда мы положим этот 10001-ый, чтобы потом к нему обратиться — нам опять придется перебрать 10000 предыдущих.

Есть еще одна неприятная вещь, которая следует из всего вышесказанного. Для Open addressing важен порядок заполнения. Какая бы замечательная хешфункция не была все может испортить порядок заполнения. Давайте посмотрим последний рассмотрим последний случай, нам не повезло. Все элементы были заполнены без единой коллизии, но последний элемент с коллизией, которая привела к перебору кучи bucket-ов:



А что если бы мы сначала положили этот единственный элемент:



у нас коллизия, мы перебрали всего 1 бакет.

А потом положили бы соседа:



снова перебрали бы 1 бакет.

И следующего соседа:



В сумме добавление бы привело всего к одной коллизии на каждый элемент. И хотя суммарное кол-во перебранных bucket-ов при добавлении осталось бы прежним — оно в целом стало бы более сбалансированным. И теперь при обращении к любому элементу мы бы сделали 2 проверки в bucket-ах.



2. Так что же не так в Delphi с Linear probing в TDictionary?



Ведь такой «неудачный» порядок с хорошей хешфункцией сложно получить, скажите вы? И сильно ошибетесь.

Для того, чтобы получить все элементы TDictionary — нам надо пройтись по массиву бакетов, и собрать элементы в занятых ячейках. Главный подвох тут в том, что последовательность сохраняется! Просто создаем еще один TDictionary, и перекидываем данные в него… и получаем кучу коллизий на последних элементах перед очередным grow.

Простейший код, чтобы воспроизвести ситуацию:

    Hash1 := TDictionary.Create();
Hash2 := TDictionary.Create();

for i := 0 to 1280000 do // этот TDictionary заполнится очень быстро
Hash1.Add(i, i);
for i in Hash1.Keys do // а этот - неожиданно медленнее, в десятки раз!
Hash2.Add(i, i);


В TDictionary rehash наступает только тогда, когда свободных ячеек в массиве bucket-ов становится меньше 25% (Grow threshold = 75%). Увеличение емкости происходит всегда в 2 раза. Вот заполненные bucket-ы в большом словаре:



попытка добавить данные элементы в таблицу меньшего размера можно рассмотреть так. Разделим большую таблицу на 2 части. Первая часть ляжет абсолютно идентично.



Теперь нам надо добавить элементы из второй половины (зелененькие).



Видите как растет число коллизий при добавлении второй половины? И если до rehash-а еще далеко, а таблица достаточно большая — мы можем получить колоссальный оверхед.

Давайте посчитаем кол-во коллизий при добавлении нового элемента. Для этого я скопировал себе исходный код TDictionary, и добавил пару коллбек методов, возвращающих коллизии. Результаты вывел на графики:



Я заполнял хеш таблицу значениями, и по мере заполенения измерял количество коллизий, каждые новые N значений отображает новый пиксель по оси X. Т.е. горизонтальная ось отображает заполнение таблицы, а вертикальная — количество коллизий. Справа от каждого графика значения:


  • Max collision — максимальное количество коллизий в пределах одного пикселя по оси X.

  • Items per pixel — количество элементов, приходящихся на один пиксель графика по оси X.

  • Items count — суммарное кол-во элементов в хештаблице

  • Filling percentage — отношение кол-ва элементов к количеству bucket-ов в таблице.



На первом графике при заполнении 48% все хорошо. Максимум коллизий 169. Как только мы перешагиваем 50% — начинается самая жуть. Так при 61% наступает самая жость. Количество коллизий на элемент может достигать 130 тысяч! И так до 75%. После 75% происходит grow, и процент заполнения уменьшается.

Каждая пила с кучей коллизий — ничто иное, как то, что я показывал на рисунке выше. Заканчивается «пила» rehash-ом и резким падением коллизий.

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

Как же это исправить? Ну самый очевидный вариант — это grow threshold установить в 50%. Т.е. свободных ячеек в хештаблице должно быть не менее 50%. Изменение этого порога дает вот такие графики:



на тех же объемах данных. Ценой дополнительной памяти мы «выйграли» себе процессорное время. Проблема тут в том, что поле GrowThreshold недоступно снаружи. Можно так же постараться избежать неудачных последовательностей. Либо вручную перемешивать/сортировать данные перед помещением в таблицу, что достаточно накладно, либо создавать разные таблицы с разными хешфункциями. Многие хешфункции (такие как Murmur2, BobJenkins hash) дают возможность задать Seed/InitialValue. Но эти значения наобум подбирать тоже не рекомендутеся. В большинстве случаев в качестве seed подойдет простое число, но все таки лучше почитать мануал по конкретной хеш функции.

Ну и наконец мой совет — не используйте Open addressing как универсальный метод для любой хеш таблицы. Я считаю лучше обратить внимание на Separate chaining с бакетами <ключ, зачение>+указатель на голову linked list-а с load factor-ом около 0.75.



p.s. На поиск данного подводного камня я потратил несколько дней. Ситуация осложнялась тем, что большие объемы данных отпрофайлить сложно + зависимость от % заполнения TDictionary приводила к тому, что тормоза мистическим образом переодически пропадали. Так что спасибо за внимание, и надеюсь вы об это не споткнетесь. ;)



Original source: habrahabr.ru.

https://habrahabr.ru/post/282902/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Релиз FastReport 5.5 для Lazarus и RAD Studio (Delphi, C++Builder)

Четверг, 28 Апреля 2016 г. 17:31 (ссылка)

Друзья, поздравляю всех с выходом нового релиза FastReport 5.5 для Lazarus и RAD Studio (Delphi, C++Builder)!



Вчера компания FastReport выпустила свой флагманский продукт FastReport.

FastReport — генератор отчётов любой сложности с огромными возможностями для Delphi, C++Builder и Lazarus.



На мой взгляд, продукт FastReport не нуждается в каком-то особом представлении, этот продукт является де-факто стандартом построения отчётов не только в России, СНГ, но и во всём мире. Практически любое бизнес-приложение нуждается в использовании генератора отчётов.

image



Новый релиз FastReport 5.5 полностью совместим с последними новейшими инструментами разработки приложений в RAD Studio 10.1 Berlin и Lazarus 1.6.

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





image



Как известно, кроссплатформенная среда разработки Lazarus позволяет разрабатывать оконные приложения для различных ОС, в том числе и для Linux, и теперь разработчики могут в полной мере насладиться, используя новые возможности последней версии FastReport.



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

FastReport при всей своей простоте и удобстве способен обеспечить должный функционал и скорость работы практически на любом современном компьютере.



image



Основные новые возможности FastReport 5.5:



— поддержка среды разработки Embarcadero RAD Studio 10.1 Berlin;

— поддержка среды разработки Lazarus 1.6;

— множество улучшений и новых возможностей для Lazarus;

— для VCL улучшена работа FastReport с высоким dpi разрешением экрана;

— исправлены параметры в FireDAC;

— добавлена поддержка TfrxPrintMode в frxClassRTTI;

— исправлено обновление списка источников бумаги после смены TfrxReport.PrintOptions.Printer в дизайнере;

— [Fast Script] увеличена точность FormatFloat;

— исправлена печать на принтерах с высоким разрешением;

— исправлено числовое форматирование в XLSX экспорте;

— исправлено использование FieldNames в DBF экспорте;

— исправлен Z-order для изображений в HTML(Layered) экспорте;

— добавлена поддержка HTML тэгов и межстрочного интервала в DOCX экспорте;

— добавлен пример SynPDF Export;

— улучшен кэш изображений;

— [Lazarus] добавлен экспорт в PDF;

— [Lazarus] добавлена поддержка стандартного объекта Chart;

— [Lazarus] исправлена печать изображений;

— [Lazarus] исправлена совместимость с x64 платформами;

— исправлены проблемы с изображениями и диалоговыми формами;

— исправлены проблемы неправильного масштабирования;

— исправлено горизонтальное выравнивание в ODF экспорте;

— исправлена ошибка с цветом и рамкой страницы в PDF экспорте;

— исправлен шрифт стилей для HighDPI;

— и многое другое.



Подробнее с новыми возможностями можно ознакомиться на официальном сайте:

www.fastreport.ru/ru/news/373



Самые важные ссылки по FastReport:



Руководство пользователя в PDF:

https://www.fastreport.ru/public_download/docs/vcl/UserManual-ru.pdf

Online — руководство пользователя:

https://www.fastreport.ru/public_download/html/FR5UserManual-HTML-ru/index.html



Скачать последнюю версию для RAD Studio (Delphi, C++Builder) с официального сайта:

https://www.fastreport.ru/ru/download/fast-report-vcl-5/

Скачать последнюю версию для Lazarus с официального сайта:

https://www.fastreport.ru/ru/download/fast-report-lazarus/



Хочется добавить, что компания FastReport создала почти совершенный продукт и при этом ещё уделила особое внимание:

— качеству продукта;

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

— наличию руссификатора;

— наличию различных примеров;

— выполнению поддержки на русском языке.

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



image



Желаю получить удовольствие от использования одного из лучших инструментов в отрасли по генерации отчётов.

Всем удачи!



Update 1:

для Lazarus в Linux необходима редакция Pro с исходниками и Qt (которая устанавлена по умолчанию).



Original source: habrahabr.ru.

https://habrahabr.ru/post/282712/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Релиз RAD Studio 10.1 Berlin (Delphi, C++Builder)

Среда, 20 Апреля 2016 г. 18:23 (ссылка)

Друзья, поздравляю всех с выходом RAD Studio 10.1 Berlin!



image



Вчера компания Embarcadero представила новую версию RAD Studio 10.1 Berlin.

RAD Studio 10.1 Berlin — это законченное средство для быстрой разработки кроссплатформенных приложений с помощью Object Pascal и C++.



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

image



Основные новые возможности RAD Studio 10.1 Berlin (Delphi, C++Builder):



— изменился механизм установки RAD Studio (и до установки);

— поддержка Android 6.0 (API Level 23);

— улучшения в Android Service;

— улучшения в FireDAC для DB2, MongoDB, Firebird, Oracle, PostgreSQL, SQLite;

— новый компонент TAddressBook, который позволяет получить доступ к адресной книге на платформе Android и iOS;

— улучшен Style Designer в FireMonkey;

— улучшен механизм предварительного просмотра интерфейса для различных устройств;

— улучшен механизм поддержки IoT (Интернет вещей);

— новый элемент ListView;

— улучшен IFMXExtendedClipboardService для работы с буфером обмена;

— улучшен редактор списка изображений в компоненте FMX.TImageList;

— поддержка High DPI для Windows-приложений;

— поддержка EMS сервера Apache;

— новые возможности EMS;

— улучшен BeaconFence для работы с маячками;

— улучшена производительность с Bluetooth LE, Beacon;

— поддержка асинхронных HTTP запросов;

— улучшен класс TStrings, появились новые методы;

— улучшен TMemIniFile;

— улучшена производительность с Generics;

— добавлены зависимости в GetIt Package Manager;

— и многое другое.



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

http://docwiki.embarcadero.com/RADStudio/Seattle/en/What's_New



image



Несколько полезных ссылок по теме:



Обзор RAD Studio 10.1 Berlin:

http://www.embarcadero.com/ru/products/rad-studio



Список исправленных багов (Fix List)

http://edn.embarcadero.com/article/44675



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

http://docwiki.embarcadero.com/RADStudio/Berlin/en/Installation_Notes



На официальном сайте появилась возможность скачать RAD Studio 10.1 Berlin:

https://downloads.embarcadero.com/free/rad_studio

или используйте ISO-образ для установки новой версии:

http://altd.embarcadero.com/download/radstudio/10.1/delphicbuilder10_1.iso



Желаю получить удовольствие от работы с новым релизом RAD Studio 10.1 Berlin.

Всем удачи!



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/282055/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Слабые[weak] ссылки в новой версии Delphi

Среда, 20 Апреля 2016 г. 14:19 (ссылка)

Здравствуйте.



Компания Embarcadero вчера объявила о выходе новой версии Delphi RAD studio XE 10.1,

Весь список изменений можно посмотреть тут я же хочу рассказать о наиболее ценном(для нашей компании) улучшении, а именно о внедрение слабых [weak] ссылок в классический компилятор (Win32/Win64).



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



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

1. В классе элемента использовали не типизированный указатель для поля FOwner. Присвоение интерфейсной ссылки к такому указателю не приводило к увеличению счетчика ссылок, что решало проблему циклической ссылки, однако этот код не безопасен — в случае если коллекция умрет раньше элемента (ссылка на который где-то оказалась присвоена), то нет безопасного способа узнать об удалении коллекции — владельца. Указатель FOwner — продолжал указывать на уже удаленную память.

2. Чтобы решить проблему предыдущего способа можно внедрить оповещение элементов об удалении коллекции. При удалении коллекция пробегает по всем своим элементам и вызывает у них некий метод, который в свою очередь “заниливает” поле FOwner. Минус этого подхода — это дополнительный код и время необходимое на его выполнение. В случае с нашим примером коллекции это еще не так страшно, но в других не тривиальных примерах этот код может очень сильно запутать логику и добавить ошибок.

И вот в последней версии XE10.1 Berlin появилась по человечески нормальная возможность решать эту проблему. Все что нужно, это объявить поле FOwner c атрибутом [weak]. Такая ссылка по прежнему будет строго типизированной, но присвоение в которую не будет увеличивать счетчик ссылок на исходный объект. В случае же когда объект (в нашем случае коллекция-владелец) удаляется из памяти, такая ссылка автоматически “занилится”, что будет индикатором что объект удален.



Напишем два интерфейса, и 2 класса реализующих эти интерфейсы (данный пример упрощен до предела, а вопросы оптимизации скорости вообще не стояли)

Описание интерфейсов и классов
type
{интерфейс элемента}
IXListItem = interface
['{02E680D6-9F86-4303-85B5-256ACD89AD46}']
function GetName: string;
procedure SetName(const Name: string);
property Name: string read GetName write SetName;
end;

{интерфейс коллекции}
IXList = interface
['{922BDB26-4728-46DA-8632-C4F331C5A013}']
function Add: IXListItem;
function Count: Integer;
function GetItem(Index: Integer): IXListItem;
property Items[Index: Integer]: IXListItem read GetItem;
procedure Clear;
end;

{класс имплементатор элемента}
TXListItem = class(TInterfacedObject, IXListItem)
private
[weak] FOwner: IXList; // слабая ссылка на коллекцию
FName: string;
public
constructor Create(const Owner: IXList);
destructor Destroy; override;
procedure SetName(const Name: string);
function GetName: string;
end;

{класс имплементатор коллекции}
TXList = class(TInterfacedObject, IXList)
private
FItems: array of IXListItem;
public
function Add: IXListItem;
function Count: Integer;
function GetItem(Index: Integer): IXListItem;
procedure Clear;
destructor Destroy; override;
end;




Как видим в объекте TXListItem есть слабая ссылка на объект владелец.



Реализация класса TXListItem, в методе GetName мы пользуемся нашей слабой ссылкой:

TXListItem
{TXListItem}
constructor TXListItem.Create(const Owner: IXList);
begin
FOwner := Owner; // получение слабой ссылки
end;

destructor TXListItem.Destroy;
begin
ShowMessage('Destroy ' + GetName);
inherited;
end;

function TXListItem.GetName: string;
var
List: IXList;
begin
List := FOwner;
if Assigned(List) then
Exit(FName + '; owner assined!')
else
Exit(FName + '; owner NOT assined!');
end;

procedure TXListItem.SetName(const Name: string);
begin
FName := Name;
end;




Класс TXList банален:

TXList
{ TXList }

function TXList.Add: IXListItem;
var
c: Integer;
begin
c := Length(FItems);
SetLength(FItems, c + 1);
Result := TXListItem.Create(Self);
FItems[c] := Result;
end;

procedure TXList.Clear;
var
i: Integer;
begin
for i := 0 to Length(FItems) - 1 do
FItems[i] := nil;
end;

function TXList.Count: Integer;
begin
Result := Length(FItems);
end;

destructor TXList.Destroy;
begin
Clear;
ShowMessage('Destroy list');
inherited;
end;

function TXList.GetItem(Index: Integer): IXListItem;
begin
Result := FItems[Index];
end;




Объявляем наши переменные:

var
var
Form1: TForm1;
List: IXList;
Item: IXListItem;




И методы для создания и удаления объектов.

methods
procedure TForm1.btnListCreateAndFillClick(Sender: TObject);
begin
List := TXList.Create; // создаем коллекцию
List.Add.Name := 'item1'; // заполняем тремя элементами
List.Add.Name := 'item2';
Item := List.Add; // последний элемент запоминаем в глобальную переменную
Item.Name := 'item3';
end;

procedure TForm1.btnListClearClick(Sender: TObject);
begin
List := nil; // освобождаем коллекцию
end;

procedure TForm1.btnLastItemFreeClick(Sender: TObject);
begin
Item := nil; // освобождаем последний элемент, который отдельно запомнили
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ReportMemoryLeaksOnShutdown := true; // Включаем проверку утечек памяти
end;




Пример работы с объявлением [weak] ссылки:

image



Пример работы без объявлением [weak] ссылки:





Как видим без использования [weak] ссылки, коллекция и элементы циклически ссылаются друг на друга и у них не вызывается деструкторы, и соответственно мы получаем утечку памяти о чем нам и сообщает FastMM.



Также в новой версии появился атрибут [unsafe] который является аналогом [weak], но при удалении объекта на который она ссылается, ссылка автоматически не “заниливается”.

С ним кстати мы уже нашли один баг, который и отправили в qc.



Благодарю за пример и помощь в написании коллегу h_xandr.



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/282035/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Релиз Lazarus 1.6

Суббота, 02 Апреля 2016 г. 09:28 (ссылка)

Друзья, поздравляю всех с выходом нового релиза Lazarus 1.6!

Оказывается, мы забыли посвятить этому событию отдельный пост, навёрстываем.



image



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



Lazarus – это среда быстрой разработки кроссплатформенных приложений с помощью Object Pascal из единого исходного кода проекта.



Lazarus – свободно распространяемая среда программирования на Object Pascal, некий бесплатный аналог Delphi.



Среду разработки Lazarus можно установить в Windows (x32, x64), Linux, FreeBSD, OS X.



image



Основные новые возможности Lazarus 1.6



— ключевым улучшением является переход на использование Free Pascal 3.0 и поддержка реализованных в нём новых возможностей;

— добавлена поддержка механизма Project group;

— добавлена поддержка Delphi-подобных пространств имён для модулей;

— появилась возможность создания динамических массивов с помощью конструктора Create;

— появились многочисленные изменения функционала IDE;

— строки типа AnsiString теперь хранят информацию о своей кодировке;

— улучшена совместимость с Delphi;

— добавлен встраиваемый редактор форм;

— добавлен анализ потоков данных (data flow analysis);

— улучшен механизм быстрых исправлений кода по сообщениям компилятора;

— улучшен перевод, в том числе и на русский язык;

— добавлены новые визуальные компоненты;

— добавлены новые свойства к некоторым визуальным компонентам;

— добавлены новые параметры запуска IDE;

— добавлен механизм настроек рабочего стола в IDE (Layout — конфигурации);

— добавлен новый уровень оптимизации -O4, при котором компилятор может переставлять поля в объектах классов, не вычислять неиспользуемые значения и ускорять работу с числами с плавающей точкой с возможной потерей точности;

— реализована поддержка в FPC: JVM / Dalvik, MS-DOS real mode, Android для ARM, x86 и MIPS, Haiku, Aros, Gameboy Advance;

— и многое другое.



С полным перечнем изменений можно ознакомиться:

http://wiki.lazarus.freepascal.org/Lazarus_1.6.0_release_notes

http://wiki.lazarus.freepascal.org/User_Changes_3.0



А также ознакомиться с перечнем исправлений в Lazarus можно тут:

http://wiki.lazarus.freepascal.org/Lazarus_1.6_fixes_branch



Поддержка платформы Windows 9x



Команда разработчиков Lazarus решила отказаться от поддержки платформы Windows 9x. С большой долей вероятности можно предположить, что релиз Lazarus 1.6 будет последним поддерживающим Windows 98 / Windows Me.

Как мы знаем, команда разработчиков Delphi уже давно отказалась поддерживать не только Windows 9x, но и Windows XP, таким образом, Lazarus до сих пор остаётся хорошей альтернативой из Pascal-подобных средств разработки, поддерживающих столь древние ОС.

image



Несколько полезных ссылок по теме



Примеры проектов с использованием Lazarus:

wiki.lazarus.freepascal.org/Projects_using_Lazarus

Примеры скриншотов приложений, созданных с использованием Lazarus:

wiki.lazarus.freepascal.org/Lazarus_Application_Gallery



WiKi — документация:

http://wiki.lazarus.freepascal.org/Main_Page/ru

Online — документация:

http://lazarus-ccr.sourceforge.net/docs/lcl/index.html



Скачать Lazarus:

https://sourceforge.net/projects/lazarus/files/



Хочется добавить, что команда разработчиков Lazarus действительно нас радует с каждым релизом. Lazarus уже сейчас обладает впечатляющим набором возможностей для разработки приложений. По моему субъективному мнению, к сожалению, в некоторых местах Lazarus не дотягивает до Delphi, но кое-где даже опережает его.

От всей души я желаю проекту Lazarus и компилятору Free Pascal дальнейших успехов и побед, я уверен, что все мы, разработчики на Lazarus и Delphi, от этого только выиграем.



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



Lazarus bugtracker:

http://bugs.freepascal.org/my_view_page.php



image



Всем удачи! Пусть этот новый релиз поможет нам создавать быстро и качественно новые проекты для различных ОС!



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/280704/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] RSA шифрование через библиотеку OpenSSL в Delphi

Понедельник, 28 Марта 2016 г. 10:42 (ссылка)





По долгу службы в разработчиках повстречалась задача шифровать текстовые строки алгоритмом RSA, используя публичный и секретный ключи в PEM формате. При изучении данного вопроса выбор пал на использование библиотеки OpenSSL. Хочу поделиться примерами реализации функционала шифрования на Delphi. Действия выполнялись в ОС Windows, среда разработки Borland Delphi 7.



С чего начать?



В первую очередь необходим пакет openssl, а точнее библиотека libeay32.dll. И для подключения библиотеки нам понадобится готовый юнит libeay32.pas, который необходимо подключить к проекту. В моем примере отсутствует функционал генерации ключей из проекта, как это сделать можно будет почитать в материале по ссылке снизу статьи. Для генерации пары ключей я использовал сам openssl следующими командами из cmd:



openssl genrsa 1024 > private.pem
openssl rsa -in private.pem -pubout > public.pem


Где 1024 является битностью ключа. Отмечу, что от битности ключа зависит и длина строки для шифрования. Если ключ 1024 бита, то зашифровать сможем всего 128 байт, тот самый размер, которому равен размеру ключа. Ниже покажу функцию, определяющие размер структуры RSA ключа. Но это не все. Данный буфер уменьшится на 11 байт, если во время шифрования указать параметр padding, отвечающего за выравнивания данных — PKCS#1.



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



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



Основные функции



Основное, что мы будем использовать для шифрования, — это:



Инициализация крипто функций


OpenSSL_add_all_algorithms;
OpenSSL_add_all_ciphers;
OpenSSL_add_all_digests;
ERR_load_crypto_strings;
ERR_load_RSA_strings;


Destroy



EVP_cleanup; 
ERR_free_strings;


Чтение ключей


//чтение секретного ключа в формате PEM, возвращает структуру RSA
//Где bp файл ключа, возвращаемый в RSA структуру указывающей x, cb – адрес функции запрашиваемая пароль к ключу.
function PEM_read_bio_PrivateKey(bp: pBIO; var x: pEVP_PKEY;
cb: TPWCallbackFunction; u: pointer): pEVP_PKEY; cdecl;

//чтение публичного ключа в формате PEM, возвращает структуру RSA
function PEM_read_bio_PUBKEY(bp: pBIO; var x: pEVP_PKEY;
cb: TPWCallbackFunction; u: pointer): pEVP_PKEY; cdecl;


И функции шифрации/дешифрации


//Шифрование/дешифрование flen размера буфера from в буфер _to используя структуру RSA ключа загруженного ранее в режиме выравнивания 
//данных padding. Получаем длину шифрованного/дешифрованного буфера или -1 при ошибке
//Шифрование публичным ключом
function RSA_public_encrypt(flen: integer; from: PCharacter; _to: PCharacter; rsa: pRSA; padding: integer): integer; cdecl;

//Шифрование секретным ключом
function RSA_private_encrypt(flen: integer; from: PCharacter; _to: PCharacter; rsa: pRSA; padding: integer): integer; cdecl;

//Дешифрование публичным ключом
function RSA_public_decrypt(flen: integer; from: PCharacter; _to: PCharacter; rsa: pRSA; padding: integer): integer; cdecl;

//Дешифрование секретным ключом
function RSA_private_decrypt(flen: integer; from: PCharacter; _to: PCharacter; rsa: pRSA; padding: integer): integer; cdecl;


Приступим к реализации



Итак, мы имеем сгенерированные ключи, dll-ка лежит в папке с проектом, liblea32.pas подключен в uses. Вызываем процедуры инициализации openssl:



procedure LoadSSL;
begin
OpenSSL_add_all_algorithms;
OpenSSL_add_all_ciphers;
OpenSSL_add_all_digests;
ERR_load_crypto_strings;
ERR_load_RSA_strings;
end;

procedure FreeSSL;
begin
EVP_cleanup;
ERR_free_strings;
end;


Пишем функции загрузки ключей.


KeyFile – пусть до ключа ('C:\key.pem'):



function LoadPublicKey(KeyFile: string) :pEVP_PKEY ;
var
mem: pBIO;
k: pEVP_PKEY;
begin
k:=nil;
mem := BIO_new(BIO_s_file()); //BIO типа файл
BIO_read_filename(mem, PAnsiChar(KeyFile)); // чтение файла ключа в BIO
try
result := PEM_read_bio_PUBKEY(mem, k, nil, nil); //преобразование BIO в структуру pEVP_PKEY, третий параметр указан nil, означает для ключа не нужно запрашивать пароль
finally
BIO_free_all(mem);
end;
end;

function LoadPrivateKey(KeyFile: string) :pEVP_PKEY;
var
mem: pBIO;
k: pEVP_PKEY;
begin
k := nil;
mem := BIO_new(BIO_s_file());
BIO_read_filename(mem, PAnsiChar(KeyFile));
try
result := PEM_read_bio_PrivateKey(mem, k, nil, nil);
finally
BIO_free_all(mem);
end;
end;


Вызов функций чтения ключей и обработка ошибок


var
FPublicKey: pEVP_PKEY;
FPrivateKey: pEVP_PKEY;
err: Cardinal;

FPublicKey := LoadPublicKey(‘C:\public.key’);
FPrivateKey := LoadPrivateKey(‘C:\private.key’);

//if FPrivateKey = nil then // если ключ не вернулся, то читаем ошибку
if FPublicKey = nil then
begin
err := ERR_get_error;
repeat
log.Lines.Add(string(ERR_error_string(err, nil)));
err := ERR_get_error;
until err = 0;
end;


Шифрование


var
rsa: pRSA; // структура RSA
size: Integer;
FCryptedBuffer: pointer; // Выходной буфер
b64, mem: pBIO;
str, data: AnsiString;
len, b64len: Integer;
penc64: PAnsiChar;
size: Integer;
err: Cardinal
begin
rsa := EVP_PKEY_get1_RSA(FPrivateKey); // Получение RSA структуры
EVP_PKEY_free(FPrivateKey); // Освобождение pEVP_PKEY
size := RSA_size(rsa); // Получение размера ключа
GetMem(FCryptedBuffer, size); // Определение размера выходящего буфера
str := AnsiString(‘Some text to encrypt’); // Строка для шифрования

//Шифрование
len := RSA_private_encrypt(Length(str), // Размер строки для шифрования
PAnsiChar(str), // Строка шифрования
FCryptedBuffer, // Выходной буфер
rsa, // Структура ключа
RSA_PKCS1_PADDING // Определение выравнивания
);

if len > 0 then // длина буфера после шифрования
begin
// полученный бинарный буфер преобразуем в человекоподобный base64
b64 := BIO_new(BIO_f_base64); // BIO типа base64
mem := BIO_push(b64, BIO_new(BIO_s_mem)); // Stream
try
BIO_write(mem, FCryptedBuffer, len); // Запись в Stream бинарного выходного буфера
BIO_flush(mem);
b64len := BIO_get_mem_data(mem, penc64); //получаем размер строки в base64
SetLength(data, b64len); // задаем размер выходному буферу
Move(penc64^, PAnsiChar(data)^, b64len); // Перечитываем в буфер data строку в base64
finally
BIO_free_all(mem);
end;
end
else
begin // читаем ошибку, если длина шифрованной строки -1
err := ERR_get_error;
repeat
log.Lines.Add(string(ERR_error_string(err, nil)));
err := ERR_get_error;
until err = 0;
end;
RSA_free(rsa);
end;


Дешифрование


var
rsa: pRSA;
out_: AnsiString;
str, data: PAnsiChar;
len, b64len: Integer;
penc64: PAnsiChar;
b64, mem, bio_out, bio: pBIO;
size: Integer;
err: Cardinal;
begin
//ACryptedData : string; // Строка в base64
rsa := EVP_PKEY_get1_RSA(FPublicKey);
size := RSA_size(rsa);
GetMem(data, size); // Определяем размер выходному буферу дешифрованной строки
GetMem(str, size); // Определяем размер шифрованному буферу после конвертации из base64

//Decode base64
b64 := BIO_new(BIO_f_base64);
mem := BIO_new_mem_buf(PAnsiChar(ACryptedData), Length(ACryptedData));
BIO_flush(mem);
mem := BIO_push(b64, mem);
BIO_read(mem, str , Length(ACryptedData)); // Получаем шифрованную строку в бинарном виде
BIO_free_all(mem);
// Дешифрование
len := RSA_public_decrypt(size, PAnsiChar(str), data, rsa, RSA_PKCS1_PADDING);
if len > 0 then
begin
// в буфер data данные расшифровываются с «мусором» в конца, поэтому очищаем, поэтому определяем размер переменной out_ и переписываем в нее нужное количество байт из data
SetLength(out_, len);
Move(data^, PAnsiChar(out_ )^, len);
end
else
begin // читаем ошибку, если длина шифрованной строки -1
err := ERR_get_error;
repeat
log.Lines.Add(string(ERR_error_string(err, nil)));
err := ERR_get_error;
until err = 0;
end;
end;


И заключении пример чтения ключа «зашитого» в приложение


var
mem, keybio: pBIO;
k: pEVP_PKEY;
keystring: AnsiString;
begin
keystring :=
'-----BEGIN RSA PRIVATE KEY-----' + #10 +
'MIICXgIBAAKBgQCfydli2u2kJfb2WetkOekjzQIg7bIuU7AzAlBUPuA72UYXWnQ/' + #10 +
'XcdSzEEMWSBLP7FO1vyVXR4Eb0/WqthF0ZViOK5bCN9CnR/1GMMiSqmIdByv/gUe' + #10 +
'Z/UjGrKmxeQOoa2Yt0MJC64cNXgnKmYC7ui3A12LlvNdBBEF3WpcDbv+PQIDAQAB' + #10 +
'AoGBAJnxukKHchSHjxthHmv9byRSyw42c0g20LcUL5g6y4Zdmi29s+moy/R1XOYs' + #10 +
'p/RXdNfkQI0WnWjgZScIij0Z4rSs39uh7eQ5qxK+NH3QIWeR2ZNIno9jAXPn2bkQ' + #10 +
'odS8FPzbZM9wHhpRvKW4FNPXqTc3ZkTcxi4zOwOdlECf9G+BAkEAzsJHgW1Isyac' + #10 +
'I61MDu2qjMUwOdOBYS8GwEBfi/vbn/duwZIBXG/BZ7Pn+cBwImfksEXwx0MTkgF3' + #10 +
'gyaChUSu+QJBAMXX3d94TwcF7lG9zkzc+AR/Onl4Z5UAb1GmUV57oYIFVgW1RIOk' + #10 +
'vqynXWrTjTOg9C9j+VEpBG67LcnkwU16JmUCQH7pukKz9kAhnw43PcycDmhCUgvs' + #10 +
'zCn/V8GCwiOHAZT7qLyhBrzazHj/cZFYknxMEZAyHk3x2n1w8Q9MACoVsuECQQDF' + #10 +
'U7cyara31IyM7vlS5JpjMdrKyPLXRKXDFFXYHQtLubLA4rlBbBHZ9txP7kzJj+G9' + #10 +
'WsOS1YxcPUlAM28xrYGZAkEArVKJHX4dF8UUtfvyv78muXJZNXTwmaaFy02xjtR5' + #10 +
'uXWT1QjVN2a6jv6AW7ukXiSoE/spgfvdoriMk2JSs88nUw==' + #10 +
'-----END RSA PRIVATE KEY-----' ;
k := nil;


keybio := BIO_new_mem_buf(Pchar(keystring), -1);
mem := BIO_new(BIO_s_mem());
BIO_read(mem, PAnsiChar(keystring), length(PAnsiChar(keystring)));
try
result := PEM_read_bio_PrivateKey(keybio, k, nil, nil);
finally
BIO_free_all(mem);
end;
end;


На этом мои примеры реализации заканчиваются. Исходники проекта доступны на Github.



Иточники:




Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/280302/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Эмуляция async/await в Delphi

Четверг, 10 Марта 2016 г. 17:34 (ссылка)

В C# появилась конструкция async/await. Далее показан вариант как добиться подобного поведения на Delphi.



Я предпологаю, что вы знакомы с async/await. Её удобно использовать для операций, где участие процессора не требуется. Процессор только начинает операцию, а из внешнего мира приходит сообщают об её окончании. Хорошим примером может служить вызов на веб сервер. Допустим наш веб сервер умеет выполнять две операции: сложение и умножение.

        async Task MakeAsyncTask_Plus(int aArg1, int aArg2, int aDurationMs)
{ // эмуляция вызова на веб сервер
await Task.Delay(aDurationMs);
return aArg1 + aArg2;
}
async Task MakeAsyncTask_Mult(int aArg1, int aArg2, int aDurationMs)
{ // эмуляция вызова на веб сервер
await Task.Delay(aDurationMs);
return aArg1 * aArg2;
}


Клиент хочет вычислить выражение (1+2)*(3+4). Т.к. результаты сложений независимы, их можно выполнять одновременно:

        async void CalcAsync()
{
Task aPlus1 = MakeAsyncTask_Plus(1, 2, 2000); // 1
Task aPlus2 = MakeAsyncTask_Plus(3, 4, 2000); // 2

int aArg1 = await aPlus1; // 3
int aArg2 = await aPlus2; // 4

Task aMult = MakeAsyncTask_Mult(aArg1, aArg2, 1000); // 5
int aRes = await aMult; // 6
Log(string.Format("{0} * {1} = {2}", aArg1, aArg2, aRes));
}


До строки "//3"(первого await) метод отрабатывает обычным образом. На await происходит выход из метода, а продолжится (до следующего await) по окончанию операции. Управление передастся механизмом сообщений или в другом потоке — настраивается в окружении. В C# это достигается возможностями компилятора. В Delphi похожего поведения на одном потоке можно достичь при помощи Fiber. Выглядеть подобный метод будет похоже:

procedure TCalcAsync.Execute;
var
aPlus1: TAsyncTask;
aPlus2: TAsyncTask;
aMult: TAsyncTask;
aArg1, aArg2: Integer;
aRes: Integer;
begin
aPlus1 := nil;
aPlus2 := nil;
aMult := nil;
try
aPlus1 := TAsyncTask_Plus.Create(Self, 1,{+}2, 2000{ms});
aPlus2 := TAsyncTask_Plus.Create(Self, 3,{+}4, 2000{ms});

aArg1 := aPlus1.Await;
aArg2 := aPlus2.Await;

aMult := TAsyncTask_Mult.Create(Self, aArg1,{*}aArg2, 1000{ms});
aRes := aMult.Await;
Example.Log('%d * %d = %d', [aArg1, aArg2, aRes]);
finally
aMult.Free;
aPlus2.Free;
aPlus1.Free;
end;
end;


Пример работает для Delphi 2007, XE2, XE8.



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/278985/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Delphi: Простая задачка RichEdit которую нужно решить до того как вы решитесь его использовать

Понедельник, 15 Февраля 2016 г. 10:35 (ссылка)


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

И тут я нашел небольшие такие грабельки :-)



Итак вопрос:

Есть редактор RichEdit в который мы ввели текст:



Курсор стоит вначале строки перед "9", RichText.SelStart := 12



Как узнать символ на котором стоит курсор?



Если ваш опыт подсказывает конструкцию наподобие:

   with RichEdit do
textChar:=Text [SelStart];


— то ваш опыт не верен!



И если вам интересно — то правильный ответ можно увидеть под катом…



Читать дальше →

https://habrahabr.ru/post/277223/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как не стать программистом или… тебе здесь не место

Понедельник, 18 Января 2016 г. 15:04 (ссылка)


ПРОЛОГ



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

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

Так что, если ты в процессе самоопределения по данной профессии — you are welcome!

Читать дальше →

http://habrahabr.ru/post/275409/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Релиз компонентов DevExpress .NET, HTML5/JS и VCL v2015.2

Среда, 30 Декабря 2015 г. 15:46 (ссылка)


Всем привет!



2015-й год близится к своему завершению и мы хотим пожелать всем разработчикам России (да и всего мира, чего уж!) весёлого новогоднего настроения, гармонии во всех ваших делах, ну и чтобы всё, что у вас ещё не получилось сделать до сих пор — обязательно получилось бы в следующем году!



А вот у нас, например, ещё в этом году получилось выпустить новую версию компонентов для .NET, HTML/JavaScript и VCL, и если вы используете наши продукты в своей работе и следите за их развитием, то добро пожаловать под кат.







Читать дальше →

http://habrahabr.ru/post/274275/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<delphi - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda