Как исправить ошибки при интеграции JScript в 1С для расчета CRC8 и перенести алгоритм на чистый код 1С

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

При интеграции сторонних алгоритмов в среду 1С:Предприятие разработчики часто сталкиваются с необходимостью использования готовых скриптов на языке JavaScript (JScript). Обычно это связано с криптографией, расчетом различных контрольных сумм (например, CRC8, CRC16) или работой со специфическим торговым оборудованием. Классическим подходом для реализации таких задач долгое время являлось использование COM-объекта MSScriptControl.ScriptControl.

Однако этот подход таит в себе множество подводных камней — от неочевидных синтаксических ошибок при передаче строк до критических проблем совместимости с современными 64-разрядными серверами и клиентами 1С. В рамках данной статьи мы подробно разберем, почему возникают ошибки при вызове JScript из 1С, как их исправить, в чем заключается главная опасность использования MSScriptControl, и как полностью переписать алгоритм расчета контрольной суммы CRC8 (дополнение до двух) на чистый и производительный код 1С.

Анализ технических ошибок из темы форума

Давайте подробно проанализируем, почему у автора темы возникли сбои на начальных этапах реализации.

1. Ошибка компиляции при вызове метода AddCode

В первом сообщении автор приводит ошибку компиляции Microsoft JScript: «Синтаксическая ошибка» при выполнении метода AddCode. Причин у этой проблемы несколько:

  1. Символы экранирования и кавычек: В коде JScript используются двойные кавычки для обозначения строк (например, strHex = new String("0123456789ABCDEF")). При передаче этого кода в качестве строкового литерала 1С необходимо строго соблюдать правила экранирования — удваивать кавычки. В исходном примере кода автора кавычки были экранированы некорректно, что нарушило структуру строки еще на этапе компиляции в самом движке 1С.
  2. Однострочные комментарии: В коде присутствуют комментарии вида // Calculate 2's complement. Когда многострочный текст из 1С передается через COM-объект, символы перевода строк (ПС) могут некорректно интерпретироваться компонентой. В результате весь последующий исполняемый код «склеивается» в одну строку с комментарием //, превращаясь в неисполняемый текст. Это гарантированно вызывает синтаксическую ошибку компиляции JScript. Рекомендуется полностью избегать однострочных комментариев // в передаваемом коде и заменять их на блочные /* ... */ или удалять.

2. Исключительная ситуация (0x80020006) при вызове метода Run

Код ошибки 0x80020006 расшифровывается как «Неизвестное имя» (DISP_E_UNKNOWNNAME). Автор попытался вызвать выполнение функции следующим образом:

