Разработка внешних компонент для платформы 1С:Предприятие на языке C# (.NET) — популярное решение, когда базовых возможностей встроенного языка не хватает. Однако разработчики часто сталкиваются с ситуацией: в толстом клиенте на компьютере разработчика всё работает прекрасно, но при попытке упаковать библиотеку в ZIP-архив (макет) и подключить её в тонком клиенте или на сервере через функцию ПодключитьВнешнююКомпоненту, платформа возвращает Ложь.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем разницу между технологиями COM и Native API, выясним роль среды выполнения CLR и рассмотрим современные, надежные способы развертывания .NET-компонент без предварительной ручной регистрации в операционной системе.
Посмотрим на представленный в теме код. Разработчик создал класс AddIn, который реализует интерфейсы IInitDone, ILanguageExtender, IAsyncEvent и IStatusLine. Эти интерфейсы имеют строго определенные GUID (например, [Guid("AB634001-F13D-11d0-A459-004095E1DAEA")]).
Главная архитектурная ошибка заключается в путанице технологий. Описанные интерфейсы — это классическая технология COM (Component Object Model), созданная Microsoft. Она использовалась в 1С еще со времен версии 7.7. Технология Native API, появившаяся позже, устроена совершенно иначе: она кроссплатформенная, не использует COM-интерфейсы, системный реестр Windows и GUID.
Когда разработчик пытается выполнить следующий код:
НачатьПодключениеВнешнююКомпоненты(ОбработчикПодключения, "ОбщийМакет.testDll", "Component", ТипВнешнейКомпоненты.Native);
Платформа 1С ожидает, что внутри динамической библиотеки (DLL) будут находиться экспортируемые функции C-формата (такие как GetClassObject, DestroyObject). Но так как библиотека написана на C# и скомпилирована под COM, этих точек входа в ней нет. Платформа не может их обнаружить и возвращает ошибку подключения.
Выясним причину, почему в толстом клиенте вызовы завершались успешно. На компьютере разработчика компонента была предварительно зарегистрирована в операционной системе с помощью утилиты regasm.exe или через настройки Visual Studio (Register for COM interop).
При ручной регистрации в реестре Windows Windows прописывается информация о ProgID и пути к файлу. В этом случае, даже если в коде 1С написано подключение из макета, платформа при неудаче локального поиска обращается к системному реестру, находит там зарегистрированный COM-класс и успешно создает объект. Но на компьютерах пользователей, где ручная регистрация не проводилась, этот механизм сразу же ломается.
Рассмотрим подробнее механизм работы 1С с COM-компонентами из макета:
DllRegisterServer.DllRegisterServer. Регистрация таких библиотек должна осуществляться утилитой regasm.exe, которая создает в реестре Windows ссылки на общеязыковую среду выполнения (CLR / mscoree.dll). 1С вызывать regasm.exe в процессе работы не умеет и не имеет для этого прав администратора.Таким образом, полноценное автоматическое подключение стандартной .NET COM-библиотеки через макет силами одной лишь платформы 1С невозможно.
---
Проанализируем три основных архитектурных подхода, которые позволяют решить данную задачу и запустить C# код на стороне клиента или сервера.
С выходом современных версий платформы .NET (начиная с .NET 7 и .NET 8) появилась технология Native AOT (Ahead-Of-Time). Она компилирует код C# напрямую в машинный код целевой операционной системы (Windows, Linux, macOS). Полученная DLL не требует установленного .NET Runtime на целевом компьютере и ведет себя как классическая библиотека, написанная на C++ или Rust.
Благодаря этому мы можем объявить внутри C# необходимые точки экспорта для 1С Native API с помощью атрибута [UnmanagedCallersOnly].
Рассмотрим пример реализации экспорта основных функций Native API на C#:
using System;
using System.Runtime.InteropServices;
namespace MyNativeComponent
{
public static class Exports
{
[UnmanagedCallersOnly(EntryPoint = "GetClassNames")]
public static IntPtr GetClassNames()
{
// Возвращаем имена классов, поддерживаемых компонентой (в формате UTF-16/WCHAR)
return Marshal.StringToCoTaskMemUni("MyComponentClass");
}
[UnmanagedCallersOnly(EntryPoint = "GetClassObject")]
public static int GetClassObject(IntPtr className, ref IntPtr classObject)
{
string name = Marshal.PtrToStringUni(className);
if (name == "MyComponentClass")
{
// Создаем экземпляр нашего класса, реализующего IComponentBase
var component = new MyComponent();
classObject = Marshal.GetComInterfaceForObject<MyComponent, IComponentBase>(component);
return 0; // S_OK
}
return -1; // E_FAIL
}
[UnmanagedCallersOnly(EntryPoint = "DestroyObject")]
public static int DestroyObject(ref IntPtr classObject)
{
if (classObject != IntPtr.Zero)
{
Marshal.Release(classObject);
classObject = IntPtr.Zero;
return 0; // S_OK
}
return -1; // E_FAIL
}
}
}
При таком подходе библиотека упаковывается в ZIP-архив с манифестом Manifest.xml следующего вида:
<?xml version="1.0" encoding="UTF-8"?>
<component xmlns="http://v8.1c.ru/8.2/addon/bundle">
<component xmlns="http://v8.1c.ru/8.2/addon/bundle" type="native" path="MyNativeComponent.dll" os="Windows" arch="i386" />
<component xmlns="http://v8.1c.ru/8.2/addon/bundle" type="native" path="MyNativeComponent_x64.dll" os="Windows" arch="x86_64" />
</component>
Эта компонента без проблем подключится методом ПодключитьВнешнююКомпоненту в любом клиенте 1С (включая веб-клиент или Linux-сервер, если собрать соответствующую версию библиотеки под Linux ELF).
Если вам необходимо работать в рамках .NET Framework (например, требуется совместимость со старым кодом или специфичными библиотеками) и Native AOT вам не подходит, можно использовать гибридный подход.
Суть метода заключается в следующем:
1cv8.exe тонкого клиента или rphost.exe сервера).Этот подход успешно реализован во многих публичных проектах (например, компоненты класса NETLoader). Для разработчика на 1С это выглядит как прозрачная работа с .NET-кодом без какой-либо предварительной регистрации библиотек в Windows.
Если вы хотите оставить архитектуру COM (использование интерфейсов IInitDone и ILanguageExtender) и подключать компоненту через Новый COMОбъект, но при этом избежать вызова утилиты regasm.exe с правами администратора на каждом клиентском компьютере, можно настроить технологию RegFree COM.
Для этого выполняются следующие шаги:
Важное ограничение: Данный метод крайне сложно использовать совместно с динамической распаковкой из общего макета 1С, поскольку 1С распаковывает файлы во временные папки с уникальными непредсказуемыми путями, а файлы манифестов жестко завязаны на относительные или абсолютные пути расположения DLL.
---
Подведем итог. Попытка загрузить .NET COM-библиотеку напрямую через макет с типом Native или COM без предварительной системной регистрации всегда будет завершаться ошибкой. Для решения этой проблемы выберите один из путей:
regasm.exe на целевых серверах/компьютерах с помощью групповых политик (GPO) или скриптов инсталляции.