Работая в франчайзи столкнулся с тем, что много времени тратится на то, чтобы обновить нетиповые конфигурации (хоть их и не сильно изменили), особенно в отчетный период. Бухгалтеру нужно сдавать отчеты, обновление только вышло и всем надо ставить срочно, знакомо, думаю, многим. И вот однажды как-то всё надоело, и стал задумываться, а как бы их автоматически обновлять. Первым делом выделил группы однотипно измененных конфигураций, получилось порядка 10 групп. Создал файлы обновления и поставки (материалов куча, не буду описывать). Для опыта выбрал по базе из каждой группы и поставил их на поддержку уже своей поставки (вроде так это называется, взял файл поставки того же релиза, что и конфигурация, и загрузил его). Вот теперь наши конфигурации "типовые", и теперь нам надо обновить уже не ....цать конфигураций, а всего 10, и сделать файлы обновлений. И теперь любой может обновлять как типовые. Идем дальше.
Хочется, чтобы при открытии конфигурация проверяла есть ли обновления, и сама устанавливала их. Возникли вопросы:
1) где хранить файлы обновлений
2) как их скачивать
3) как организовать автообновление конфигурации
1) По поводу хранения файлов обновления остановился на ftp сервере ([хорошая скорость отдачи, легкий доступ, ...). Нашел инструкцию по настройке ftp сервера на Windows 7, благо был внешний статический ip. Если нет такового, то провайдер может его предоставить или же воспользоваться специальной программкой DynDNS. Но для доступа к ftp серверу нужен логин и пароль, да и сам адрес, хранить его в коде не хотелось, сохранил во внешнем файле и, когда нужно, получал их. Также встал вопрос, как проверить релиз, ну тут просто имя файла сделал (2.0.64.5.cfu).
Так как не всем клиентам можно автоматически обновляться, а только тем, у кого есть действующая подписка ИТС, под каждого клиента была создана папка, в которой будет лежать обновление (и обновление мы будем проверять именно в этой папке). Отсюда вытекло, что хранить имя папки также где-то надо, сначала хотел хранить в константе, но потом решил хранить вне программы.
Руками раскидывать файлы обновлений и отслеживать, кому откуда копировать, а кому и не копировать (действующая подписка ИТС), трудоемко, для этих целей сделал обработку.
2) Сначала попробовал скачивать файл средствами 1С, но программа при этом зависала до окончания скачивания файла. Решил сделать через bat файл, но при его запуске висело окно командной панели, решено было его скрыть, написали скрипт. Протестировав загрузку файла, невозможно было понять, когда он загрузился полностью. Тестируя на Windows XP, решил проверять загрузку файла по размеру файла. Уже не помню почему, но размер файла указал в имени файла, в итоге имя файла обновлений стало выглядеть примерно так 2.0.64.5_12586125.cfu.
3) Обновление сделал в пакетном режиме (часть кода взял тут //infostart.ru/public/147253/, Спасибо!). Позже появилась идея использовать типовой механизм обновления конфигураций, подсунуть ему свой файл обновления, но руки так и не дошли.
Общий порядок получился такой:
В процедуре ПриНачалеРаботыСистемы проверяем наличие обновления:
ИмяFTPСервера = Адрес;//
ПортFTPСоединения = "21";
ПользовательFTPСоединения = Логин;//
ПарольFTPСоединения = Пароль;
ПассивноеFTPСоединение = Ложь;
Соединение = Новый FTPСоединение(ИмяFTPСервера, ПортFTPСоединения,ПользовательFTPСоединения,ПарольFTPСоединения, ,ПассивноеFTPСоединение);
//Путь на сервере в формате /OOO_Birka/
Массив = Соединение.НайтиФайлы(СокрЛП(ПутьНаСервере), "*.cfu");
Если Массив.Количество() <> 0 Тогда
Для Каждого Стр Из Массив Цикл
//Получаем релиз и сравниваем
ВерсияКонф = Метаданные.Версия;
ВерсияНаСервере = Стр.ИмяБезРасширения;
//проверить может уже скачан (вынесено выше до проверки обновления на ftp)
Если Число(Сред(ВерсияКонф,5,2)) < Число(Сред(ВерсияНаСервере,5,2)) Тогда
Режим = РежимДиалогаВопрос.ДаНет;
//Текст = "Вышло очередное обновление" + Символы.ПС + "Скачать??";
//Ответ = Вопрос(Текст, Режим, 0);
СформироватьБатникНаСкачивание(Стр.Имя);
ЭтотОбъект.ПолучитьФорму("Форма").Открыть();
ИначеЕсли Число(Сред(ВерсияКонф,5,2)) = Число(Сред(ВерсияНаСервере,5,2)) и Число(Сред(ВерсияКонф,8,1)) < Число(Сред(ВерсияНаСервере,8,1)) Тогда
Режим = РежимДиалогаВопрос.ДаНет;
//Текст = "Вышло очередное обновление" + Символы.ПС + "Скачать??";
//Ответ = Вопрос(Текст, Режим, 0);
//Если Ответ = КодВозвратаДиалога.Да Тогда
СформироватьБатникНаСкачивание(Стр.Имя);
ЭтотОбъект.ПолучитьФорму("Форма").Открыть();
//КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Процедура СформироватьБатникНаСкачивание(ИмяФайла)
ПутьДляОбновлений = "";
ПутьДляОбновлений = "D:\papka\";
Если ПутьДляОбновлений = Null или ПутьДляОбновлений = "" Тогда
Возврат;
КонецЕсли;
ПутьНаСервере = "/OOO_Birka/";
//vbs
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку("Dim oShell ");
тек.ДобавитьСтроку("Set oShell = WScript.CreateObject (""WSCript.shell"") ");
тек.ДобавитьСтроку("oShell.run """+ СокрЛП(ПутьДляОбновлений) + "1.bat"", 0 ");
тек.ДобавитьСтроку("Set oShell = Nothing");
тек.Записать(СокрЛП(ПутьДляОбновлений) + "start.vbs",КодировкаТекста.OEM,);
//txt
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку("open " + Адрес);
тек.ДобавитьСтроку(Логин);
тек.ДобавитьСтроку(Пароль);
тек.ДобавитьСтроку("get " + СокрЛП(ПутьНаСервере) + ИмяФайла + " " + СокрЛП(ПутьДляОбновлений) + ИмяФайла);
тек.ДобавитьСтроку("bye");
тек.Записать(СокрЛП(ПутьДляОбновлений) + "conf.txt",КодировкаТекста.OEM,);
//bat
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку("ftp -i -s:conf.txt");
тек.ДобавитьСтроку("timeout /t 3 ");
тек.ДобавитьСтроку("REN | RENAME " + СокрЛП(ПутьДляОбновлений) + ИмяФайла + " ok" + ИмяФайла);
тек.ДобавитьСтроку(СокрЛП(ПутьДляОбновлений) + "del.bat");
тек.Записать(СокрЛП(ПутьДляОбновлений) + "1.bat",КодировкаТекста.OEM,);
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку("del " + СокрЛП(ПутьДляОбновлений) + "conf.txt");
тек.ДобавитьСтроку("del " + СокрЛП(ПутьДляОбновлений) + "start.vbs");
тек.ДобавитьСтроку("del " + СокрЛП(ПутьДляОбновлений) + "1.bat"); тек.ДобавитьСтроку("del %0");
тек.Записать(СокрЛП(ПутьДляОбновлений) + "del.bat",КодировкаТекста.OEM,);
Запустить(ПутьДляОбновлений);
КонецПроцедуры
процедура Запустить(ПутьДляОбновлений)
КомандаСистемы(СокрЛП(ПутьДляОбновлений) + "start.vbs",СокрЛП(ПутьДляОбновлений));
КонецПроцедуры
В открываемой форме ( ЭтотОбъект.ПолучитьФорму("Форма").Открыть(); , код был в модуле обработки, в процедуре ПриОткрытии формы подключаем обработчик ожидания. Она проверяет окончание загрузки файла и открывает следующую форму:
Процедура Ожидать() Экспорт
ПодключитьОбработчикОжидания("ЖдатьЗагрузки",10);
Конецпроцедуры
Процедура ЖдатьЗагрузки()
Завершена = ОжиданиеЗагрузки(); /// процедура в модуле обработки
Если Завершена Тогда
ОтключитьОбработчикОжидания("ЖдатьЗагрузки");
ЭтотОбъект.ПолучитьФорму("Форма1").ОткрытьМодально();
ЭтаФорма.Закрыть();
Конецесли;
Конецпроцедуры
Процедура ПриОткрытии()
Ожидать();
КонецПроцедуры
Функция ОжиданиеЗагрузки() Экспорт
ПутьДляОбновлений = ""; ///каталог где хранится наш файл
ПутьДляОбновлений = "D:\papka\"; ///
Если ПутьДляОбновлений = Null или ПутьДляОбновлений = "" Тогда
Возврат ЛОЖЬ;
КонецЕсли;
Массив = НайтиФайлы(СокрЛП(ПутьДляОбновлений),"*.cfu");
Если Массив.Количество() = 0 Тогда
Массив = НайтиФайлы(СокрЛП(ПутьДляОбновлений), "*.cf");
КонецЕсли;
Если Массив.Количество() <> 0 Тогда
Для каждого стр из Массив Цикл
Если Найти(Стр.имя,"ok") Тогда
Позиц = Найти(Стр.ИмяБезРасширения,"_");
Размер = Число(Сред(Стр.ИмяБезРасширения,Позиц + 1 ));
Если Размер = Стр.Размер() Тогда
//Сообщить("Загрузка завершена");
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку(Стр.Имя);
тек.Записать(СокрЛП(ПутьДляОбновлений) + "imya.txt",КодировкаТекста.OEM,);
Возврат Истина;
Иначе
Возврат ЛОЖЬ;
конецЕсли;
Иначе
Возврат ЛОЖЬ;
КонецЕсли;
КонецЦикла;
Иначе
Возврат ЛОЖЬ;
КонецЕсли;
КонецФункции
Следующие формы проверяют активные сеансы и, если есть такие, просит их закрыть. Если активных сеансов нет, формирует bat файл для обновления, запускает его и закрывает программу. Процедура формирования bat файла:
Процедура СоздатьФайлобновления() Экспорт
ПутьДляОбновлений = "";
ПутьДляОбновлений = "D"\papka\";
Если ПутьДляОбновлений = Null или ПутьДляОбновлений = "" Тогда
Возврат;
КонецЕсли;
ПутьДляОбновлений = Лев(ПутьДляОбновлений,СтрДлина(ПутьДляОбновлений) - 1) + "ZIK\";
ПутьАрхива = "D:\Arhiv\";
Если ПутьАрхива = Null или ПутьАрхива = "" Тогда
Возврат;
КонецЕсли;
ПутьДля1СПредприятия = "C:\Program Files (x86)\1cv82\8.2.19.76\bin\1cv8.exe";
тек = Новый ТекстовыйДокумент;
тек.ДобавитьСтроку("timeout /t 10 ");
ЗапускПред = """"+СокрЛП(ПутьДля1СПредприятия)+""" enterprise";
ЗапускКонф = """"+СокрЛП(ПутьДля1СПредприятия)+""" config";
Пароль = "";
Подсказка = "Введите пароль своего пользователя в 1С (Если Он есть), "+ Символы.ПС +" если пароль не задан нажмите ОК";
ВвестиСтроку(Пароль, Подсказка, 0, Истина);
ПодклБаза = " /F"""+НСтр(СтрокаСоединенияИнформационнойБазы(), "File")+"""" +?(СокрЛП(ПараметрыСеанса.ТекущийПользователь.Наименование)="" или СокрЛП(ПараметрыСеанса.ТекущийПользователь.Наименование) = "<Не указан>",""," /N"""+СокрЛП(ПараметрыСеанса.ТекущийПользователь.Наименование)+"""") + ?(СокрЛП(Пароль)="",""," /P"""+СокрЛП(Пароль)+"""");
РезервКоп = " /DumpIB"""+СокрЛП(ПутьАрхива)
+СтрЗаменить(СтрЗаменить("Было"," "," ")," ","_")+"_"
+СтрЗаменить(Формат(ТекущаяДата(),"ДЛФ=Д"),".","_")+"Бух.dt""";
РезервКоп2 = " /DumpIB"""+СокрЛП(ПутьАрхива)
+СтрЗаменить(СтрЗаменить("стало"," "," ")," ","_")+"_"
+СтрЗаменить(Формат(ТекущаяДата(),"ДЛФ=Д"),".","_")+"Бух.dt""";
Массив = НайтиФайлы(СокрЛП(ПутьДляОбновлений),"imya.txt");
Если Массив.Количество() <> 0 Тогда
Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(СокрЛП(ПутьДляОбновлений) + "imya.txt");
ФайлОбновление = СОКРЛП(Текст.ПолучитьСтроку(1));
Иначе
ФайлОбновление = "";
Возврат;
КонецЕсли;
ОбновлКонф = " /UpdateCfg"""+СокрЛП(ПутьДляОбновлений) + ФайлОбновление+"""";
ОбновлБазы = " /UpdateDBCfg";
стр = ЗапускКонф+ПодклБаза+РезервКоп;
Если стр<>"" тогда тек.ДобавитьСтроку(стр); стр=""; конецесли;
стр = ЗапускКонф+ПодклБаза+ОбновлКонф;
стр = стр+ОбновлБазы;
Если стр<>"" тогда тек.ДобавитьСтроку(стр); стр=""; конецесли;
стр = ЗапускКонф+ПодклБаза+РезервКоп2;
Если стр<>"" тогда тек.ДобавитьСтроку(стр); стр=""; конецесли;
тек.ДобавитьСтроку("del " + СокрЛП(ПутьДляОбновлений) + ФайлОбновление);
тек.ДобавитьСтроку("del " + СокрЛП(ПутьДляОбновлений) + "imya.txt");
стр = ЗапускПред+ПодклБаза;
Если стр<>"" тогда тек.ДобавитьСтроку(стр); стр=""; конецесли;
тек.ДобавитьСтроку("del %0");
тек.ДобавитьСтроку("");
тек.Записать(СокрЛП(ПутьДляОбновлений) + "Obnov.bat",КодировкаТекста.OEM,);
Конецпроцедуры
процедура ЗапуститьОбновление(Форма) Экспорт
ПутьДляОбновлений = "D:\Papka\";
ЗапуститьПриложение(СокрЛП(ПутьДляОбновлений) + "Obnov.bat");
ПрекратитьРаботуСистемы();
КонецПроцедуры
Позже переделал это всё в обработку (её и выкладываю) и указывал дополнительные параметры запуска "/Execute "C:\Загрузка.epf", обновляем типовые конфигурации. Нам только необходимо определиться с местом хранения параметров: адрес ftp, логин, пароль, папка клиента на ftp и папка, куда мы будем скачивать обновления. Велись работы по изменению окна обновления, чтобы не висело окно командной панели, заменить чем-нибудь красивым. И вроде как бы получилось, если кому-то надо, поищу исходники. Проблемные места:
1) Блокирует скачивание брэндмауер, Kaspersky, Avira.
2) При наличии 2 сетевых подключений загрузка не происходит.
3) Требуется участие пользователя.
4) Иногда процесс обновления конфигурации не происходит, пользователь видит сообщение "конфигурация базы данных не соответствует сохраненной конфигурации" и звонит вам.
5) Паранормальные случаи.
Проверял только на файловых версиях. Операционные системы: Windows XP, Windows 7, Windows 8, Windows Vista. Код открытый, обработку необходимо немного изменить (решить, где хранить параметры и прописать их получение). С вводом и настройкой автоматического обновления. Обновление готовлю в свободное время (иногда поздно вечером) и терерь, сделав 10 файлов обновления, обновляем ими более 250 клиентов. Мы не привязаны к временным рамкам работы бухгалтера.