Как разрабатывать нестандартные внешние компоненты для 1С и обходить ограничения платформы

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

Стандартная технология создания внешних компонент (ВК), предлагаемая фирмой 1С, накладывает ряд ограничений на разработчика: жесткий жизненный цикл объекта, ограниченные возможности по управлению интерфейсом и необходимость регистрации COM-объектов в реестре Windows. Однако, используя возможности языков низкого уровня (C++) и системные API операционной системы, мы можем выйти за эти рамки. В данной статье мы разберем, как внедрять собственный код в процесс 1С, управлять окнами платформы напрямую и обеспечивать стабильную работу модулей даже после их формального удаления в коде 1С.

Прямое взаимодействие с интерфейсом 1С через WinAPI

Рассмотрим ситуацию, когда стандартных средств отображения информации в 1С недостаточно (например, нужно отрисовать видео или динамическую графику поверх окон платформы). Вместо использования штатных объектов 1С мы можем применить технологию сабклассинга (subclassing). Разберем этот процесс по шагам:

  1. Получение дескриптора окна (HWND): В процессе инициализации ВК мы можем найти главное окно приложения 1С или окно конкретной формы. Для этого используются функции FindWindowEx или перебор дочерних окон через EnumChildWindows.
  2. Замена оконной процедуры: С помощью функции SetWindowLongPtr с флагом GWLP_WNDPROC мы подменяем стандартный обработчик сообщений окна на свою функцию. Это позволяет нам перехватывать системные события, такие как WM_PAINT (перерисовка), WM_SIZE (изменение размера) или события мыши.
  3. Отрисовка контента: Получив управление в момент перерисовки, мы можем использовать контекст устройства (HDC) и графические библиотеки (например, GDI+), чтобы рисовать произвольные элементы непосредственно на поверхности окна 1С.

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

Метод предотвращения выгрузки DLL из памяти процесса

Одной из проблем при работе с внешними компонентами в 1С 7.7 и 8.x является непредсказуемая или нежелательная выгрузка DLL. Когда объект в 1С уничтожается (переменная принимает значение Неопределено), платформа вызывает функцию FreeLibrary. Если вы запустили в компоненте фоновые потоки, это приведет к критической ошибке (Access Violation).

Выясним, как заблокировать выгрузку компоненты нестандартным способом. Рассмотрим решение, которое заключается в повторной загрузке библиотеки самой собой. В секции инициализации компоненты (например, в функции Init или DllMain) выполняется следующий код:


HMODULE hSelf = NULL;
char path[MAX_PATH];
GetModuleFileNameA(hInstance, path, MAX_PATH);
hSelf = LoadLibraryA(path);

Разберем механизм работы этого кода: функция LoadLibrary увеличивает счетчик ссылок модуля в операционной системе. Когда платформа 1С вызывает штатную FreeLibrary, счетчик уменьшается, но не достигает нуля, так как мы "удерживаем" одну лишнюю ссылку. В результате DLL остается в адресном пространстве процесса 1С до момента его завершения. Это позволяет безопасно завершать фоновые операции и сохранять перехваты сообщений (хуки) активными.

Использование COM-компонент без регистрации в реестре (Registration-Free COM)

Многие системные администраторы ограничивают права пользователей на запись в реестр (ветка HKEY_CLASSES_ROOT), что делает невозможным стандартное использование ПодключитьВнешнююКомпоненту для COM-объектов. Посмотрим на альтернативный способ использования технологии Side-by-Side (SxS).

Для реализации этого метода необходимо создать специальный файл манифеста (XML), который описывает компоненту, ее интерфейсы и CLSID. Если манифест включен в ресурсы DLL или расположен рядом с исполняемым файлом, операционная система позволит создать экземпляр объекта через CoCreateInstance, не обращаясь к реестру. В контексте 1С это можно реализовать через вызов GetClassObject напрямую из загруженной в память библиотеки, минуя стандартные механизмы COM-активации.

Особенности инициализации в новых версиях платформы (8.3.14 и выше)

В современных версиях платформы 1С разработчики могут столкнуться с тем, что код в секции DllMain выполняется в условиях Loader Lock, что накладывает серьезные ограничения (нельзя создавать потоки, загружать другие библиотеки и т.д.). Рассмотрим правильный алгоритм инициализации:

Проанализируем ситуацию: начиная с версии 8.3.14, платформа стала более строго следить за инициализацией. Если вы используете технологию Native API, всю логику по запуску дополнительных сервисов (видео-плееров, сетевых сокетов) необходимо переносить в метод Init интерфейса IComponentBase. Платформа гарантированно вызывает этот метод после того, как библиотека полностью загружена и все системные блокировки сняты.

Важный момент: если ваша компонента должна работать в фоновом режиме, рекомендуется использовать следующий паттерн для передачи событий в 1С:


// В основном потоке сохраняем указатель на IAsyncEvent
m_iEvent = (IAsyncEvent*)pInterface;

// В фоновом потоке вызываем событие
m_iEvent->ExternalEvent(L"MyComponent", L"StatusUpdate", L"Success");

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

← На главную