Результат = ScrptCtrl.Run("CRC8("""+КодКарты+""");");

Это грубейшая ошибка использования метода Run. Данный метод устроен так: первым параметром передается исключительно имя вызываемой функции в виде строки, а все последующие аргументы функции передаются как отдельные параметры метода Run. Передавая в первый параметр всю конструкцию с аргументом и точкой с запятой, разработчик заставлял систему искать функцию с безумным именем CRC8("AABBCCDD");, которой, естественно, не существовало в контексте скрипта.

Правильный синтаксис вызова метода Run должен выглядеть так:

Результат = ScrptCtrl.Run("CRC8", КодКарты);

Автор темы обошел эту проблему, заменив метод Run на метод Eval:

Результат = ScrptCtrl.Eval("CRC8("""+КодКарты+""");");

Метод Eval действительно работает иначе — он принимает на вход единую строку, компилирует ее как выражение JScript «на лету» и возвращает результат. Несмотря на работоспособность данного костыля, использование Eval снижает производительность (так как выражение парсится заново при каждом вызове) и снижает безопасность кода.

Скрытая угроза: проблема 64-битной совместимости

Использование компоненты MSScriptControl.ScriptControl в современных реалиях разработки 1С — это мина замедленного действия. Давайте разберем по шагам, почему это так.

Библиотека msscript.ocx, которая обеспечивает работу этого COM-объекта, является устаревшим 32-разрядным (x86) компонентом Active X. Она поставлялась в составе операционных систем Windows и не имеет официальной 64-разрядной версии от Microsoft.

Как только ваша база данных 1С будет запущена на 64-битном сервере приложений (процессы rphost.exe) или пользователи начнут работать в 64-битных версиях тонкого или толстого клиента, конструктор:

ScrptCtrl = Новый COMОбъект("MSScriptControl.ScriptControl");

вызовет неустранимую ошибку выполнения: «Класс не зарегистрирован» (0x80040154). Это связано с тем, что 64-битный процесс не может напрямую загрузить в свое адресное пространство 32-битные динамические библиотеки (DLL).

Существуют обходные пути для решения этой проблемы, но все они усложняют архитектуру:

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

Разбор математики алгоритма дополнения до двух

Автор темы заимствовал алгоритм с популярного зарубежного ресурса для расчета контрольных сумм. Самым сложным фрагментом для переноса на язык 1С автору показалась следующая строка:

result = (~(result & 0xff) + 1) & 0xFF;

Давайте подробно проанализируем, что здесь происходит с точки зрения побитовой математики:

  1. result & 0xff — операция побитового «И» (AND) с маской 0xFF (255 в десятичной системе). Она отсекает все старшие биты числа, оставляя только младшие 8 бит (1 байт).
  2. ~(...) — побитовое отрицание «НЕ» (NOT). Оно инвертирует все биты числа. В компьютерной арифметике для знаковых чисел операция ~x эквивалентна математическому действию -x - 1.
  3. + 1 — прибавление единицы к инвертированному значению. Сочетание инверсии бит и прибавления единицы (~x + 1) — это классический способ получения отрицательного числа в двоичном коде (представление отрицательных чисел методом дополнения до двух). Математически это превращает число x в -x.
  4. Конечный & 0xFF — повторное наложение маски, чтобы гарантированно удержать результат в рамках одного байта (диапазон от 0 до 255).

Вся эта побитовая магия для 8-разрядного беззнакового целого числа сводится к простой арифметической формуле. Дополнение до двух для числа, ограниченного одним байтом, эквивалентно вычитанию этого числа из 256. Таким образом, на языке 1С формула принимает изящный вид:

Результат = (256 - (Сумма % 256)) % 256;

Здесь оператор остатка от деления % 256 заменяет операцию побитового «И» с маской 0xFF. Данная формула работает со 100% точностью и выдает абсолютно идентичные результаты для любых входных данных без использования сложных низкоуровневых функций.

Готовое решение на чистом коде 1С

Ниже представлен протестированный программный код на встроенном языке 1С, который полностью заменяет JScript-скрипт автора. Он производит побайтовый разбор HEX-строки (например, кода карты), суммирует значения байтов, рассчитывает дополнение до двух и возвращает результат в виде двухсимвольной шестнадцатеричной строки.


// Вычисляет 8-битное дополнение до двух (2's complement checksum) для HEX-строки.
// Полный аналог алгоритма с сайта planetimming (входной параметр КодКарты - например, "AABBCCDD")
Функция ВычислитьCRC8_Двухдополнение(Знач КодКарты) Экспорт
    
    // Очищаем входную строку от пробелов
    ЧистаяСтрока = СтрЗаменить(КодКарты, " ", "");
    
    // Проверяем длину hex-строки на четность
    Если СтрДлина(ЧистаяСтрока) % 2 <> 0 Тогда
        ВызватьИсключение "Некорректная длина HEX-строки (должно быть четное количество символов)";
    КонецЕсли;
    
    СуммаБайт = 0;
    Шаг = 2;
    
    // Побайтово разбираем hex-строку и суммируем десятичные значения байтов
    Для Позиция = 1 По СтрДлина(ЧистаяСтрока) / Шаг Цикл
        БайтСтрокой = Сред(ЧистаяСтрока, (Позиция - 1) * Шаг + 1, Шаг);
        
        // Преобразуем HEX-байт в десятичное число
        БайтЧислом = HexВДесятичное(БайтСтрокой);
        Если БайтЧислом = -1 Тогда 
            Возврат "Ошибка: обнаружены некорректные символы в HEX-строке";
        КонецЕсли;
        
        СуммаБайт = СуммаБайт + БайтЧислом;
    КонецЦикла;
    
    // Вычисляем дополнение до двух (2's complement) для 8 бит с помощью простой арифметики
    РезультатЧислом = (256 - (СуммаБайт % 256)) % 256;
    
    // Преобразуем результат обратно в HEX-представление
    Возврат ДесятичноеВHex(РезультатЧислом);
    
КонецФункции

// Вспомогательная функция перевода HEX-строки (длиной до 2 символов) в десятичное число
Функция HexВДесятичное(Знач СтрHEX)
    АлфавитHEX = "0123456789ABCDEF";
    СтрHEX = ВРег(СтрHEX);
    
    Результат = 0;
    Для НомерСимвола = 1 По СтрДлина(СтрHEX) Цикл
        Символ = Сред(СтрHEX, НомерСимвола, 1);
        ПозицияВАлфавите = Найти(АлфавитHEX, Символ);
        
        Если ПозицияВАлфавите = 0 Тогда
            Возврат -1; // Возвращаем признак ошибки, если символ не входит в шестнадцатеричный алфавит
        КонецЕсли;
        
        Результат = Результат * 16 + (ПозицияВАлфавите - 1);
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

// Вспомогательная функция перевода десятичного числа (0-255) в 2-значный HEX
Функция ДесятичноеВHex(Знач Число)
    АлфавитHEX = "0123456789ABCDEF";
    
    СтаршийРазряд = Цел(Число / 16);
    МладшийРазряд = Число % 16;
    
    СимволСтарший = Сред(АлфавитHEX, СтаршийРазряд + 1, 1);
    СимволМладший = Сред(АлфавитHEX, МладшийРазряд + 1, 1);
    
    Возврат СимволСтарший + СимволМладший;
КонецФункции

Преимущества перехода на чистый код 1С

Внедрение данного платформенного решения дает разработчику весомые преимущества:

  1. Полная независимость от разрядности: Код будет одинаково стабильно работать как на 32-битных клиентах, так и на мощных 64-битных серверах 1С.
  2. Кроссплатформенность: Поскольку решение не использует технологию COM, оно может беспрепятственно выполняться на серверах под управлением Linux, а также в мобильных клиентах 1С.
  3. Производительность: Исключаются накладные расходы на инициализацию скриптового движка, парсинг текстового представления JS-кода и сериализацию данных при передаче между процессами. Вычисления на встроенном языке 1С выполняются мгновенно.
  4. Простота отладки: Вы можете отслеживать состояние переменных СуммаБайт, РезультатЧислом непосредственно через стандартный отладчик 1С, заходя внутрь функций, что невозможно при работе с «черным ящиком» в виде COM-объекта JScript.
← На главную