14.10.2011

О нумерации версий Delphi


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

   Пятничные размышления, на которые натолкнуло письмо одного моего приятеля.
   Сначала разработчики Delphi нумеровали версии просто: 1, 2, 3, 4, 5, 6, 7, 8. Затем, с подачи маркетологов Microsoft перешли на нумерацию версий по годам: 2005, 2006, 2007, 2009, 2010. В 2010 году Embarcadero придумала для всех своих продуктов новый бренд - "XE". "XE" - это не "Express Edition" как у Oracle, а два понятия: "X" - гетерогенность платформы (например, доступ к различным базам данных без дополнительных затрат) и "E" - скромное "Embarcadero". Поэтому с 2010 года началась новая эра в нумерации версий Delphi: Delphi XE, Delphi XE2... Что будет дальше? А дальше:
  • Delphi XE3
  • Delphi XE4
  • Delphi XE5
  • Delphi XE6
  • Delphi XE7
  • Delphi XE8
  • Delphi XE9
  • Delphi XEA
  • Delphi XEB
  • Delphi XEC
  • Delphi XED
  • Delphi XEE
 О, XEE! Легкой перестановкой букв мы получаем название первой версии Delphi - "Delphi.EXE". Круг замкнулся... :)

15.09.2011

Конвертирование XLS/XLSX/XLSM в XLSB

   С появлением MS Excel 2007 на смену привычного XLS-файла пришли сразу три формата:
  • XLSX - стандартный формат файлов Excel 2007-2010 на основе XML;
  • XLSM - формат Excel 2007-2010 на основе XML с поддержкой макросов (в отличие от XLSX он позволяет сохранять код макросов MS Visual Basic для приложений (VBA) и листы макросов MS Excel 4.0 (XLM));
  • XLSB - формат двоичных файлов Excel 2007-2010 (BIFF12).
Наиболее интересным из них является формат XLSB - Excel Binary Workbook. В отличие от других форматов Excel 2007-2010, он хранит данные не в виде XML, а является двоичным. Это дает существенные преимущества при работе с большими таблицами, т.к. бинарные файлы занимают меньше места на диске и читаются/записываются быстрее.
   Ни одна из библиотек для работы с файлами Excel в Delphi не поддерживает XLSB-формат. Например, XLSReadWrite поддерживает только XLSX, а авторы TMS FlexCel вообще не могут сказать, когда у них будет поддержка формата Excel 2007 и будет ли вообще. Поэтому, что бы конвертировать файлы Excel в XLSB-формат необходимо использовать OLE:

Var
  xls: OleVariant;
...
Const
  // formats in Excel 2007-2010
  xlExcel12 = 50; // XLSB
  xlOpenXMLWorkbook = 51; // XLSX
  xlOpenXMLWorkbookMacroEnabled = 52; // XLSM
  xlExcel8 = 56; // XLS (export to Excel 97-2003)
...

Procedure XYZ.ConvertFilesToXLSB(slFiles: TStringList);
Var
  iFile: Integer;
begin
  Try
    Try
      xls := CreateOleObject('Excel.Application');
      xls.DisplayAlerts := False;
      If StrToFloat(StringReplace(xls.Version, '.', DecimalSeparator, [])) < 12
        then WriteToLog('Error! Requires Excel 2007/2010')
        else for iFile := 0 to slFiles.Count-1 do
                ConvertToXLSB(slFiles[iFile]);
    Finally
      xls.Quit;
      xls := UnAssigned;
    End;
  Except
    on E: Exception do
      WriteToLog(E.Message);
  End;
end;

Где ConvertToXLSB:

Procedure XYZ.ConvertToXLSB(sFileName: String);
Var
  sFileNameTo: String;
begin
  sFileName := ExpandFileName(sFileName);
  sFileNameTo := ChangeFileExt(sFileName, '.xlsb');
  Try
    Try
      xls.Workbooks.Open(sFileName);
      xls.ActiveWorkbook.SaveAs(Filename := sFileNameTo, FileFormat := xlExcel12);
    Finally
      xls.Workbooks.Close;
    End;
  Except
    on E: Exception do
      WriteToLog(E.Message);
  End;
