При разработке сложных систем на платформе 1С часто возникает необходимость расширить стандартный функционал с помощью внешних компонент. Одной из наиболее актуальных задач является создание универсальной компоненты, которая будет корректно работать как на 32-битных клиентских местах (тонкий клиент), так и на 64-битных серверах (процесс rphost). В этой статье мы подробно разберем процесс создания такой компоненты с использованием Visual Studio и технологии Native API.
Для начала разберем важный технический момент: как заставить проект компилироваться под разные операционные системы и разрядности. Платформа 1С может работать в разных режимах, и разрядность компоненты (DLL) должна строго соответствовать разрядности процесса, который её вызывает. Если у пользователя установлен 32-битный тонкий клиент, ему нужна 32-битная библиотека. Если код выполняется на стороне сервера 1С (64-битного), потребуется 64-битная версия.
Разберем по шагам настройку в Visual Studio:
x64 для создания 64-битной версии компоненты. Для 32-битной версии обычно используется x86 или Win32.При использовании шаблонов с ИТС мы сталкиваемся с необходимостью реализации обязательных методов. Проанализируем структуру методов CallAsProc и CallAsFunc. Если ваша компонента должна выполнять действие (например, инициализировать перехват печати) и возвращать результат, мы используем CallAsFunc. Если же возвращаемое значение не требуется — пишем код в CallAsProc.
Проанализируем ситуацию, когда метод не используется. Просто удалить его из кода нельзя, так как это нарушит структуру виртуальной таблицы объектов C++. В этом случае следует оставить пустую реализацию, которая возвращает false или код ошибки ADDIN_E_NOTIMPL.
Рассмотрим пример управления памятью: При передаче строк в 1С крайне важно использовать менеджер памяти, предоставляемый самой платформой. Рассмотрим фрагмент кода:
// Пример использования IMemoryManager для выделения памяти под строку
wchar_t* dest = nullptr;
if (m_iMemory->AllocMemory((void**)&dest, (strLen + 1) * sizeof(wchar_t)))
{
wcscpy(dest, sourceString);
// Теперь этот указатель можно безопасно передать в 1С
}
Помним, что платформа 1С работает со строками в формате UTF-16 (тип wchar_t в C++), поэтому при преобразовании данных из системных функций Windows нужно быть внимательными с кодировками.
Чтобы 1С понимала, какую именно библиотеку загружать, нам не нужно создавать разные макеты в конфигурации под каждую ОС. Правильный подход — использование единого архива с файлом манифеста. Выясним, как должна выглядеть структура ZIP-файла:
Component32.dll — ваша скомпилированная библиотека x86.Component64.dll — ваша скомпилированная библиотека x64.Manifest.xml — описание содержимого для платформы 1С.Разберем структуру файла Manifest.xml. Этот файл является связующим звеном:
<?xml version="1.0" encoding="UTF-8"?>
<bundle xmlns="http://v8.1c.ru/8.2/addin/bundle">
<component os="Windows" project="i386" path="Component32.dll" type="native" />
<component os="Windows" project="x86_64" path="Component64.dll" type="native" />
</bundle>
Здесь атрибут project="i386" указывает на 32-битную версию, а project="x86_64" — на 64-битную. Платформа 1С автоматически прочитает этот файл и выберет нужный файл DLL в зависимости от окружения, в котором запущен сеанс.
После того как архив готов, переходим в конфигуратор 1С. Создадим общий макет с типом Двоичные данные и назовем его, например, КомпонентаПерехватаПечати. Загрузим в него наш созданный ZIP-архив.
Теперь разберем программный код для подключения компоненты. Использование метода СистемнаяИнформация для ручного определения ОС, как предлагалось в обсуждении, является избыточным при наличии манифеста. Платформа сделает это за нас.
Рассмотрим правильный алгоритм подключения:
// 1. Установка компоненты из макета во временное хранилище пользователя
РезультатУстановки = УстановитьВнешнююКомпоненту("ОбщийМакет.КомпонентаПерехватаПечати");
Если РезультатУстановки Тогда
// 2. Подключение компоненты. Имя "MyComponent" используется для обращения к объекту
ПодключитьВнешнююКомпоненту("ОбщийМакет.КомпонентаПерехватаПечати", "PrintHook", ТипВнешнейКомпоненты.Native);
// 3. Создание объекта
ОбъектКомпоненты = Новый("ВнешняяКомпонента.PrintHook");
Иначе
Сообщить("Не удалось установить компоненту");
КонецЕсли;
Важный нюанс: Если вы планируете перехватывать печать из окна предварительного просмотра (интерфейсная задача), подключать компоненту нужно НаКлиенте. Если же компонента должна выполнять вычисления на сервере, вызов должен происходить в серверном контексте.
Задача автора по перехвату печати из формы «Предварительный просмотр» является нетривиальной. Стандартное Native API 1С не имеет встроенных событий для отслеживания кликов по кнопкам в системных диалогах платформы. Для реализации этой логики внутри C++ кода компоненты обычно используются возможности Windows API:
SetWindowsHookEx позволяет отслеживать сообщения в очередях событий окон. Это позволяет «поймать» момент нажатия кнопки «Печать».Print Spooler API для отслеживания появления новых заданий на печать, инициированных процессом 1cv8.exe.Проанализируем риски: работа с хуками требует глубокого понимания потоков Windows. Поскольку компонента загружается прямо в процесс 1С, любая критическая ошибка в C++ коде приведет к немедленному закрытию (аварийному завершению) всей программы 1С. Поэтому всегда используйте блоки try...catch и тщательно проверяйте указатели на nullptr.
Многие начинающие разработчики задаются вопросом: как проверить работу кода, если 1С уже запущена? Для этого в Visual Studio предусмотрен механизм Attach to Process (Отладка -> Присоединиться к процессу):
1cv8c.exe.rphost.exe (учтите, что на сервере может быть несколько таких процессов).После присоединения вы сможете расставлять точки останова (breakpoints) прямо в коде C++, и при вызове метода из 1С отладчик остановит выполнение на нужной строке. Это значительно ускоряет поиск ошибок и проверку логики работы с памятью.
Таким образом, мы проанализировали полный цикл создания внешней компоненты: от настройки проекта и выбора архитектуры до упаковки в манифест и загрузки в конфигурацию 1С. Соблюдение этих правил обеспечит стабильную работу вашего расширения в любых клиент-серверных окружениях.