Многие сталкивались с тем, что при динамичесом обновлении новая версия конфигурации может работать с ошибками, причем ошибки могут быть совершенно не связаны с измененным объектом и даже не поддаваться никакому логическому объяснению как например ошибка формата потока. Для их устранения нужно всего-лишь отчистить кэш пользователя у которого она возникает. Было решено не чистить кэш при каждом динамическом обновлении, а чистить только тогда, когда это действительно необходимо, причем пользователь сам решит, когда ему удобно произвести очистку.
Есть много решений данной проблемы, и хочется добавить к ним еще один вариант решения, который успешно работает и для кого-то может быть более удобным.
Основное отличие обработки:
1. Очистка производится с помощью bat файла
2. Очищается только каталог в котором находится кэш текущего сеанса работы
3. При очистке кэша я столкнулся с тем, что простое удаление файлов кэша ничего не дает (windows умудряется их восстанавливать и ошибка возникает вновь), поэтому при очистке генерируется новый уникальный идентификатор базы, а старые файлы кэша удаляются вместе с каталогом в котором они находятся.
Разработка выполнялась для себя, поэтому предполагается, что пользователь работает с 1С8.2 и в клиент-серверном варианте работы программы.
////////////////////////////////////////////////////////////////////////////////
// ПРОЦЕДУРЫ И ФУНКЦИИ ОБЩЕГО НАЗНАЧЕНИЯ
// Помещает в массив строки, которые разделены указанным символом
// Параметры
// Стр - строка, которую необходимо разложить
// Разделитель - строка, символ разделяющий строки
//
// Возвращаемое значение
// Массив строк
//
Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",")
МассивСтрок = Новый Массив();
Если Разделитель = " " Тогда
Стр = СокрЛП(Стр);
Пока 1=1 Цикл
Поз = Найти(Стр,Разделитель);
Если Поз=0 Тогда
МассивСтрок.Добавить(Стр);
Возврат МассивСтрок;
КонецЕсли;
МассивСтрок.Добавить(Лев(Стр,Поз-1));
Стр = СокрЛ(Сред(Стр,Поз));
КонецЦикла;
Иначе
ДлинаРазделителя = СтрДлина(Разделитель);
Пока 1=1 Цикл
Поз = Найти(Стр,Разделитель);
Если Поз=0 Тогда
МассивСтрок.Добавить(Стр);
Возврат МассивСтрок;
КонецЕсли;
МассивСтрок.Добавить(Лев(Стр,Поз-1));
Стр = Сред(Стр,Поз+ДлинаРазделителя);
КонецЦикла;
КонецЕсли;
КонецФункции // глРазложить
// Возвращает строку запуска 1С
// Параметры
// Нет
//
// Возвращаемое значение
// Строка для запуска 1С
//
Функция ПолучитьСтрокуЗапуска1С()
ПутьКФайлуЗапуска = "";
Если КаталогИлиФайлСуществует("C:\Program Files (x86)\1cv82\common\1cestart.exe") Тогда
ПутьКФайлуЗапуска = """C:\Program Files (x86)\1cv82\common\1cestart.exe";
ИначеЕсли КаталогИлиФайлСуществует("C:\Program Files\1cv82\common\1cestart.exe") Тогда
ПутьКФайлуЗапуска = """C:\Program Files\1cv82\common\1cestart.exe";
Иначе
Возврат "";
КонецЕсли;
ИмяИБ = "";
ИмяСервера = "";
ПодстрокиСтрокиСоединения = РазложитьСтрокуВМассивПодстрок(СтрокаСоединенияИнформационнойБазы(),";");
Если ПодстрокиСтрокиСоединения.Количество()> 1 и Лев(ПодстрокиСтрокиСоединения[0], 5) = "Srvr=" и Лев(ПодстрокиСтрокиСоединения[1], 4) = "Ref=" Тогда
ИмяСервера = Сред(ПодстрокиСтрокиСоединения[0],7, СтрДлина(ПодстрокиСтрокиСоединения[0]) - 7);
ИмяИБ = Сред(ПодстрокиСтрокиСоединения[1],6, СтрДлина(ПодстрокиСтрокиСоединения[1]) - 6);
КонецЕсли;
ИмяТекПользователя = ?(ПользователиИнформационнойБазы.ТекущийПользователь().АутентификацияОС = Истина,"",ИмяПользователя());
ПараметрыСтрокиЗапуска = "";
Если ИмяСервера <> "" И ИмяИБ <> "" Тогда
ПараметрыСтрокиЗапуска = """ ENTERPRISE" + " /S""" + ИмяСервера + "\" + ИмяИБ + """/N""" + ИмяТекПользователя + """";
КонецЕсли;
Возврат ПутьКФайлуЗапуска + ПараметрыСтрокиЗапуска;
КонецФункции
// Проверяет существование каталога
// Параметры
// Путь - путь к проверяемому каталогу
//
// Возвращаемое значение
// Булево. Истина, если каталог существует, Ложь, если каталог не существует
//
Функция КаталогИлиФайлСуществует(Путь)
КаталогНаДиске = Новый Файл(Путь);
Если КаталогНаДиске.Существует() Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// ПРОЦЕДУРЫ - ДЕЙСТВИЯ ФОРМЫ
// Процедура вызывается при нажатии кнопки "Сформировать" командной панели формы
//
Процедура КнопкаСформироватьНажатие(Кнопка)
//Проверка штука хорошая, однако я столкнулся с ограничениями доступа пользователей. Для
//того, чтобы все было корректно необходимо положить ее в привелигированный модуль.
//
//МассивСоединений = ПолучитьСоединенияИнформационнойБазы();
//НомерТекущегоСоединения = НомерСоединенияИнформационнойБазы();
//ИмяТекПользователя = ИмяПользователя();
//
//Для каждого Соединение ИЗ МассивСоединений Цикл
// Если Соединение.ИмяПриложения <> "Designer"
// И Соединение.НомерСоединения <> НомерТекущегоСоединения
// И Соединение.Пользователь <> Неопределено
// И СокрЛП(Соединение.Пользователь.Имя) = ИмяТекПользователя
// Тогда
// Предупреждение("Существует несколько сеансов работы с текущей базой. Закройте их.");
// Возврат;
// КонецЕсли;
//КонецЦикла;
WSH=Новый COMobject("wscript.shell");
ПрофильПользователя = WSH.ExpandEnvironmentStrings("%APPDATA%");//Возвращает используемое по умолчанию размещение данных приложений
Каталог = ПрофильПользователя+"\1C\1CEStart\";
КаталогСуществует = КаталогИлиФайлСуществует(Каталог);
Если КаталогСуществует = Ложь Тогда
Сообщить("Не найден каталог инфрормационной базы. Очистка кеша невозможна. ");
Возврат;
КонецЕсли;
Каталог = Каталог + "ibases.v8i";
Если КаталогИлиФайлСуществует(Каталог) Тогда
Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(Каталог);
ТекстФайла = Текст.ПолучитьТекст();
Позиция = Найти(ТекстФайла,СтрокаСоединенияИнформационнойБазы());
Если Позиция = 0 Тогда
Сообщить("GUID информационной базы не найден. Очистка кеша невозможна.");
Возврат;
Иначе
ТекстФайла = Прав(ТекстФайла,СтрДлина(ТекстФайла) - Позиция + 1);
Позиция = Найти(ТекстФайла,"ID=");
GUID = Сред(ТекстФайла, Позиция + 3, 36);
НовыйGUID = Новый УникальныйИдентификатор;
Пока Найти(ТекстФайла,НовыйGUID) > 0 Цикл
НовыйGUID = Новый УникальныйИдентификатор;
КонецЦикла;
Если Вопрос("Необходимо перезагрузить программу. Перезагружаем?",РежимДиалогаВопрос.ДаНет) = КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
//Присвоим базе новый УИД
ТекстФайла = Текст.ПолучитьТекст();
ТекстФайла = СтрЗаменить(ТекстФайла,GUID,НовыйGUID);
Текст.УстановитьТекст(ТекстФайла);
Текст.Записать(Каталог);
КонецЕсли;
Иначе
Сообщить("Файл ""ibases.v8i"" не найден. Очистка кеша невозможна.");
Возврат;
КонецЕсли;
Каталог = СтрЗаменить(Каталог,"1CEStart\ibases.v8i","") + "1Cv82\" + GUID + "\";
Если КаталогИлиФайлСуществует(Каталог) Тогда
ПутьКФайлу = Каталог + "1Cv8.lck";
ТекстBatФайла = "
|cd\
|cls
|rem Restart 1C
|@echo off
|rem Файл работает следующим образом:
|rem ждем пока удалится файл 1Cv8_1.lck (удаляется при закрытии 1С) и чистим кэш
|rem если файл не удаляется в течение 40 сек. завершаем работу программы
|set /a count=1
|:flag
|if %count% gtr 8 goto end
|if Not exist """ + ПутьКФайлу + """ goto go
|ping -n 5 127.0.0.1 > NUL
|call set /a count+=1
|goto flag
|:go
|rem Удаляем все файлы
|Del /F /Q """ + Каталог + "*.*""
|rem Удаляем все каталоги
|for /d %%i in ("""+ Каталог + "*"") do rmDir /s /q ""%%i""
|rem Удаляем основной каталог
|rmDir """ + Лев(Каталог,СтрДлина(Каталог)-1) + """
|:end
|rem Запускаем 1С
|" + ПолучитьСтрокуЗапуска1С() + "
|rem Удаляем этот файл
|del %0";
Текст = Новый ТекстовыйДокумент;
Текст.УстановитьТекст(ТекстBatФайла);
Текст.Записать(КаталогВременныхФайлов() + "\ClearCache.bat",КодировкаТекста.OEM);
ЗапуститьПриложение("""" + КаталогВременныхФайлов() + "\ClearCache.bat""");
ЗавершитьРаботуСистемы(Ложь);
Иначе
Сообщить("Каталог с GUIDом """ + GUID + """ не найден. Очистка кеша невозможна.");
Возврат;
КонецЕсли;
КонецПроцедуры