13 июня 2011

ImageEn – кто не успел, тот опоздал

   Год назад компания HiComponents сделала бесплатной свою библиотеку компонент для работы с картинками – ImageEn. Исходные коды, хоть и было обещано, выложены не были, но любой желающий, после несложной регистрации, мог скачать новую версию библиотеки (3.12), скомпилированную под любую версию Delphi и C++Builder и насладиться её мощным функционалом бесплатно.
   Но теперь халява закончилась. Права на ImageEn переданы новозеландской компании Xequte Software и библиотека снова стала платной. Вот такой поворот в условиях лицензии. Взглянув на список продуктов компании (сплошь утилиты для работы с картинками, видео и музыкой), становится очевидной причина смены хозяина. Предполагаю, что для разработки многих продуктов компании используется ImageEn и, после того как ее автор (итальянец Fabrizio) утратил к библиотеке коммерческий интерес, ей просто не дали умереть.
   По заявлению представителя компании Xequte Software они планируют развивать библиотеку и даже задумываются над 64-х битной версией, а над исходными кодами ImageEn по-прежнему трудится Fabrizio.
   Со сменой хозяина и лицензии изменились и цены. У Xequte Software лицензия на исходные коды ImageEn и подписка на их бесплатное 12-ти месячное обновление стоит 299.50$ (на одного разработчика). Эта цена почти вдвое больше, чем у HiComponents (175$)! А лицензия на скомпилированную версию ImageEn не продается(у HiComponents она стоила 59$), но её владельцы могут приобрести новую версию по сниженной цене – за 249.50$.
   Если Xequte Software снова не выложит бесплатно скомпилированную версию ImageEn, то тот, кто не успел её скачать, попал на деньги.

15 апреля 2011

FastReport. Вывод данных в внизу страницы

   Недавно коллега обратился с вопросом "Как в FastReport сделать так, чтобы бэнд с данными выводился внизу страницы?".
   Первая моя мысль была положить SubReport на PageFooter. Но такое решение естественно не сработало, и я стал пробовать управлять положением бэнда на странице с помощью скрипта. В результате я нашел решение данного вопроса с помощью дополнительного бэнда и одной строчки скрипта. Поясню на примере.
   Например, вверху отчета нам нужно вывести какую-то информацию (добавляем на страницу бэнд MasterData1) и внизу отчета нам нужно вывести какую-то информацию (добавляем на страницу бэнд MasterData2). А между ними положим еще один бэнд (MasterData3), который заполнит пространство между MasterData1 и MasterData2. Его не будем подключать к данным, а просто укажем количество строк RowCount = 1.
   В скрипте, при старте отчета зададим размер MasterData3:

MasterData3.Height := Engine.PageHeight - MasterData1.Height * MasterData1.RowCount – MasterData2.Height * MasterData2.RowCount

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

16 февраля 2011

Object Pascal для Java и Android

   На прошедшей в Лас-Вегасе конференции Developer Solutions Conference, компания RemObjects Software впервые представила свой новый проект – "Cooper". Cooper – это новый компилятор языка RemObjects Oxygene для платформ Java и Android (RemObjects Oxygene – это реализация языка Object Pascal для .NET и Mono, третья версия которого была выпущена как Embarcadero Delphi Prism). Cooper подключает стандартные библиотеки Java-классов и создает 100% байт-код для виртуальных машин Java и Dalvik (Dalvik – виртуальная машина Java для Android).
   В ролике показано, как под Mac-OS в командной строке скомпилировали паскалевский код консольной программы и калькулятора, использующего swing-контролы, а затем запустили полученные jar-файлы.

   Планируется интеграция Cooper в Visual Studio и MonoDevelop (аналогично с компилятором для .NET). Обещают выпустить это чудо уже в этом году.

13 февраля 2011

Сохранение в базу данных отчета FastReport в формате PDF

   Недавно пришлось писать DLL, одна из функций которой должна была:
1. сформировать отчет в FastReport;
2. экспортировать отчет в файл PDF-формата и сохранить его в базе данных;
3. возвратить идентификатор сохраненного в базе данных файла.
Предположим, что исходная структура таблицы для хранения файла в базе данных была такая (MS SQLServer 2000):
CREATE TABLE X.FILES (
  ID BIGINT IDENTITY NOT NULL,
  FILE_BODY IMAGE NULL,
  CONSTRAINT PK_FILES PRIMARY KEY (ID)),
где FILE_BODY – это поле, в которое сохраняется файл, а ID – идентификатор файла.
   Для начала я создал процедуру, которая будет вставлять файл в базу данных и возвращать идентификатор вставленного файла.
CREATE PROCEDURE X.InsertFile
 @FILE image,
 @ID bigint OUTPUT
AS
 INSERT INTO X.FILES(FILE_BODY) VALUES(@FILE)
 SET @ID = SCOPE_IDENTITY()
GO
   Потом сел писать код DLL. В Delphi вся работа с файлами реализована с помощью потоков, поэтому я немного удивился, когда оказалось, что метод Export у TfrxReport экспортирует отчет только в файл (честно сказать, я ожидал увидеть, что-то в стиле ExportToStream). Т.е. вместо прямой передачи отчета через поток в базу данных, необходимо было сначала сохранить отчет во временный файл, а потом этот файл загрузить в базу данных. Мне это не понравилось, т.к. файловые операции (сначала записи, потом чтения) должны были хоть немного, но тормозить работу. Но нужно было срочно отдать DLL, поэтому я не стал разбираться с экспортом и сделал через файл:

...
 db: TSDDatabase; // база данных SQLDirect
 spInsertFile: TSDStoredProc; // вызов X.InsertFile
 frxReport: TfrxReport;
 frxPDFExport: TfrxPDFExport;
...

Function GetDoc(const sDotName: String; ...): Integer;
begin
 Result := -1;
 // загружаем шаблон отчета
 If frxReport.LoadFromFile(sDotName)
  then begin
   // устанавливаем параметры отчета
   ...
   If frxReport.PrepareReport
    then try
     // получаем имя временного файла
     frxPDFExport.FileName := GetTempFileName;
     Try
      // экспортируем отчет во временный файл
      frxReport.Export(frxPDFExport);
      // загружаем PDF-файл в параметр процедуры
      // из временного файла
      spInsertFile.Params[1].LoadFromFile(frxPDFExport.FileName, ftBlob);
     Except
      on E: Exception do
       WriteErrorMessage(E.Message);
     End;
     // сохраняем PDF-файл в базу данных
     Try
      db.StartTransaction;
      spInsertFile.ExecProc;
      db.Commit;
      Result := spInsertFile.Params[2].AsInteger;
     Except
      on E: ESDEngineError do
       begin
        db.Rollback;
        WriteErrorMessage(E.Message);
       end;
     End;
    Finally
     // удаляем временный файл
     DeleteFile(frxPDFExport.FileName)
    End
    else WriteErrorMessage('Ошибка подготовки отчета')
  end
  else WriteErrorMessage('Файл шаблона не найден')
end;

   После передачи DLL другому программисту, мысли о лишних файловых операциях при сохранении отчета в базу через временный файл, не давала мне покоя. Вечером, не найдя решения в документации по FastReport, я, прежде чем смотреть исходный код экспорта, решил еще раз пройтись по методам и свойствам экспорта. Глаз сразу же зацепился за свойство Stream. Я создал для этого свойства поток и метод Export у TfrxReport выгрузил отчет не в файл, а в поток.

Function GetDoc(const sDotName: String; ...): Integer;
begin
 Result := -1;
 // загружаем шаблон отчета
 If frxReport.LoadFromFile(sDotName)
  then begin
   // устанавливаем параметры отчета
   ...
   If frxReport.PrepareReport
    then begin
     Try
      Try
       // создаём поток в памяти
       frxPDFExport.Stream := TMemoryStream.Create;
       // экспортируем отчет в поток
       frxReport.Export(frxPDFExport);
       // загружаем PDF-файл в параметр процедуры
       // из потока в памяти
       spInsertFile.Params[1].LoadFromStream(frxPDFExport.Stream, ftBlob);
      Except
       on E: Exception do
        WriteErrorMessage(E.Message);
      End;
     Finally
      frxPDFExport.Stream.Free;
     End;
     // сохраняем PDF-файл в базу данных
     Try
      db.StartTransaction;
      spInsertFile.ExecProc;
      db.Commit;
      Result := spInsertFile.Params[2].AsInteger;
     Except
      on E: ESDEngineError do
       begin
        db.Rollback;
        WriteErrorMessage(E.Message);
       end;
     End;
    end
    else WriteErrorMessage('Ошибка подготовки отчета')
  end
  else WriteErrorMessage('Файл шаблона не найден')
end;

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

30 января 2011

Часть антивируса Касперского написана на Delphi

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

Ссылки по теме:
1. Кому выгодно раскручивать тему утечки кодов из Лаборатории Касперского?
2. Kaspersky Anti-Virus Source Code Leaks online

28 января 2011

Delphi и C++Builder Starter Edition

   По информации SD Times, Embarcadero Technologies собирается продавать новую редакцию Delphi и C++Builder – Starter Edition. Эта редакция будет включать: полноценную IDE с 32-разрядным компилятором, отладчик и библиотеку визуальных компонент (VCL), содержащую сотни компонент для создания пользовательского интерфейса (от стандартных Windows-контролов до контролов в стиле Office Ribbon и touch-интерфейса) и работы с различными Internet протоколами и стандартами. До публикации обновленного "Delphi Feature Matrix" трудно, что то понять о функциональных возможностях новой редакции, но по короткому описанию она очень напоминает Professional Edition.

25 января 2011

Интернет на халяву

   Сегодня заменил свой старый ADSL-модем на новенький с Wi-Fi. Кроме моей точки доступа ноутбук сразу нашел ещё четыре. Одна из них была помечена, как "Unsecured wireless network". Проверив работу своей точки доступа, я отключил её и проверил "соседскую". Через "соседскую" я без проблем вышел в интернет, открыл для тестирования пару сайтов и отключился. Предположим, что на моём месте оказался бы другой любопытный, но менее честный человек. Что тогда? В лучшем случае, он потихоньку приворовывал бы трафик бороздя просторы интернета, а в худшем - забил бы весь чужой канал каким-нибудь торрентом (если там модем без шейпера).
   "Граждане, храните деньги в сберегательной кассе!", - сказал Жорж Милославский, герой всенародно любимого кинофильма "Иван Васильевич меняет профессию", запихивая в карман пухлую пачку денег, похищенную из квартиры доктора Шпака. Так и я таким же поучительным тоном скажу: "Граждане, защитите свою беспроводную сеть! Хотя бы ограничьте подключения к вашей точке доступа по MAC-адресу устройств".

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