СТАТЬЯ

15.10.01


Предыдущая часть

Профессиональная разработка приложений с помощью Delphi 5

Часть 3. Оформление приложений для Windows95/98/NT/2000 в Delphi

Сергей Трепалин,
УКЦ Interface Ltd.
КомпьютерПресс #3 2001

Статья была опубликована в КомпьютерПресс (www.cpress.ru)

Информация о версии

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

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

Главный смысл контроля версии: любой файл, содержащий код (исполняемый файл или динамически загружаемая библиотека), содержит в ресурсах информацию о версии, которая понятна Windows. Это четыре числа, например 1.0.0.0 или 1.1.0.2. Чем больше эти числа, тем новее версия, причем чем левее стоит число, тем больший у него приоритет при определении версии. Перед копированием такого файла на диск проверяется, существует ли файл с таким именем. В случае положительного ответа сравниваются эти числа в уже существующем и новом файле. Если оказывается, что существующий файл имеет ту же самую или более новую версию, копирование не выполняется. Если же существующий файл имеет более раннюю версию, то старый файл переписывается новым с дистрибутива. Некоторые инсталляционные приложения требуют подтверждения копирования у пользователя и в конце инсталляции дают ему список замененных файлов.

Имеется ряд функций Windows API, которые позволяют выполнять манипуляции с файлами с учетом их версий. Например, VerInstallFile копирует и распаковывает файл только в том случае, если у пользователя отсутствует файл с более новой версией. Обычно программисту не требуется вызывать эти методы, поскольку их вызов осуществляется автоматически в инсталляционных программах типа InstallShield. Но если программист сам создает инсталляционное приложение, то без вызова этих методов ему не обойтись.

Для внесения информации о версии в открытом проекте необходимо вызвать команду меню Project/Options и в появляющемся диалоге выбрать закладку Version Info. Для добавления информации о версии необходимо отметить опцию Include Version Information in project.

Если на данном компьютере имеется поддержка русского языка, то по умолчанию ставится значение Language=$0419 (Русский). Это, в принципе неправильно, поскольку такая информация о версии может быть прочитана только русской версией Windows. Однако очень многие пользователи имеют английскую версию Windows c поддержкой русского языка. Если приложение не представляет собой какую-либо только национальную специфику, в нем обязательно должна быть включена информация о версии на английском языке (Language=$0409).

Значения всех флагов и элементов управления в этом диалоге очевидны и не требуют дальнейших пояснений. Некоторые затруднения вызывает заполнение текстовых полей. Их значение следующее:

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

var
   ThisVerComments,ThisVerCompanyName,
   ThisVerFileDescription,ThisVerFileVersion,ThisVerInternalName,
   ThisVerLegalCopyright,ThisVerLegalTrademarks,ThisVerOriginalFilename,
   ThisVerProductVersion,ThisVerProductName,ThisVerSpecialBuild,
   ThisVerPrivateBuild:string;
   ThisVerFixedFileInfo:TVSFixedFileInfo;

procedure InitializeVersion;
var
VSize:integer;
   VHandle:DWORD;
   VData:pointer;
   PC:pointer;
   Len:UINT;
   C:array[0..1000] of char;
begin
VData:=nil;
   ThisVerComments:='';
   ThisVerCompanyName:='';
   ThisVerFileDescription:='';
   ThisVerFileVersion:='';
   ThisVerInternalName:='';
   ThisVerLegalCopyright:='';
   ThisVerLegalTrademarks:='';
   ThisVerOriginalFilename:='';
   ThisVerProductVersion:='';
   ThisVerProductName:='';
   ThisVerSpecialBuild:='';
   ThisVerPrivateBuild:='';
{Reading This product version from resource}
   GetModuleFileName(HInstance,C,1000);
   VSize:=GetFileVersionInfoSize(C,VHandle);
   if VSize>0 then begin
        GetMem(VData,VSize);
     if GetFileVersionInfo(C,VHandle,VSize,VData) then begin
       if VerQueryValue(VData,'\StringFileInfo\040904E4\Comments',PC,Len)
          then ThisVerComments:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\CompanyName',PC,Len)
          then ThisVerCompanyName:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\FileDescription',PC,Len)
          then ThisVerFileDescription:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\FileVersion',PC,Len)
          then ThisVerFileVersion:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\InternalName',PC,Len)
          then ThisVerInternalName:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\LegalCopyright',PC,Len)
          then ThisVerLegalCopyright:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\LegalTrademarks',PC,Len)
          then ThisVerLegalTrademarks:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\OriginalFilename',PC,Len)
          then ThisVerOriginalFilename:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\ProductVersion',PC,Len)
          then ThisVerProductVersion:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\ProductName',PC,Len)
          then ThisVerProductName:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\SpecialBuild',PC,Len)
          then ThisVerSpecialBuild:=StrPas(PC);
       if VerQueryValue(VData,'\StringFileInfo\040904E4\PrivateBuild',PC,Len)
          then ThisVerPrivateBuild:=StrPas(PC);
       if VerQueryValue(VData,'\',PC,Len)
          then ThisVerFixedFileInfo:=PVSFixedFileInfo(PC)^;
   end;
end;

Настраиваемые опции проекта

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

Поэтому для всех форм, кроме главной и немодальных, которые будут показываться в единственном экземпляре, флаг Auto Created должен быть убран. Для этого их необходимо перенести в список Available. Соответственно их конструктор и деструктор должны быть вызваны динамически. Поэтому вместо одной строчки кода:

Form2.ShowModal;

которая используется для показа модального диалога формы с флагом Auto Created, потребуется написать следующий код:

Form2:=nil;
try
   Form2:=TForm2.Create(Self);
   Form2.ShowModal;
finally
   if Assigned(Form2) then Form2.Release;
end;

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

В опциях проекта необходимо также определить имя и путь файла справки (Application/Help File). Ясно, что если указать имя файла с путем, то пользователь должен будет ставить приложение в фиксированный каталог, чего допускать нельзя. В случае же отсутствия пути в имени файла WinHelp осуществляет поиск файла помощи в текущем каталоге. При этом если текущий каталог не совпадает с каталогом, в котором находится *.hlp-файл, то WinHelp объявляет о его отсутствии. Поэтому не рекомендуется указывать имя файла справки при разработке проекта. Вместо этого выполняется следующая последовательность действий:

Application.HelpFile:=ExtractFilePath(ParamStr(0))+’myhelp.hlp’;

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

Заключение

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

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

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Отправить ссылку на страницу по e-mail
Обсудить на форуме Inprise/Borland


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 15.10.01