пятница, 14 ноября 2014 г.

Обновление своего ПО из Интернет без... программирования

Любой разработчик программного обеспечения (ПО) рано или поздно сталкивается с необходимостью автоматизации обновления устаревших версий своих программ, чаще всего через сеть Интернет. Как правило, при этом решаются следующие задачи: определение уже запущенной версии программы, поиск новой версии на удаленном файлохранилище, скачивание архива с новой версией, распаковка архива, завершение работы уже работающего приложения и запуск новой версии. Сегодня настало время уделить немножко внимания данной проблеме. Нет, мы не будем программировать в обычном понимании этого слова, а всего лишь воспользуемся обычным блокнотом и алгоритмизируем все вышеописанное простым скриптовым языком или пакетным, например BATCH*-файлом.

Вы можете спросить: «...в чем резон хранить обновления в виде архива?». Во-первых – экономия места на хостинге и трафика, как вашего, так и клиента (пользователя вашего ПО), во-вторых – удобство при работе с множеством файлов, которые необходимо обновить. Согласитесь, гораздо проще запаковать все в один архив, слить его на файлохранилище и поручить распаковку кучи ресурсов программе или скрипту, чем делать это вручную.

К слову, все таки программа или скрипт а-ля пакетный файл? Ряд разработчиков идут двумя путями: как разработка отдельного исполняемого файла или сервиса обновления (как то корпоративные версии программ или те же антивирусы), так и в виде скриптов автообновления. Мы выбрали второй вариант как более гибкий. Гибкий в плане модификации набора выполняемого функционала (ведь всегда можно расширить набор обновляемых файлов, скорректировать пути и прочее) и нет необходимости запускать каждый раз IDE (среду компиляции), вся работа идет в обычном блокноте (да-да, Notepad). Конечно, разработчик сервиса автообновления в виде исполняемого файла может предусмотреть внешний конфиг, файл настроек, но всего, увы, не предусмотришь. Да и, как правило, современные антивирусы часто «трубят» (дают ложные срабатывания) в случае автообновления исполняемых файлов, с пакетными же файлами или скриптами это случается реже. Таким образом, наиболее логичным и простым, с нашей точки зрения, является использование пакетных или командных файлов. Для этого не потребуются знания программирования и языков. Лишь основы работы со старым добрым DOS.
* Пакетный файл (англ. batch file) – текстовый файл в MS-DOS (имеет расширение *.BAT), OS/2 или Windows (*.CMD, впрочем, поддерживает и *.BAT), содержащий последовательность команд, предназначенных для исполнения командным интерпретатором. По сути,  пакетный файл – аналог скриптовых файлов командной строки (shell script) в Unix-подобных операционных системах / Справка.
Описание алгоритма...

Распишем пошагово все необходимые магические действия для совершения ритуала омоложения обновления:
  1. Необходимо создать временную директорию (допустим 'update') для скачивания последней версии (обновления) программы в архиве (пусть будет иметь имя 'update.zip').
  2. В исключения встроенного файрволла ОС добавляем утилиту для доступа сетевым архивам.
  3. Производим скачивание архива по заданному адресу с сервера в заданный каталог.
  4. Распаковываем полученный архив во временную директорию.
  5. Сканируем список процессов в системе и среди полученного списка ищем работающую версию "старой" программы в текущем каталоге.
  6. Закрываем процесс "старой" версии программы по имени.
  7. Из временной директории в текущий каталог перемещаем "новую" версию программы.
  8. Производим удаление временной директории с авто-подтверждением удаления.
  9. Производим запуск обновленной версии программы …как ни в чем не бывало :)
Предпосылки реализации ПО

Итак. Прежде всего, нам понадобится:
  1. Консольная системная утилита 'ftp.exe' (для скачивания файлов по протоколу FTP, входит в состав ОС Windows) или 'httpget.exe' (для скачивания файлов по протоколу HTTP, см. ресурсы к материалу [1]).
  2. Свободный консольный распаковщик архивов UnZip под лицензией Gnu32 под ОС MS DOS/Windows http://gnuwin32.sourceforge.net/downlinks/unzip-bin-zip.php.
Рассмотрим параметры запуска консольной утилиты FTP. Подведите мышь к кнопке "Пуск", выберите пункт меню "выполнить" и в появившемся окне наберите CMD, нажмите ENTER. В окне командной строки наберите (см. рисунок):
ftp -h

Рис. Параметры запуска консольной утилиты FTP

Далее для открытия соединения с заданным адресом наберите:
o [address host]
и по клавише ENTER введите последовательно login и password. После чего вы уже можете обмениваться файлами. К примеру, для загрузки файлов на FTP используется команда SEND, синтаксис ее вызова следующий:
send [путь к файлу] [имя]
Для скачивания файлов с FTP используется команда GET, синтаксис ее вызова следующий:
GET [путь к скачиваемому файлу] [путь к локальному сохранению файла]
То есть, в первую очередь, необходимо указать, какой файл с FTP сервера нужно скачать, а затем указываем путь, где файл будет сохранен на вашем компьютере и с каким именем он будет сохранен. Проверить наличие файла можно классической DOS-овской командой DIR для текущего каталога, а удалить просто DELETE. Для перемещения MOVE, создания директории MKDIR.

