При переносе старых обработок с платформы 1С 7.7 («семерки») на 1С 8.3 («восьмерку») разработчики часто сталкиваются с проблемами совместимости устаревших COM-объектов и системных библиотек. Типичный пример — использование объекта MSScriptControl.ScriptControl для выполнения VBScript-кода. В современных операционных системах Windows при попытке инициализировать этот объект часто возникает критическая ошибка: «Ошибка при вызове конструктора (COMОбъект) ... по причине: -2147024891(0x80070005): Отказано в доступе».
В этой статье мы подробно разберем, почему возникает эта ошибка, как быстро обойти её с помощью прямой работы с COM-объектами и как правильно переписать этот функционал на современный, надежный и кроссплатформенный нативный код 1С 8.3 без использования каких-либо внешних библиотек.
Для начала проанализируем, почему код, который годами стабильно работал на платформе 1С 7.7, начинает выдавать ошибку доступа на 1С 8.
Основная причина кроется в безопасности операционной системы Windows и разрядности процессов:
MSScriptControl (файл msscript.ocx) является исключительно 32-разрядным ActiveX-компонентом. Если ваша база 1С 8 запускается под 64-разрядным клиентом или на 64-разрядном сервере приложений, операционная система физически не может загрузить 32-битный COM-объект в 64-битный процесс. Это вызывает сбой инициализации.USR1CV8), блокируется операционной системой с выдачей системной ошибки «Отказано в доступе».Если вам требуется максимально быстро запустить обработку без глобальной переработки логики, мы можем исключить использование промежуточного объекта MSScriptControl.ScriptControl. Исходный VBScript-код использовался только для того, чтобы передать бинарные данные (Response Body) из HTTP-запроса в файл на диске через поток ADODB.Stream. Мы можем работать с этим потоком напрямую из 1С.
Посмотрим на пример кода, который исключает использование MSScriptControl:
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open("GET", СсылкаНаФайлDropbox, 0);
WinHttp.Send();
Если WinHttp.Status = 200 Тогда
StreamOut = Новый COMОбъект("ADODB.Stream");
StreamOut.Type = 1; // Указываем тип данных: бинарный
StreamOut.Mode = 3; // Режим доступа: чтение и запись
StreamOut.Open();
StreamOut.Write(WinHttp.ResponseBody); // Записываем тело ответа в поток
StreamOut.SaveToFile(ИмяВыходногоФайла, 2); // Сохраняем файл на диск с перезаписью
StreamOut.Close();
StreamOut = Неопределено;
Иначе
Сообщить("Ошибка получения файла! Статус сервера: " + WinHttp.Status);
КонецЕсли;
Проанализируем этот подход. Данное решение вполне рабочее для операционных систем семейства Windows и клиентского режима обычных форм. Однако у него есть серьезные архитектурные недостатки:
ADODB.Stream может блокироваться антивирусным ПО или политиками безопасности домена при выполнении на стороне сервера приложений.Платформа 1С v8.3 предоставляет встроенные механизмы работы с интернет-ресурсами, которые позволяют отказаться от любых COM-объектов (таких как WinHttp.WinHttpRequest и ADODB.Stream). Мы можем решить эту задачу с помощью объектов HTTPСоединение и HTTPЗапрос.
При работе с файлообменником Dropbox напрямую через встроенный HTTP-клиент 1С необходимо учитывать две критически важные особенности:
?dl=0 (например, https://www.dropbox.com/s/xyz123/file.xlsx?dl=0). Если отправить запрос по такой ссылке напрямую, сервер Dropbox вернет не сам файл Excel, а HTML-страницу предпросмотра веб-интерфейса. Чтобы скачать именно бинарный файл, нам нужно заменить этот параметр в ссылке на ?dl=1 или ?raw=1.302 Found (или 301/307), указывая реальный временный адрес скачивания в заголовке ответа Location. Встроенный объект 1С HTTPСоединение не умеет автоматически следовать по перенаправлениям, поэтому нам необходимо обработать редиректы программно в цикле.Рассмотрим по шагам надежный, отказоустойчивый и кроссплатформенный код для скачивания файлов из Dropbox, который будет отлично работать как на Windows, так и на Linux, в файловом и клиент-серверном вариантах работы.
&НаСервереБезКонтекста
Процедура СкачатьФайлСDropbox(Знач СсылкаDropbox, Знач ИмяФайлаНаДиске)
// Шаг 1. Корректируем ссылку для принудительного прямого скачивания файла
Если Найти(СсылкаDropbox, "?dl=0") > 0 Тогда
СсылкаDropbox = СтрЗаменить(СсылкаDropbox, "?dl=0", "?dl=1");
ИначеЕсли Найти(СсылкаDropbox, "?") = 0 Тогда
СсылкаDropbox = СсылкаDropbox + "?dl=1";
КонецЕсли;
ТекущийАдрес = СсылкаDropbox;
МаксРедиректов = 5; // Устанавливаем лимит перенаправлений для защиты от зацикливания
Шаг = 0;
// Dropbox работает исключительно по защищенному протоколу HTTPS
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
Пока Шаг < МаксРедиректов Цикл
// Разбираем URL на составляющие (хост, путь, порт)
СтруктураURI = РазобратьАдресURL(ТекущийАдрес);
Соединение = Новый HTTPСоединение(
СтруктураURI.Хост,
СтруктураURI.Порт,
, , , 20, // Таймаут соединения 20 секунд
ЗащищенноеСоединение
);
Запрос = Новый HTTPЗапрос(СтруктураURI.Путь);
Попытка
// Метод Получить() платформы 1С автоматически записывает тело ответа в файл на диске
Ответ = Соединение.Получить(Запрос, ИмяФайлаНаДиске);
КодСостояния = Ответ.КодСостояния;
Если КодСостояния = 200 Тогда
// Файл успешно загружен и сохранен на диск
Возврат;
ИначеЕсли КодСостояния = 301 Или КодСостояния = 302 Или КодСостояния = 307 Тогда
// Обрабатываем перенаправление сервера Dropbox
НовыйАдрес = Ответ.Заголовки.Получить("Location");
Если ЗначениеЗаполнено(НовыйАдрес) Тогда
ТекущийАдрес = НовыйАдрес;
Шаг = Шаг + 1;
Продолжить; // Переходим на следующую итерацию цикла с новым адресом
Иначе
ВызватьИсключение "Сервер вернул пустой адрес перенаправления (Location).";
КонецЕсли;
Иначе
ВызватьИсключение "Ошибка HTTP-запроса. Код ответа сервера: " + КодСостояния;
КонецЕсли;
Исключение
ВызватьИсключение "Произошел сбой при скачивании файла: " + ОписаниеОшибки();
КонецПопытки;
КонецЦикла;
ВызватьИсключение "Превышено допустимое количество перенаправлений (редиректов).";
КонецПроцедуры
&НаСервереБезКонтекста
Функция РазобратьАдресURL(Знач URL)
Результат = Новый Структура("Хост, Порт, Путь", "", 443, "");
// Удаляем протокол из строки URL
Если Найти(НРег(URL), "https://") = 1 Тогда
URL = Сред(URL, 9);
Результат.Port = 443;
ИначеЕсли Найти(НРег(URL), "http://") = 1 Тогда
URL = Сред(URL, 8);
Результат.Порт = 80;
КонецЕсли;
// Находим первый разделитель пути
РазделительПути = Найти(URL, "/");
Если РазделительПути > 0 Тогда
Результат.Хост = Лев(URL, РазделительПути - 1);
Результат.Путь = Сред(URL, РазделительПути);
Иначе
Результат.Хост = URL;
Результат.Путь = "/";
КонецЕсли;
Возврат Результат;
КонецФункции
Рассмотрим подробнее логику работы написанного нами кода:
РазобратьАдресURL мы делим входящую строку на хост (доменное имя) и путь к ресурсу, что критически важно для корректной инициализации объекта HTTPСоединение.ЗащищенноеСоединениеOpenSSL. Без этого платформа вернет ошибку при попытке связаться по протоколу SSL/TLS.Получить() мы вторым параметром передаем локальный путь к файлу. Платформа 1С самостоятельно берет на себя всю работу по потоковому чтению данных из сети и записи их на жесткий диск — нам больше не требуются сторонние потоковые библиотеки.Пока ... Цикл отслеживает заголовки ответов. Если Dropbox возвращает заголовок Location с кодом перенаправления 302, наш код мгновенно подхватывает новый адрес, разбирает его и отправляет повторный запрос до тех пор, пока файл не будет успешно скачан.Используя этот нативный подход, вы гарантируете стабильность работы вашей системы, полную независимость от разрядности операционной системы и версии платформы 1С, а также получаете полностью кроссплатформенный код, готовый к работе в любых корпоративных ИТ-ландшафтах.