end;

   Думаю, что код простой и комментировать нечего. Остановлюсь только на строке проверки версии MS Excel. xls.Version возвращает номер версии MS Excel в виде строки, где цифры разделены точкой (например, "11.0" для Excel 2003, "12.0" для Excel 2007...), поэтому, чтобы получить номер версии в виде числа его необходимо преобразовать следующим способом:

StrToFloat(StringReplace(xls.Version, '.', DecimalSeparator, []))

18.07.2011

Проверка корректности адреса электронной почты

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

Function ValidateMail(const sAddress: String): Boolean;
Var
  clEV: TclEmailValidator;
begin
  clEV := TclEmailValidator.Create(nil);
  Try
    clEV.ValidationLevel := vlMailbox;
    clEV.DnsServer := '8.8.8.8';
    Result := clEV.Validate(sAddress) = vrMailboxOk
  Finally
     clEV.Free;
  End;
end;

Я задал всего лишь два свойства clEmailValidator (остальные можно пропустить). Первое и основное, это ValidationLevel - метод (уровень) проверки правильности адреса, их пять:
  1. vlBlacklist - проверка на вхождение адреса в ваш "чёрный список" (чёрный список хранится у clEmailValidator в свойстве BlackList типа TStrings);
  2. vlSyntax - проверка синтаксиса (проверяется при помощи шаблона RegEx);
  3. vlDomain - проверка существования домена (проверяется запросом DNS-информации для почтового домена);
  4. vlSmtp - проверка доступности почтового сервера (проверяется попыткой установления SMTP-соединения с хостом, указанным в MX-записи DNS);
  5. vlMailbox - проверка существования почтового ящика (проверяется попыткой отправить SMTP-запрос почтовому серверу с указанием проверяемого адреса в поле "RCPT TO").
   Я расположил эти значения в списке по очереди (в порядке) выполнения. Т.е. если вы хотите проверить существование домена, то clEmailValidator выполнит проверки нижнего уровня - сначала на вхождение в чёрный список, потом проверку синтаксиса адреса, а уж затем проверку существования домена.
   Проверка корректности с уровнем vlDomain и выше требует активного internet-подключения и у clEmailValidator необходимо задать значение свойству DnsServer. DnsServer - это IP-адрес name-сервера вашего internet-провайдера. В примере выше я использовал адрес Google Public DNS.
   При желании для уровня vlSmtp (и выше) можно задать имя которое используется в команде "SMTP HELO" (свойство HostName). А для уровня vlMailbox можно задать еще и адрес электронной почты, который используется в SMTP-запросе свойство EmailFrom). Я написал "при желании", т.к. у меня проверка корректности работает и без них.
   Метод Validate возвращает уровень, до которого проверка адреса электронной почты выполнилась корректно (vrBlacklistOk, vrSyntaxOk, vrDomainOk, vrSmtpOk, vrMailboxOk) или, если вы совсем ерунду подсунули clEmailValidator, то "vrInvalid".

06.07.2011

Описание у службы Windows

   При написании очередной службы для MS Windows, меня посетила мысль: "А почему у TService нет свойства "Description"?". При этом из своего опыта знаю, что подобное свойство есть у аналогичных компонент: у TNtService из библиотеки SvCom и даже у бесплатной компоненты TDDService от Arno Garrels, а у стандартного TService его нет даже под Delphi XE. Я понимаю, что описание - это не важно, но служба без описания выглядит на фоне других как-то неполноценно.
   Метода для установки описания у TService я не нашел, поэтому ничего другого не оставалось, как добавить описание службе самому.
   Оказалось, у MS Windows для этого есть специальная функция - ChangeServiceConfig2 (в advapi32.dll), которая изменяет дополнительные параметры конфигурации службы. Вместо реализации вызова ChangeServiceConfig2 на Delphi я сделал проще – в событии TService.ServiceAfterInstall записал описание службы напрямую в реестр:

procedure TxyzSvc.ServiceAfterInstall(Sender: TService);
begin
  With TRegistry.Create(KEY_READ or KEY_WRITE) do
    Try
      RootKey := HKEY_LOCAL_MACHINE;
      If OpenKey('\SYSTEM\CurrentControlSet\Services\' + Name, False) then
        begin
          WriteString('Description', 'XYZ Service');
          CloseKey;
        end;
    Finally
      Free;
    End;
end;

13.06.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, то тот, кто не успел её скачать, попал на деньги.