NSIS: продолжение установки после перезагрузки.

Преамбула

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

Изначально я хотел обойтись параметрами командной строки, добавляемыми при запуске установщика, но с ними произошла жопа, поэтому будем действовать более надежными методами.

Алгоритм

0. Проверяем наличие уникального ключа Реестра, сигнализирующего о том, что надо выполнить вторую часть установки (после перезагрузки):

DetailPrint "Read After Reboot flag..."
ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"
StrCmp "$R0" "1" AfterReboot

1. Производим все действия, которые необходимо произвести до перезагрузки (устанавливаем драйвера, регистрируем DLL и т.д.)
2. Записываем в однократную автозагрузку (ключ Реестра RunOnce) наш инсталлятор, путь к exe файлу инсталлятора, который можно взять из переменной $EXEPATH.
Автозагрузку прописываем для текущего пользователя (пользователя, запустившего установщик), т.е. в ключ HKEY_CURRENT_USER.

WriteRegStr HKCU
"Software\Microsoft\Windows\CurrentVersion\RunOnce"
"${APPNAME}" "$EXEPATH"

Примечание: В RunOnce могут записаться программы, которые требуется выполнить однократно при загрузке системы. После выполнения программ, ключ RunOnce очищается автоматически, что отличает его от ключа Run, где данные не очищаются, и его можно использовать, как постоянную автозагрузку.

3. Устанавливаем уникальный флаг, по которому будем определять, что инсталлятор был запущен после перезагрузки, например, таким образом:

DetailPrint "Write After Reboot flag..."
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot" "1"

4. Выдаем запрос на немедленную перезагрузку:

DetailPrint "Reboot request."
MessageBox MB_YESNO|MB_ICONINFORMATION
"Installation will be cobntinue after reboot. Press OK to reboot now." IDYES RebootID

Если пользователь ответил «Yes«, сразу перезагружаемся:

	RebootID:
		DetailPrint "Rebooting..."
		Reboot

Если нет, ждем перезагрузки вручную:

DetailPrint "Installation continue if user restart system."
Goto SecEnd

5. После перезагрузки удаляем флаг (проверив его наличие, см выше):
DetailPrint "Delete After Reboot flag..."
DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\"
"${APPNAME}_afterreboot"

6. И продолжаем установку…
DetailPrint "Continue install after reboot..."

Скриншоты



Исходник примера

На GitHub

Глюк в NSIS: проверка параметров командной строки инсталлятора не работает

Вот серьезно, бьюсь (головой об стену) уже третий день, ну не работает функция GetOptions, так, как заявлено в NSIS Wiki, уже и по колесам стучал, и фары протирал, в смысле просто тупо копировал код из примера в тестовый инсталлятор, и еще десяток написал, перепробовав все что можно и нельзя, ну не выходит каменный цветок, хоть тресни. Функция в любом случае выдает, либо что никаких ошибок не случилось, для следующего кода, соответственно, всегда получается found:

Section
	${GetOptions} "/S /T" "/T"  $R0
 
	IfErrors 0 +2
	MessageBox MB_OK "Not found" IDOK +2
	MessageBox MB_OK "Found"
SectionEnd

Либо, для следующего кода всегда остается значение по умолчанию, даже если в командной строке явно задано иное:

Section
	${GetOptions} "/AR=N" "/AR=" $R0
	DetailPrint "R0: $R0"
	
SectionEnd

Например, выполняешь TestInstaller.exe /AR=Y, все равно в переменной $R0 оказывается N

Такие дела.

Переопределение вывода на другой терминал в Linux

Преамбула

Пришли сегодня ко мне с одной задачкой, мол есть у нас программка, которая висит в фоне и периодически выводит данные в консоль. Неудобно оператору работать, либо что-то другое делать, либо ничего не делать, лишь в консоль смотреть. Даже отдельный комп думаем программке выделить, чтоб она на нем крутилась-вертелась. И нельзя ли так сделать, чтоб программку на другом терминале запустить, чтоб можно было по Ctrl+Alt+F[номер] переключаться, и за состоянием программки смотреть?

