Как исправить ошибку «Отказано в доступе» (0x80070005) при вызове MSScriptControl.ScriptControl и переписать скачивание файлов из Dropbox на нативный код 1С 8.3?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При переносе старых обработок с платформы 1С 7.7 («семерки») на 1С 8.3 («восьмерку») разработчики часто сталкиваются с проблемами совместимости устаревших COM-объектов и системных библиотек. Типичный пример — использование объекта MSScriptControl.ScriptControl для выполнения VBScript-кода. В современных операционных системах Windows при попытке инициализировать этот объект часто возникает критическая ошибка: «Ошибка при вызове конструктора (COMОбъект) ... по причине: -2147024891(0x80070005): Отказано в доступе».

В этой статье мы подробно разберем, почему возникает эта ошибка, как быстро обойти её с помощью прямой работы с COM-объектами и как правильно переписать этот функционал на современный, надежный и кроссплатформенный нативный код 1С 8.3 без использования каких-либо внешних библиотек.

Выясняем причины возникновения ошибки доступа (0x80070005)

Для начала проанализируем, почему код, который годами стабильно работал на платформе 1С 7.7, начинает выдавать ошибку доступа на 1С 8.

Основная причина кроется в безопасности операционной системы Windows и разрядности процессов:

  1. Разрядность приложения (32-бит против 64-бит). Библиотека MSScriptControl (файл msscript.ocx) является исключительно 32-разрядным ActiveX-компонентом. Если ваша база 1С 8 запускается под 64-разрядным клиентом или на 64-разрядном сервере приложений, операционная система физически не может загрузить 32-битный COM-объект в 64-битный процесс. Это вызывает сбой инициализации.
  2. Политики безопасности современных ОС (UAC). В актуальных версиях Windows (Windows 10, 11, Server 2016/2019/2022) запуск сценариев ActiveX жестко ограничен. Попытка создания объекта выполнения сценариев из-под процесса 1С, запущенного без прав администратора (или под системной учетной записью службы сервера 1С USR1CV8), блокируется операционной системой с выдачей системной ошибки «Отказано в доступе».

Вариант решения №1: Быстрый обход проблемы через ADODB.Stream (COM)

Если вам требуется максимально быстро запустить обработку без глобальной переработки логики, мы можем исключить использование промежуточного объекта 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 и клиентского режима обычных форм. Однако у него есть серьезные архитектурные недостатки:

Вариант решения №2: Современный нативный код 1С 8.3 (Рекомендуемый)

Платформа 1С v8.3 предоставляет встроенные механизмы работы с интернет-ресурсами, которые позволяют отказаться от любых COM-объектов (таких как WinHttp.WinHttpRequest и ADODB.Stream). Мы можем решить эту задачу с помощью объектов HTTPСоединение и HTTPЗапрос.

При работе с файлообменником Dropbox напрямую через встроенный HTTP-клиент 1С необходимо учитывать две критически важные особенности:

  1. Корректировка ссылки для скачивания. Публичные ссылки, генерируемые Dropbox, обычно заканчиваются параметром ?dl=0 (например, https://www.dropbox.com/s/xyz123/file.xlsx?dl=0). Если отправить запрос по такой ссылке напрямую, сервер Dropbox вернет не сам файл Excel, а HTML-страницу предпросмотра веб-интерфейса. Чтобы скачать именно бинарный файл, нам нужно заменить этот параметр в ссылке на ?dl=1 или ?raw=1.
  2. Обработка редиректов (перенаправлений). Серверы Dropbox никогда не отдают файлы напрямую с основного домена. Они возвращают HTTP-ответ со статусом временного перенаправления 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;
        Результат.Путь = "/";
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Рассмотрим подробнее логику работы написанного нами кода:

Используя этот нативный подход, вы гарантируете стабильность работы вашей системы, полную независимость от разрядности операционной системы и версии платформы 1С, а также получаете полностью кроссплатформенный код, готовый к работе в любых корпоративных ИТ-ландшафтах.

← На главную