В принципе использование FTP не совсем приемлемо для нашей задачи. Почему? Есть пара нюансов. Для скачивания архивов конечно  можно использовать публичный FTP, но в ряде случаев это будет невозможно,  обусловлено это тем, что: протокол может оказаться заблокированным на уровне внутреннего прокси организации пользователя вашей программы или, скажем, вы используете FTP сервер с обязательной авторизацией, параметры доступа к которому вам не хотелось бы открывать широкой общественности, или хостинг-план вашего провайдера не предусматривает доступ по FTP. А вот доступ к Интернету в виде обычных сайтов по протоколу HTTP, так или иначе, открыт в любой организации. Посему воспользуемся второй утилитой, но уже для работы по протоколу HTTP – 'HTTPGET'.

Рассмотрим параметры ее запуска (см. рисунок):
httpget –h

Рис. Параметры запуска утилиты HTTPGET

Как видим, имеются всего два параметра:
  1. Полный путь к скачиваемому файлу.
  2. Путь для сохранения файла.
Теперь рассмотрим параметры запуска распаковщика UnZip. В командной строке наберите:
unzip –h

Рис. Параметры запуска утилиты UnZip

Получим:
unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]
Из всех параметров (см. рисунок выше) нам важны два флага: "o-" – путь к архиву,  "d-" – путь к каталогу распаковки обновления. Теперь приступим к практике…

Используем командные файлы

Создадим в блокноте текстовый файл со следующим содержимым (см. листинг 1).

ЛИСТИНГ-1
REM Update.bat
REM Батник обновления программы из Интернета
REM
REM При запуске:
REM 1. Создается временная директория для закачки свежей версии программы в архиве
REM 2. Производится скачивание архива (обновления) по заданному адресу
REM 3. Архив распаковывается во временную директорию
REM 4. В процессах ищется запущенная версия "старой" программы и убивается
REM 5. Из временной директории в текущую перемещается "новая" версия программы
REM 6. Временная директория удаляется с автоподтверждением
REM 7. Прозводится запуск обновленной версии программы
REM
REM Разработчик: Бадло Сергей Григорьевич
REM H-page: http://raxp.radioliga.com
REM Ограничения: Win OS + запуск батника самой программой, которая хочет себя обновить

@echo off

В реальном приложении убрать этот первый запуск старой программы
echo Test run old program...
start raxp_sockets.exe

mkdir update

REM добавляем в исключения HTTPGET
netsh firewall add allowedprogram httpget.exe ENABLE

echo Downloading Update...
httpget http://raxp.radioliga.com/update/update.zip update\update.zip

echo Unpacking update.zip...
unzip -o update\update.zip -d update

echo Kill old program...
set ProcessName="raxp_sockets.exe"
TaskList /FI "ImageName EQ %ProcessName%" | Find /I %ProcessName%
REM Задержка через пинг, в реальном убрать (введена для видеоролика)
ping 0 -n 7
taskkill /f /im %ProcessName%

echo Moving New to Old...
move /Y update\raxp_sockets.exe

echo Delete Update Directory...
rmdir update /S /Q

echo Run New program...
start raxp_sockets.exe
И сохраним его под именем <update.bat>. Некоторые нововведения нуждаются в дополнительном пояснении:
  1. Для добавления нашей утилиты в исключения файрволла была использована системная утилита 'Netsh.exe' [2]. Netsh – мощная и полезная утилита командной строки, предназначенная для обновления и настройки параметров сети ОС Windows. Параметры командной строки 'firewall add allowedprogram'  создают дополнительное правило в текущие настройки файрволла Windows и добавляют имя программы в исключения.
  2. Для получения списка загруженных процессов использована системная утилита 'TaskList.exe' [3].
  3. Для закрытия заданного процесса использована системная утилита 'Taskkill.exe' [4] с параметрами '/f /im ', позволяющие задать в качестве идентификатора не ID процесса, а имя.
Проведем натурные испытания

Итак, для тестов в каталоге с текущим скриптом обновления мы положили файл 'raxp_sockets.exe', выполняющим роль "старой" версии программы. При запуске скрипта будем имитировать ее работу перед выполнением основного рабочего цикла. На удаленный сервер по адресу http://raxp.radioliga.com/update/update.zip загрузим "обновление" этой программы в архиве. Произведем запуск скрипта обновления (см. рисунок).

Рис. Тестирование работы скрипта автообновления. Запуск обновленной версии

В дальнейшем вам необходимо закомментировать ее старт. Видеотестирование всего процесса вы можете посмотреть на нашем канале LaboratoryW:


Результат впечатляет. Как видите, вполне можно обойтись командными (пакетными) файлами без единого гвоздя IDE.

Запуск Batch- файла как службы