Вот запустить нельзя, без особого бубна, а вывод переопределить, всегда пожалуйста.

Решение

Можно пользуясь стандартным перенаправлением ввода-вывода в Linux, заставить программу или скрипт отправлять сообщения на другой терминал. Пусть программка будет называться tscript. За терминалы в Linux отвечают устройства /dev/tty*, например, /dev/tty2 отвечает за терминал, вызываемый по Ctrl+Alt+F2.
Например, чтобы программа переопределяла вывод на /dev/tty2, запускаем ее таким образом:

tscript >/dev/tty2

Можно отправить на другой терминал только вывод сообщений об ошибках:

tscript 2>/dev/tty2

Чтобы программа работала в фоне, а на том терминале, с которого мы ее запустили, можно было продолжить работу, добавляем после команды знак &:

./tscript >/dev/tty2 &

Пример

Пишем тестовый скрипт, который, скажем, будет бесконечно выводить на консоль случайное шестнадцатиричное число раз в секунду:

#!/bin/bash

SEC=1

echo "Test script, write to STDOUT random number after $SEC sec."

while [ 1 -eq 1 ];do
    sleep $SEC
    printf 'Number: %x\n' $RANDOM
done

Пишем скрипт, который будет убивать тестовый:

#!/bin/bash
echo "Kill test script..."
pkill tscript

Пишем запускающий скрипт, в котором вывод тестового скрипта переопределяется на терминал tty2:

#!/bin/bash
TERMNO=2
echo "Send tscript output to terminal #$TERMNO"
./tscript >/dev/tty$TERMNO &

Пример работы

Запускаем тестовый скрипт на текущем терминале:

Выполняем запускающий скрипт:


Состояние tty1


Вывод на tty2

Исходники примера

На GitHub

NSIS: Совсем коротко про секции

Преамбула

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

Отображение секций и выбор компонентов

Для самого простого выбора компонентов в NSIS, необходимо вставить в скрипт, перед, собственно, описанием секции, следующий код:

ComponentText "Какой-то текст", например:

ComponentText "Choose which features of ${APPNAMEANDVERSION} you want to install."

Естественно, ${APPNAMEANDVERSION} должна быть заранее определена:

!define APPNAME "SectionsExample"
!define APPNAMEANDVERSION " SectionsExample 0.1"


Окно инсталлятора с выбором компонентов

Простая секция

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

Section
	DetailPrint "Hello, world!"	
SectionEnd


Примечание: После конструкции Section идет имя секции, заключенное в кавычки. Если кавычки пропустить, то имя секции будет некорректным, и неверно отобразится в окне выбора компонентов. Попробуйте вставить следующий код в пример, и посмотрите, как он будет работать. Ссылка на пример в конце заметки.

Section Component 4

	; Wrong section description
	SetOverwrite on
	
	DetailPrint "Component #4 installing..."
	
SectionEnd

Основные компоненты. Блокируем возможность снятия checkbox’а (галочки) пользователем

Для чего? Например, у нас есть программа, у которой, в свою очередь есть основные компоненты, например экзешник и DLL, а также дополнительные, которые можно устанавливать, а можно и не устанавливать. И если уж пользователь хочет поставить наше приложение, то он должен установить хотя бы основные компоненты.

Для того, чтобы заблокировать чекбокс, прописываем в начале секции конструкцию:

SectionIn RO

Section "Main Program and components"

	; Checkbox select and disable user changes
	SectionIn RO
	SetOverwrite on
	
	DetailPrint "Main program installing..."
	
SectionEnd

Чекбокс (галочка) выбранный по умолчанию

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

Section "Component #2"

	; Checkbox enabled by default & user will change it state
	SetOverwrite on
	
	DetailPrint "Component #2 installing..."
	
