При переходе на 64-разрядные версии платформы «1С:Предприятие» разработчики часто сталкиваются с проблемами совместимости старого кода, который использовал внешние COM-компоненты. Типичный сценарий — выгрузка или загрузка данных через офисные пакеты (MS Excel или LibreOffice/OpenOffice Calc). Код, который годами стабильно работал на 32-битных клиентах, внезапно начинает аварийно завершаться с ошибками доступа или маршаллинга в 64-битной среде.
В этой статье мы подробно проанализируем, почему возникает ошибка «Произошла исключительная ситуация (Ошибка выполнения Microsoft JScript): Разрешение отклонено» при интеграции 1С с LibreOffice, разберем архитектурные причины этого сбоя и рассмотрим правильное, современное решение без использования устаревших библиотек.
Рассмотрим классический пример кода, который часто использовался для работы с LibreOffice в скрытом режиме на 32-битных клиентах 1С:
ServiceManager = New COMObject("com.sun.star.ServiceManager");
js = New COMObject("MSScriptControl.ScriptControl");
js.language = "javascript";
js.AddObject("ServiceManager", ServiceManager);
js.eval("Arr = new Array()");
js.eval("Arr[0] = ServiceManager.Bridge_GetStruct('com.sun.star.beans.PropertyValue')"); // Ошибка происходит здесь
При выполнении этого кода на стороне 64-битного клиента 1С система выбрасывает исключение. Даже если вы попытаетесь обновить сам офисный пакет LibreOffice до 64-битной версии, это не решит проблему. Дело здесь не в разрядности самого LibreOffice, а в компоненте MSScriptControl.ScriptControl.
Проанализируем ситуацию с технической точки зрения:
msscript.ocx, разработанная корпорацией Microsoft, существует исключительно в 32-разрядном варианте. Официальной 64-битной версии этого COM-объекта никогда не выпускалось.MSScriptControl, операционная система Windows вынуждена запускать его «вне процесса» (out-of-process) в специальном суррогатном контейнере dllhost.exe (через службы компонентов COM+).ServiceManager) внутрь изолированного 32-битного скрипт-контейнера через метод AddObject, стандартные механизмы маршаллинга COM Windows не могут корректно преобразовать типы данных и указатели между 64-битным процессом 1С и 32-битным процессом dllhost.exe. В результате операционная система блокирует вызов метода Bridge_GetStruct и возвращает ошибку «Разрешение отклонено».Ранее скрипт-контроль (JScript или VBScript) использовался разработчиками 1С как «костыль» для создания типизированных массивов, необходимых LibreOffice для параметров открытия файлов (например, для передачи флагов ReadOnly или Hidden). В современных версиях платформы 1С v8 этот обходной путь больше не требуется.
Для того чтобы избавиться от нестабильных 32-битных зависимостей и обеспечить бесперебойную работу кода как в 32-битных, так и в 64-битных клиентах 1С, нам необходимо полностью исключить MSScriptControl.ScriptControl из цепочки вызовов.
Платформа 1С содержит встроенный объект COMSafeArray, который позволяет передавать типизированные массивы в COM-объекты напрямую. Нам нужно использовать тип массива "VT_VARIANT", который понимается интерфейсом UNO LibreOffice без каких-либо посредников.
Разберем по шагам обновленный, полностью работоспособный и безопасный код:
// Шаг 1. Инициализируем менеджер сервисов LibreOffice
ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
// Шаг 2. Создаем объект Desktop для управления документами
Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");
// Шаг 3. Создаем структуры свойств (PropertyValue) напрямую через Bridge_GetStruct
Property1 = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
Property1.Name = "ReadOnly";
Property1.Value = Истина;
Property2 = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
Property2.Name = "Hidden";
Property2.Value = Истина;
// Шаг 4. Формируем безопасный массив параметров VT_VARIANT средствами 1С
Args = Новый COMSafeArray("VT_VARIANT", 2);
Args.SetValue(0, Property1);
Args.SetValue(1, Property2);
// Шаг 5. Приводим путь к файлу к URL-формату, требуемому для LibreOffice
// Пример конвертации: "C:\file.xlsx" -> "file:///C:/file.xlsx"
ПутьКФайлуРесурса = "file:///" + СтрЗаменить(СтрЗаменить(ПутьКФайлу, "\", "/"), " ", "%20");
// Шаг 6. Загружаем документ в скрытом режиме без использования скрипт-контроллера
Document = Desktop.LoadComponentFromURL(ПутьКФайлуРесурса, "_blank", 0, Args);
Этот код абсолютно универсален. Он отлично отрабатывает и на 32-битной, и на 64-битной версии клиента 1С, вне зависимости от разрядности установленного в системе пакета LibreOffice или OpenOffice.
Если в вашем решении динамический запуск JavaScript или VBScript действительно необходим для каких-то сторонних вычислений (не связанных напрямую с LibreOffice), и вы ищете полноценную замену MSScriptControl в 64-битной среде, можно рассмотреть следующие варианты.
В операционной системе Windows присутствует компонент MSHTML, который имеет встроенный движок для выполнения скриптов. Он доступен как в 32-битных, так и в 64-битных процессах. Мы можем использовать его для выполнения произвольного JS-кода следующим образом:
HTMLДокумент = Новый COMОбъект("htmlfile");
HTMLДокумент.Open("text/html");
// Добавляем тег скрипта с нужными функциями
HTMLДокумент.Write("<script>
|function ВычислитьВыражение(a, b) {
| return a + b;
|}
|</script>");
// Получаем объект окна для вызова функций скрипта
ОкноСкрипта = HTMLДокумент.parentWindow;
Результат = ОкноСкрипта.ВычислитьВыражение(10, 20); // Вернет 30
Для полной замены ScriptControl без изменения структуры вызовов вы можете установить бесплатную библиотеку с открытым исходным кодом Tablacus Script Control 64. После ее регистрации в операционной системе через утилиту regsvr32 в системе появится полноценный 64-разрядный объект скрипт-контроля.
Если вы планируете перенести разработанный код загрузки файлов из интерактивного клиента на сторону сервера 1С (например, для выполнения в фоновом или регламентном задании), вы можете столкнуться с ошибкой безопасности DCOM: «Отказано в доступе» (код ошибки 0x80070005).
Это связано с тем, что служба сервера «1С:Предприятия» по умолчанию функционирует под специальной локальной учетной записью (например, USR1CV8), у которой нет прав на запуск и активацию COM-объектов офисных приложений. Чтобы решить эту проблему, выполните следующие действия:
Win + R, введите dcomcnfg и нажмите Enter.В заключение отметим, что использование технологий COM-соединений жестко привязывает ваше прикладное решение к операционной системе семейства Windows. В современных условиях, когда бизнес массово мигрирует на Linux-платформы и СУБД PostgreSQL, использование внешних COM-компонентов считается устаревшей практикой.
Для работы с табличными документами платформа 1С предоставляет мощный нативный инструмент, не требующий установки офисных пакетов на сервере или клиенте:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособСравненияОбъектов.ИмяФайла);
// Далее производим разбор и обработку данных ТабличногоДокумента
Исключение
ЗаписатьЛогСобытий("Ошибка чтения файла: " + ОписаниеОшибки());
КонецПопытки;
Этот метод работает нативно, быстро и абсолютно кроссплатформенно как на Windows, так и на Linux, избавляя вас от необходимости настройки прав DCOM, отслеживания разрядности процессов и очистки «зависших» процессов офисных приложений в операционной системе.