Следует отметить, что ничто не мешает нам запустить наш командный файл как службу, которая будет выполнять автообновление по заданному условию. В ОС Windows для создания службы можно воспользоваться системными утилитами 'Sc.exe' или ' Instsrv.exe' и 'Srvany.exe' (параметры запуска см. подробнее [5…7]). Дополнительно потребуется создать ключ в реестре в ветке 'HKLM\SYSTEM\CurrentControlSet\Services' с произвольным именем службы, назовем ее, скажем, "Radiolybitel_Service", с ключом 'Parameters' и значением '/f /v Application /t REG_SZ /d "%src%'. Все операции нужно проводить в режиме повышенных прав. После чего достаточно стартовать службу. Реализация подобного подхода представлена в листинге 2.

ЛИСТИНГ-2
REM Запуск Batch- файла как службы
@echo off
REM Абсолютный путь к запускаемому batch-файлу как службы
set src=с:\update\update.bat

sc create My_Service binPath= %windir%\SysWOW64\srvany.exe DisplayName= "Radiolybitel_Service"
reg add ЄAatControlSet\Services\Radiolybitel_Service\Parameters" /f /v Application /t REG_SZ /d "%src%"
net start "Radiolybitel_Service"
pause
Для остановки службы создайте в блокноте batch-файл следующего содержания:
@echo off
net stop "Radiolybitel_Service"
Для удаления службы:
sc delete "Radiolybitel_Service"
pause
Обратите внимание! Поскольку в ОС Windows XP/Vista/8 утилита 'Srvany.exe' отсутствует, то перед созданием службы ее необходимо скопировать в системную папку 'System32'. В 64-х битных ОС для 32-битных приложений такой системной папкой является 'SysWOW64'.

Как запустить Batch-файл с повышенными правами (от имени Администратора)?

Неискушенные пользователи семерки и восьмерки, сами того не подозревая, время от времени сталкиваются с проблемой запуска приложений, требующих повышенных привилегий в системе. При этом казалось-бы вполне себе работоспособное приложение в "хрюше" вдруг перестает работать в новых версиях ОС из-за более жесткой политики безопасности. Тем не менее, приложение вполне работоспособно, если знать небольшие хитрости.

Первая и, пожалуй, наиболее классическая – обычный запуск в режиме совместимости с созданием ярлыка к запускаемому приложению и активацией запуска от имени администратора. Рассмотрим пример. У вас есть приложение, скажем тот же наш пакетный файл обновления. На рабочем столе или через контекстное меню проводника создайте ярлык к этому файлу и зайдите в свойства ярлыка. Теперь выберите вкладку "Ярлык", нажмите кнопку "Дополнительно" и активируйте опцию "Запускать от имени администратора". Все, звучат фанфары!


Рис. Создание ярлыка и активация режима запуска от администратора

Вторая – запуск через команду Runas [8], к примеру, в нашем случае:
@echo off
runas /user:Администратор update.bat
Первой строкой мы запрещаем текстовый вывод. Второй же, запускаем утилиту 'Runas.exe', передав ей в качестве имени пользователя – имя текущего пользователя c административными привилегиями. У второй есть большой недостаток – необходимость ввода пароля и обязательность записи bat и cmd файлов с расширениями. Поэтому появились еще извращения способы [9…11] повышения привилегий: через PowerShell http://technet.microsoft.com/ru-ru/library/bb978526.aspx, Native Shell https://github.com/amdf/NativeShell или AdmiLink http://crw-daq.ru/download/doc/admilink/admilink.htm и т.д.

Заключение

Все упомянутые утилиты, тестовые пакетные файлы обновления, создания и удаления сервиса (архив upd_res.zip) вы можете загрузить c сайта автора или сайта нашего журнала (раздел ”Программы”). Если тема представляет для вас интерес – пишите, задавайте вопросы. Удачного вам апдейта!

Ресурсы
  1. Ресурсы к проекту. Скрипты и утилиты 
  2. MSDN. Описание системной утилиты Netsh http://msdn.microsoft.com/en-us/library/windows/desktop/bb736546(v=vs.85).aspx 
  3. Описание командной строки системной утилиты TaskList http://www.windows-commandline.com/tasklist-command
  4. Описание командной строки системной утилиты Taskkill http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/taskkill.mspx?mfr=true
  5. Создание службы Windows с помощью программы 'Sc.exe' http://support.microsoft.com/kb/251192/ru
  6. MS TechNet. Sc create http://technet.microsoft.com/ru-ru/library/cc990289(v=ws.10).aspx
  7. MSDN. Создание определяемой пользователем службы через INSTSRV.EXE http://support.microsoft.com/kb/137890/en-us
  8. Использование программы RUNAS.EXE http://windata.ru/windows-xp/faq-xp/ispolzovanie-programmy-runas-exe, http://technet.microsoft.com/en-us/library/bb490994.aspx
  9. Как открыть командную строку от имени администратора в нужной папке http://www.outsidethebox.ms/10629/
  10. Как открывать файлы из контекстного меню с полными правами http://www.outsidethebox.ms/12219
  11. Так ли страшен контроль учетных записей? http://www.outsidethebox.ms/10034/
  12. Run Apps and Batch Files without a Console Window or UAC Prompt with Hidden Start http://www.ntwind.com/software/hstart.html

Комментариев нет:

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.