Инсталлятор на ассемблере
АрхивПрограммазм (архив)Создание простого установщика на ассемблере
В одной из статей я рассматривал создание программы-установщика (setup.exe) с помощью программы InstallShield. Да, даже Express-версия программы InstallShield позволяет за сравнительно небольшое время создать гибкую программу установки. При использовании InstallShield вам потребуется больше времени для обмозгования состава каждой программной группы, чем на создание самого установщика.
Но что делать, если нам нужно написать простой установщик для нашей небольшой программы? Нам не нужны различные типы установки (Typical, Compact или Custom), наша программа не использует BDE, у нас есть всего лишь три файла: сама программа, файл данных и файл справки. Целесообразно ли использовать для этой цели InstallShield? Я думаю, что нет.
Для установки небольших программ можно воспользоваться установочными файлами Windows. Вы когда-нибудь устанавливали драйвер для устройства? Для добавления нового устройства мастер определения устройств запрашивает INF-файл, в котором находятся все сведения о драйвере: наименование устройства, его тип, версия драйвера, необходимые файлы и информация, которую нужно добавить в реестр Windows. Мы можем написать такой же INF-файл, который установит нашу программу. На создание этого файла вам потребуется несколько минут, тем более, что вы можете воспользоваться приведенным ниже примером – только подставить свои значения.
Установочные INF-файлы (сведения для установки) очень похожи на INI-файлы. Они состоят из секций, в которых описаны действия, которые нужно выполнить при установке и удалении программы, а также список файлов, подлежащих установке.
Итак, начнем по порядку. Для определенности скажем, что нам нужно установить программу base.exe в каталог C:\Program Files\Base, скопировать файлы base.hlp и base.txt в каталог C:\Program Files\Base\Help, создать для программы программную группу в меню Windows, а также поместить сведения о программе в реестр Windows, чтобы ее можно было удалить стандартными средствами Windows. Разумеется, названия каталогов можно будет изменить.
Для начала определим тип установки (он у нас будет один – базовый). Создайте файл base.inf (имя файла не обязательно должно совпадать с именем программы – я использовал имена base.exe и base.inf для наглядности) и добавьте в него следующие строки :
; Установочный inf-файл [Version] Signature="$CHICAGO$" SetupClass=BASE ; Константы [Strings] ; Название программы и имя ярлыка BASE="BASE Program" ; Корневой установочный каталог BASEDIR="Progra~1\Base" ; Подкаталог каталога %BASEDIR% для файлов справки HELPDIR="Help" ; Ключ реестра для удаления программы REGKEY="Software\Microsoft\Windows\CurrentVersion\Uninstall\Base" ; Ключ для раздела Software SOFTKEY="Software\DHSI Labs\Base" ; Описание программы DESC="Demonstration program" ; Название компании. DHSILabs="DHSI Labs"
В секции Version мы определяем подпись и класс установки – "$CHICAGO$" и BASE соответственно. Вам ничего не здесь не надо изменять. Во второй секции Strings мы определяем константы, которые будут доступны во всем INF-файле. Вот здесь вам будет что изменить. Все эти переменные мы будем использовать во всем INF-файле. Секция Strings является зарезервированной и она не может называться по-другому. Данная секция необязательно должна находится в начале файла – вы можете написать ее хоть в середине, хоть в конце.
Далее определим число установочных дисков, их названия, а также список файлов:
; Названия исходных дисков. Нам нужен только один диск. [SourceDisksNames] 1=%BASE%,"",1 ; Файлы на дисках [SourceDisksFiles] base.exe=1 base.hlp=1 base.txt=1
Название диска пользователь увидит, когда установщик запросит установить другой диск. Мы названия дисков не использовали (обычно пишут Disk #1, .., Disk #N, но у нас всего один диск), поэтому пользователь увидит только название программы (%BASE%):
Вы же можете написать так (если у вас два или более дисков):
[SourceDisksNames] 1=%BASE%,"Disk 1",1 2=%BASE%,"Disk 2",2
Примечание. Должен отметить, что секция SourceDisksFiles необязательна (в случае, если один диск установочный диск, но весьма желательна – так система сразу узнает, какого файла не хватает).
Обычно картину, изображенную на рисунке 1, пользователь вообще не должен увидеть, если у вас всего лишь один диск. Чтобы сфотографировать это окно, мне пришлось удалить файл base.txt, который запрашивает программа.
Теперь определим группы установки. Она у нас всего лишь одна – DefaultInstall (Типичная установка):
; Группы установки [Optional Components] DefaultInstall
Само собой разумеется, теперь мы должны описать действия, которые нужно выполнить для установки нашей программы – ведь Windows еще не до такой степени умный, чтобы читать наши мысли:
; Типичная установка [DefaultInstall] CopyFiles=Main.Files, Help.Files, Inf.Files AddReg=Base.Registry UpdateInis=Groups.Add OptionDesc=%BASE% Tip=%DESC% Parent=AccessTop InstallType=10 IconIndex=16 Uninstall=DefaultUninstall
Мы говорим установщику, чтобы тот установил (CopyFile) группы файлов Main.Files, Help.Files и Inf.Files. Также мы его просим, чтобы он добавил в реестр информацию Base.Registry и создал программную группу Groups.Add ("DHSI Labs") в меню Пуск, Программы.
Сразу, чтобы не забыть, опишем действия для удаления программы. Что мы сделали? Скопировали файлы, добавили группы и информацию в реестр. Значит, для деинсталляции все это нужно удалить, о чем мы сообщаем установщику в секции DefaultUninstall:
[DefaultUninstall] DelFiles=Main.Files, Help.Files DelReg=Base.Registry UpdateInis=Groups.Del
Мы сообщили установщику, что мы хотим установить группы Main.Files (содержит наш exe-файл), Help.Files (файлы base.hlp и base.txt) и Inf.Files (base.inf). Для чего нам нужно устанавливать INF-файл? Для того, чтобы Windows знала, какие действия нужно выполнить для удаления программы. Ведь она же должна прочитать секцию DefaultUnInstall, а откуда она ее прочитает, если мы не установим INF-файл?
Вернемся к нашему установщику: он знает, какие группы файлов нужно установить, но не знает куда именно (:) ). Мы забыли указать каталоги-назначения. Исправимся:
; Каталоги [DestinationDirs] Main.Files=24,%BASEDIR% Help.Files=24,%BASEDIR%\%HELPDIR% Inf.Files=17
Группа Main.Files будет установлена в каталог %BASEDIR% (C:\Program Files\Base), группа Help.Files – в %BASEDIR%\%HELPDIR% (C:\Program Files\Base\Help), а INF-файл нужно установить в каталог <WINDIR>\INF (обычно C:\WINDOWS\INF). Все системные каталоги WINDOWS пронумерованы: 17 – это каталог INF, 18 – HELP, 10 – WINDIR и так далее.
Следующая степень уточнения – это непосредственно указание файлов, которые входят в группы Main.Files, Help.Files и Inf.Files:
[Main.Files] base.exe [Help.Files] base.hlp base.txt [Inf.Files] base.inf
Обратите внимание, что имена групп файлов должны совпадать с названиями секций. То же самое касается и информации о добавлении информации в реестр.
Теперь конкретизируем информацию, которую мы хотим добавить в реестр:
; Добавленная к реестру информация
[Base.Registry]
HKLM,%REGKEY%,,,
HKLM,%REGKEY%,DisplayName,,%BASE%
; C:\WINDOWS\rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 4 C:\WINDOWS\INF\base.inf
HKLM,%REGKEY%,UninstallString,,"%10%\rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 4 %17%\base.inf"
HKCU,%SOFTKEY%,,,
HKCU,%SOFTKEY%,Config,,
Сначала мы добавляем %REGKEY% в HKLM (HKEY_LOCAL_MACHINE), а затем %SOFTKEY% в HKCU (HKEY_CURRENT_USER). Строка
HKLM,%REGKEY%,UninstallString,,"%10%\rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 4 %17%\base.inf"
будет заменена на строку:
C:\WINDOWS\rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 4 C:\WINDOWS\INF\base.inf
Команда InstallHinfSection указывает, какую секцию файла %17%\base.inf" нужно прочитать для удаления программы – DefaultUninstall.
Добавленная в реестр информация будет использована не только для удаления программы, но и для ее отображения в списке установленных программ:
Теперь опишем действия для создания программной группы DHSI Labs и ее удаления: [Groups.Add]
setup.ini, progman.groups,,"groupx=%DHSILABS%"
setup.ini, groupx,,"%BASE%,""%24%\Progra~1\Base\base.exe"",,,,""%24%\Progra~1\Base\"",%DESC%"
[Groups.Del]
setup.ini, progman.groups,,"groupx=%DHSILABS%"
setup.ini, groupx,,"%BASE%
Будет создана группа DHSI Labs и ярлык BASE Program (%BASE%). Путь – ""%24%\Progra~1\Base\base.exe"", рабочий каталог ""%24%\Progra~1\Base\"", описание %DESC%".
Вот и все. Если бы не одно НО: действием по умолчанию для INF-файлов является их редактирование в блокноте. Для установки нужно щелкнуть на файле правой кнопкой мыши и выбрать команду «Установить». Попробуйте объяснить это пользователю, который всю жизнь привык запускать SETUP.EXE.
Нам нужно написать этот самый SETUP.EXE, который запускал бы установку программы. Это можно сделать на Delphi (или CBuilde или с помощью любого другого языка), но тогда проще использовать InastallShield – простейшая программа на Delphi будет весить около 300К. Получается, что цель не оправдывает средства. Вот сейчас нам и понадобится тот самый Ассемблер, который фигурирует в названии статьи. Вам лень писать две сотни строк для запуска функции API на ассемблере? Вы ошибаетесь, не 200, а всего лишь 18, не учитывая пустых строк:
ideal p386n model flat, stdcall O equ <offset> procdesc ShellExecuteA :dword, :dword, :dword, :dword, :dword, :dword procdesc ExitProcess :dword dataseg szAction db 'install', 0 szFilename db 'base.inf', 0 codeseg proc WinMain xor edi, edi call ShellExecuteA, edi, O szAction, O szFilename, edi, edi, edi call ExitProcess, edi ret endp end WinMain
Текст программы настолько прозрачен, что не нуждается в объяснении. Но кроме этого файла нам потребуются еще несколько: файл ресурса (RC), файл определений (DEF) и Makefile, в котором описываются действия по сборке программы. Вы можете не использовать Makefile, а выполнить находящиеся в нем команды вручную, но с Makefil'ом намного удобнее.
Сначала создадим файл ресурса (install.rc):
101 ICON DISCARDABLE "base.ico" 1 VERSIONINFO LOADONCALL MOVEABLE FILEVERSION 4, 0, 0, 0 PRODUCTVERSION 4, 0, 0, 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "DHSI Labs\0" VALUE "FileDescription", "BASE Installation Program\0" VALUE "FileVersion", "1.0\0" VALUE "Final Release", "Oct.13 2002\0" VALUE "InternalName", "BaseInstall\0" VALUE "Language", "English (United States)\0" VALUE "OriginalFilename", "INSTALL.EXE\0" VALUE "ProductName", "BASE Program\0" VALUE "ProductVersion", "1.0\0" END END END
Думаю, что особо объяснять, что и к чему, не стоит – просто замените нужные вам параметры. Файл install.def:
NAME INSTALL DESCRIPTION 'BASE Installation Program' CODE PRELOAD FIXED NONDISCARDABLE EXECUTEONLY NONCONFORMING DATA PRELOAD MOVEABLE SINGLE EXETYPE WINDOWS HEAPSIZE 65536 STACKSIZE 65536
Последний файл – install.mk (или просто Makefile):
!if $d(MAKEDIR)
IM=$(MAKEDIR)\..\lib\import32
!else
IM=import32
!endif
install.exe: install.obj install.res
tlink32 /x /Tpe /aa /c /V4.0 install.obj, , , $(IM), install.def, install.res
erase install.obj
erase install.res
install.obj: install.asm
tasm32 /m /ml /q install.asm
install.res: install.rc
brc32 -r install.rc
Для сборки всего этого вам необходим tasm32 (Borland TASM5). Для сборки перейдите в каталог, в котором расположены все файлы и введите:
make install.mk
или просто
make
если вы создали файл с именем Makefile, а не install.mk.
В итоге получился файл INSTALL.EXE весом в 6 144 (6 Кб!). Если вы напишите такой же маленький файл на Delphi или CBuilder, я умываю руки.
Вы можете задать вполне правомерный вопрос: при создании инсталлятора с помощью InstallShield все установочные файлы упаковываются, как поступить здесь? А кто вам мешает создать ZIP-файл, распаковать его с помощью Asm (выполнить еще одну команду – запуск unzip) и потом уже устанавливать программу? Конечно, если ваша программа не умещается на одной дискете даже в архиве, возникнут определенные трудности, но тогда вы уже находитесь за рамками поставленной задачи – нам нужно создать инсталлятор для маленькой программы. Можно, конечно, и BDE установить, используя приведенный принцип, но стоит ли?