» Создание своего инсталлятора на NSIS. Деинсталлятор

K.A.V.
www.oszone.net
22.02.2010
Автор: hb860
Последнее обновление: 22.02.2010


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

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

В NSIS деинсталлятор создается очень просто, всего одной командой:
WriteUninstaller "$OUTDIR\uninst.exe"


Я обычно создаю деинсталлятор в секции, отвечающей за копирование основных файлов приложения.
Section "${PRODUCT_NAME}" SEC01
SectionIn 1 2 RO

WriteUninstaller "$OUTDIR\uninst.exe"
...
SectionEnd


Помимо этого, надо как-то сообщить пользователю о наличии у программы деинсталлятора. Не лазить же за ним в папку установки приложения, далеко не каждому придет это в голову. Логично создать на него ярлыки в меню "Пуск" и создать запись в апплете установки и удаления программ в панели управления Windows.

Первое реализуется командой CreateShortCut.
 CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Удалить ${PRODUCT_NAME}.lnk" "$OUTDIR\uninst.exe"


Параметры команды таковы:
CreateShortCut link.lnk target.file [parameters icon.file icon_index_number start_options keyboard_shortcut description]


Всё, что в квадратных скобках, задавать необязательно.

Итак,
link.lnk — путь и имя файла-ярлыка
target.file — на что, собственно, ярлык
parameters — параметры командной строки для target.file
icon.file — файл со значком для ярлыка
icon_index_number — порядковый номер иконки, полезно, если в icon.file их несколько
start_options — вид окна при запуске ярлыка, принимает вот такие значения
SW_SHOWNORMAL — обычное окно,
SW_SHOWMAXIMIZED — развернутое на весь экран,
SW_SHOWMINIMIZED — свернутое на панель задач.
keyboard_shortcut — сочетание клавиш для быстрого вызова ярлыка
description — всплывающая подсказка для ярлыка

В моем примере создается ярлык "Пуск-Программы-Моя программа-Удалить Моя программа.lnk", при условии, что ${PRODUCT_NAME} = Моя программа. Значок деинсталлятора берется из файла uninst.exe.

Обратите внимание, что для ярлыка, создаваемая командой CreateShortCut, рабочая папка берется из переменной $OUTDIR, которая устанавливается командой SetOutPath.
SetOutPath "$INSTDIR"


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

С ярлыками закончили, теперь пропишем деинсталлятор в «Установку и удаление программ».
Сначала немного теории. Всё, что мы видим в этом апплете (а также кое-что из того, что не видим), находится в реестре, по адресу HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

Как правило, необходимо и достаточно создать ключ в этой ветке, и два значения:
DisplayName, строка, со значением, равным названию приложения.
UninstallString, строка, со значением, равным пути к программе-деинсталлятору.
Помимо этих двух значений, в реестре могут быть прописаны ряд других, подробней об том написано на Wiki NSIS.

Используем для записи в реестр функцию WriteRegStr.
Пример:
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyProgram "DisplayName" "${PRODUCT_NAME}"


Как несложно догадаться, она создает строковое значение по указанному пути в реестре.
Первый параметр — корневой ключ, у нас это HKLM
Второй параметр — субключ, где будет создан параметр
Третий — это имя параметра, у нас это DisplayName
Ну и, соответственно, последний параметр функции - это непосредственно значение DisplayName.

Прописываем примерно следующее:
 WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyProgram "DisplayName" "${PRODUCT_NAME}"
WriteRegStr HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyProgram "UninstallString" "$OUTDIR\uninst.exe"


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

Но вот беда, он ничего не делает. Вообще ничего, потому что его надо запрограммировать.

Это также несложно. Действия деинсталлятора задаются специальной секцией.
Section Uninstall
SectionEnd 


Всё, что написано в этой секции, будет выполнено при запуске деинсталлятора.
Типовой пример такой секции:
Section Uninstall secidx01
DeleteRegKey HKLM "Software\MyApp"

RMDir /r "$INSTDIR"

SetShellVarContext all
RMDir /r "$SMPROGRAMS\MyApp"
Delete "$Desktop\${PRODUCT_NAME}.lnk" 

DeleteRegKey HKLMSOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\MyApp
SectionEnd


Данный пример:


Для организации взаимодействия с пользователем «современный» интерфейс NSIS предоставляет схожие с инсталлятором средства. Имеется возможность задать страницы мастера удаления программы. Их несколько:


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

Необходимо командой InstType определить варианты удаления программы, только перед названием варианта следует задать префикс «un.». Вот так:
InstType "un.Полное удаление ${PRODUCT_NAME}"


Тоже самое и для секций:
Section "Un.Удалить папку данных"
Section "Un.Удалить настройки реестра"


Посмотрим, как всё работает на примере скрипта, устанавливающего Mail.ru Агент.
!define PRODUCT_NAME "Mail.ru Агент"
!define PRODUCT_VERSION "5.5.2842"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define Branding "By Happy Bulldozer860"
!define pkgdir "d:\package"

; MUI 1.67 compatible ------
!include "MUI.nsh"
SetCompressor /SOLID lzma
; MUI Settings
!define MUI_COMPONENTSPAGE_NODESC 
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
;;;;;
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_COMPONENTS
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_UNPAGE_FINISH

; Language files
!insertmacro MUI_LANGUAGE "Russian"

; MUI end ------
Name "${PRODUCT_NAME}"
Caption "${PRODUCT_NAME} ${PRODUCT_VERSION}"
UninstallCaption "Удаление ${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "${PRODUCT_NAME}-${PRODUCT_VERSION}.exe"
InstallDir "$PROGRAMFILES\Mail.ru\Agent"
BrandingText "${Branding}"
ShowInstDetails show
ShowUnInstDetails show
InstType "Полная"
InstType "Сокращенная"
InstType "un.Полное удаление ${PRODUCT_NAME}"
Section "${PRODUCT_NAME}" SEC01
SectionIn 1 2 RO
SetAutoClose true
SetOutPath "$INSTDIR"
File /r "${pkgdir}\agent\*.*"

WriteRegDWORD HKCU "Software\Mail.Ru\Agent" "set_mrasearch" 0
WriteRegStr HKCU "Software\Mail.Ru\Agent" "lang" "ru" 
WriteRegDWORD HKCU "Software\Mail.Ru\Agent" "SavedInstSettings" 286261249
;;;;
WriteRegDWORD HKLM "Software\Mail.Ru\Agent" "ForAllUsers" 1
WriteRegDWORD HKLM "Software\Mail.Ru\Agent" "version" 2842
WriteRegStr HKLM "Software\Mail.Ru\Agent" "InstallPath" "$OUTDIR" 

CreateDirectory "$APPDATA\Mra\Update"

SetShellVarContext all
CreateDirectory "$SMPROGRAMS\Mail.ru"
CreateShortCut "$SMPROGRAMS\Mail.ru\${PRODUCT_NAME}.lnk" "$OUTDIR\magent.exe"
WriteUninstaller "$OUTDIR\uninst.exe"
CreateShortCut "$SMPROGRAMS\Mail.ru\Удалить ${PRODUCT_NAME}.lnk" "$OUTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$OUTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
SectionEnd

Section /o "Ярлык на рабочем столе"
SectionIn 1
CreateShortCut "$Desktop\${PRODUCT_NAME}.lnk" "$INSTDIR\magent.exe"
SectionEnd


Section Uninstall secidx01
SectionIn 1 RO
DeleteRegKey HKLM "Software\Mail.Ru\Agent"

RMDir /r "$INSTDIR"

SetShellVarContext all
RMDir /r "$SMPROGRAMS\Mail.ru"
Delete "$Desktop\${PRODUCT_NAME}.lnk" 
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
SetAutoClose true
SectionEnd


Section "Un.Удалить папку данных"
SectionIn 1
SetShellVarContext current
RMDir /r "$APPDATA\Mra\" 
SectionEnd

Section "Un.Удалить настройки реестра"
SectionIn 1
SetShellVarContext current
DeleteRegKey HKCU "Software\Mail.Ru\Agent"
SectionEnd


Function un.onInit
SectionSetText ${secidx01} "Удалить приложение"
FunctionEnd


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

Деинсталлятор предоставляет возможность удаления различных компонентов.

Обратите внимание, что секция Uninstall переименовывается функцией un.onInit. Эта функция отрабатывает до появления окна деинсталлятора, и задает заголовок для секции с идентификатором ${secidx01}, для этой: Section Uninstall secidx01.

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