SectionEnd

Сделать, чтобы галочка была снята по умолчанию

Наверное, самый частый вопрос, задаваемый, что в рунете, что в Интернете вообще, по поводу NSIS. Так вот, ларчик открывается просто. Достаточно после Section поставить специальный флаг /o.

Пользователь также сможет активировать checkbox (галочку), если ему нужно будет установить данный компонент.

Section /o "Component #3"

	; Checkbox disabled by default & user will change it state
	SetOverwrite on
	
	DetailPrint "Component #3 installing..."
	
SectionEnd

Скрытые секции

Такие секции не будут отображены в окне выбора компонентов. Их названия пишутся без кавычек и без пробела, а перед названием ставится знак «-«. Код в таких секциях будет выполнен в любом случае, независимо от желания пользователя:

Section -HiddenSection
	DetailPrint "This is a hidden section"
	DetailPrint "This code running anyway."
SectionEnd

Специальные секции

К ним, наверное, относится одна — Uninstall, ну и еще не совсем секция, а встроенная функция, которую можно переопределить, дописав свой код, т.е. что-то типа обработчика событий в «больших» языках, например в C#

О секции Uninstall и рассказывать особо не надо, кроме ремарки, что в секции Uninstall «забываются» все значения глобальных переменных и значение переменной $INSTDIR

Исходник примера с секциями

На GitHub

IPInformer v 0.2.0

Наконец-то руки дошли прикрутить инсталлер и выложить 🙂

Программа предназначена для отображения внешнего IP-адреса компьютера, определения географической принадлежности IP-адреса, а также того, не попадает ли IP-адрес в список «запрещенных» стран.

Программа получает IP-адрес, из поставляемого с ней PHP-скрипта, размещенного на Web-сервере в Интернете, и/или (в текущей версии) с сайтов, которые информируют пользователя о его внешнем IP. В текущей версии не все такие сайты подходят (сайт не должен быть заскриптован, не требовать обязательного использования cookie и не выдавать капчу), а оригинальный скрипт PHP предоставляет некоторые дополнительные возможности.

Далее, программа получает из базы данных SxGeo сведения о геопозиции, и, если настроено и IP-адрес попал в стоп-лист стран, выводит предупреждение о попадании в данный список.

Свежую версию БД SxGeo можно бесплатно скачать с сайта разработчиков базы данных: https://sypexgeo.net/ru/download/

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

Изначально писалась по заказу одного активиста, у которого была проблема с периодическим отключением от VPN, в связи с чем, случайно мог «засветиться» его IP, или VPN мог переключить его на нежелательную страну.

По умолчанию программа запускается в «портативном» режиме (все данные хранятся в подкаталоге data каталога с исполняемым файлом)

Системные требования

Microsoft Windows XP и выше (Vista/7/8/8.1/10), .NET Framework 2.0 и выше, 512 Мб оперативной памяти, 15 Мб на жестком диске.

Дополнительные компоненты

В качестве контрола для ввода IP-адреса мы использовали C# IP Address Control вот этого автора:

https://www.codeproject.com/Articles/9352/A-C-IP-Address-Control

База данных SypexGeo (SxGeo):
© 2006-2018 zapimir
© 2006-2018 BINOVATOR

https://sypexgeo.net

Скриншоты

Получение нового IP

Остальные под катом

История версий

0.0.1 b, 19/01/2010 — Первая версия, написанная для товарища OPPosition
0.1.2 08/08/2018 — Исправлен код запросов и конфигов, многое переделано
0.2.0 01/07/2019 — Программа «отвязана» от скрипта с SxGeo на сервере, интерфейс к БД SxGeo перенесен внутрь программы, запросы к БД обрабатываются локально, добавлена поддержка других источников IP-адресов. Первая публичная версия.

Скачать

Портабельная версия
Инсталлятор

Исходники

Репозиторий на GitHub