Внешняя компонента 1С++ (1C++) является ключевым инструментом для расширения возможностей платформы 1С:Предприятие 7.7. Она позволяет выполнять прямые SQL-запросы к базе данных, использовать объектно-ориентированное программирование (ООП) прямо во встроенном языке и создавать продвинутые интерфейсные элементы. Однако при переходе со старых версий (например, 2.0.x.x) на современную ветку 3.x разработчики регулярно сталкиваются с рядом технических сложностей.
В этой статье мы подробно разберем, как правильно установить актуальную версию 1С++, настроить её работу на современных операционных системах, решить проблему разделения с компонентой FormEx, а также рассмотрим практические примеры работы с индексированными таблицами и написания оптимальных прямых SQL-запросов.
В процессе развития проекта финальной, наиболее стабильной и общепринятой в профессиональном сообществе версией из линейки 3.x стала сборка 3.2.4.3. Хотя на официальном сайте в качестве "рекомендуемой" долгое время указывалась версия 2.5, для работы с современными СУБД и операционными системами необходимо использовать ветку 3.x.
Для удобства разработки в Конфигураторе вам обязательно понадобятся файлы синтакс-помощника (формат .als). Без них написание кода превратится в постоянное подглядывание в веб-документацию. Чтобы подключить актуальную подсказку, выполните следующие шаги:
1c++.als для третьей версии компоненты.BIN) либо в каталог базы данных в папку ExtForms.Для ещё более комфортной разработки рекомендуется использовать среду расширения Конфигуратора OpenConf совместно с плагином Visual 1C++ (vis1cpp.dll). Данный плагин автоматически парсит файл описания классов defcls.prm вашей конфигурации и предоставляет полноценное автодополнение кода (IntelliSense) "на лету".
При переносе баз данных 1С 7.7 на современные операционные системы (Windows Server 2012 R2, 2016, 2019, 2022 или Windows 10/11) системные администраторы часто сталкиваются с внезапными падениями программы без объяснения причин. Проанализируем основные технические нюансы, которые необходимо учесть:
А. Настройка DEP (Data Execution Prevention)
Функция предотвращения выполнения данных (DEP) на уровне операционной системы является главным виновником "тихих" вылетов платформы 1С 7.7 при использовании низкоуровневых перехватов вызовов, которые делает 1С++. Чтобы решить эту проблему, обязательно добавьте исполняемые файлы платформы 1cv7.exe и 1cv7s.exe в список исключений DEP в свойствах системы (вкладка «Дополнительно» -> раздел «Быстродействие» -> «Предотвращение выполнения данных»). В некоторых случаях на терминальных серверах DEP приходится отключать полностью через командную строку.
Б. Правильная регистрация библиотеки 1cpp.dll
Пытаться зарегистрировать библиотеку вручную через системную утилиту regsvr32 не нужно — это часто вызывает ошибки несовместимости окружения. Компонента отлично регистрируется динамически при первом обращении в коде:
Если ЗагрузитьВнешнююКомпоненту("1cpp.dll") = 0 Тогда
Предупреждение("Критическая ошибка: Не удалось загрузить компоненту 1С++!");
КонецЕсли;
Важный нюанс: Для успешной первичной регистрации библиотеке требуются права на запись в ветку системного реестра HKEY_CLASSES_ROOT\Addin.1C++. Поэтому самый первый запуск 1С после обновления библиотеки на сервере необходимо произвести под учетной записью локального администратора компьютера (через контекстное меню «Запуск от имени администратора»). После однократной успешной регистрации все рядовые пользователи смогут работать в системе без повышенных прав.
В. Зависимости Visual C++ Redistributable
Версия 1С++ 3.x компилировалась более современными средствами разработки, нежели старая версия 2. Поэтому для её корректной работы на "чистой" операционной системе может потребоваться предварительная установка пакетов распространяемых библиотек Visual C++ Redistributable x86 (версий 2005 и 2008).
Выясним ключевое архитектурное различие между линейками версий. В версии 2.0 внешняя компонента FormEx (которая отвечает за расширенную работу с экранными формами, табличными полями, раскраску таблиц и перехват событий клавиатуры/мыши) была жестко интегрирована внутрь файла 1cpp.dll.
Начиная с версии 3.0, разработчики полностью разделили эти компоненты. В версии 1С++ 3.x функционала FormEx больше нет! Если вы просто замените файл 1cpp.dll в рабочей базе, весь ваш интерфейсный код перестанет работать.
Чтобы безболезненно выполнить переход, сделайте следующее:
FormEx.dll (рекомендуется использовать стабильные сборки, например, 2.0.5.124 или 2.0.5.198).ПриНачалеРаботыСистемы() пропишите последовательную загрузку обеих компонент:
Процедура ПриНачалеРаботыСистемы()
// Загружаем 1С++ для работы с прямыми запросами и классами
Если ЗагрузитьВнешнююКомпоненту("1cpp.dll") = 0 Тогда
Сообщить("Ошибка загрузки 1cpp.dll!", "!");
КонецЕсли;
// Загружаем FormEx для работы с формами и табличными полями
Если ЗагрузитьВнешнююКомпоненту("FormEx.dll") = 0 Тогда
Сообщить("Ошибка загрузки FormEx.dll!", "!");
КонецЕсли;
КонецПроцедуры
Осторожно: Избегайте ситуаций, когда в системе одновременно пытаются загрузиться старая версия 1С++ (со встроенным FormEx) и новая отдельная библиотека FormEx.dll. Это вызовет конфликт адресов в оперативной памяти и приведет к аварийному завершению работы 1С.
Рассмотрим ситуацию, когда нам необходимо выполнить сложный прямой SQL-запрос к базе данных и быстро обработать его результаты в коде. Стандартный метод возвращает обычную Таблицу Значений платформы 1С, поиск по которой на больших объемах данных работает крайне медленно.
Компонента 1С++ предоставляет великолепную альтернативу — объект ИндексированнаяТаблица. Этот объект работает в разы быстрее стандартной таблицы за счет построения внутренних индексов по нужным колонкам.
Посмотрим на пример того, как получить индексированную таблицу значений напрямую из метода ВыполнитьИнструкцию() класса ODBCRecordSet:
// Создаем объект для выполнения прямого запроса
ЗапросSQL = СоздатьОбъект("ODBCRecordset");
ТекстЗапроса = "
|SELECT
| Товар as [Товар $Справочник.Номенклатура],
| Остаток as Количество
|FROM
| $РегистрИтоги.ОстаткиТоваров
|";
// Вместо создания пустой ТЗ, передаем вторым параметром новый объект "ИндексированнаяТаблица"
ИндексированнаяТЗ = ЗапросSQL.ВыполнитьИнструкцию(ТекстЗапроса, СоздатьОбъект("ИндексированнаяТаблица"));
// Теперь мы можем моментально построить индекс по колонке "Товар" и выполнять быстрый поиск
ИндексированнаяТЗ.ЗаполнитьИндексы("Товар");
Передача объекта ИндексированнаяТаблица вторым параметром указывает компоненте на необходимость сразу типизировать возвращаемый результат в памяти. Это избавляет разработчика от долгого ручного переноса данных из стандартной таблицы значений и позволяет сразу применять методы быстрого поиска и фильтрации.
Разберем классическую задачу: нам нужно получить данные из табличной части конкретного документа с помощью прямого запроса через класс ODBCRecordSet. Для этого необходимо связать таблицу шапки документа, таблицу его строк (табличной части) и общую таблицу журнала документов для фильтрации по периоду.
В СУБД MS SQL Server для баз данных 1С 7.7 связь осуществляется по уникальному внутреннему идентификатору документа — полю IDDoc. Посмотрим на пример реализации такого запроса:
ЗапросSQL = СоздатьОбъект("ODBCRecordset");
// Передаем границы периода в параметрах запроса
ЗапросSQL.УстановитьТекстовыйПараметр("НачДата", ВыбНачДата);
ЗапросSQL.УстановитьТекстовыйПараметр("КонДата", ВыбКонДата);
ТекстЗапроса = "
|SELECT
| SUM($ДокС.Сумма) as Сумма,
| Док.IDDoc as [Докум $Документ.Реализация]
|FROM
| $ДокументСтроки.Реализация as ДокС
|INNER JOIN
| $Документ.Реализация as Док ON Док.IDDoc = ДокС.IDDoc
|INNER JOIN
| _1SJourn as Жур ON Жур.IDDoc = ДокС.IDDoc AND
| Жур.Date_Time_IDDoc BETWEEN :НачДата AND :КонДата~ AND
| Жур.Closed & 1 = 1
|GROUP BY
| Док.IDDoc
|";
// Выполняем инструкцию и получаем готовую таблицу результатов
ТаблицаРезультатов = ЗапросSQL.ВыполнитьИнструкцию(ТекстЗапроса);
Проанализируем особенности этого SQL-запроса:
$ДокументСтроки.Реализация — это метаимя 1С++, которое автоматически преобразуется в реальное имя таблицы табличной части документа в SQL-базе (например, DT321).$Документ.Реализация — метаимя, преобразующееся в таблицу шапки документа (например, DH321).ON Док.IDDoc = ДокС.IDDoc объединяет строки табличной части с соответствующей шапкой документа._1SJourn (Журнал документов) используется для проверки периода проведения документов. Конструкция :КонДата~ автоматически преобразует дату конца периода в формат даты-времени конца дня со всеми миллисекундами, чтобы не потерять документы, проведенные в последнюю секунду дня.Жур.Closed & 1 = 1 отбирает только проведенные документы.При построении продвинутых интерфейсов разработчики часто используют элемент «Табличное Поле» (из компоненты FormEx). Распространенная проблема: при интерактивном переключении строк в табличном поле срабатывает предопределенное событие активизации строки, код отрабатывает, данные считываются, но текстовые элементы на форме (например, комментарий к текущему документу) визуально не обновляются.
Проанализируем ситуацию. Платформа 1С 7.7 не всегда автоматически перерисовывает элементы формы, если изменения значений переменных произошли внутри обработчиков событий внешних компонент. Чтобы заставить форму немедленно отобразить новые данные, необходимо явно вызвать метод принудительного обновления экрана.
Рассмотрим правильный код обработчика события активизации строки табличного поля:
Процедура ТППриАктивизацииСтроки(оТП)
// Получаем индекс текущей выбранной строки табличного поля
ТекСтр = оТП.ТекущаяСтрока;
// Получаем объект документа из нашей исходной таблицы данных
Док = ТЗ.ПолучитьЗначение(ТекСтр, "Док");
// Присваиваем значение переменной, которая выведена в виде текста на форме
Каммент = Док.Комментарий;
// Важнейший шаг: принудительно заставляем форму обновить элементы интерфейса
Форма.Обновить(1);
КонецПроцедуры
Передача параметра 1 в метод Форма.Обновить() указывает платформе на необходимость выполнить глубокое синхронное обновление всех элементов управления формы без задержек. Это гарантирует, что пользователь моментально увидит актуальный комментарий при перемещении курсора по списку документов.