Как разработать внешнюю компоненту на C# для 1С для работы с COM-портом и внешними событиями

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

Разработка внешних компонент на языке C# для платформы 1С:Предприятие — это эффективный способ расширить возможности системы, когда стандартных средств встроенного языка недостаточно. Чаще всего это требуется для низкоуровневой работы с оборудованием, например, с COM-портами сканеров штрихкодов или картридеров. В данной статье мы подробно разберем процесс создания такой компоненты, механизм передачи данных через внешние события и устраним типичные ошибки, возникающие при регистрации и инициализации объектов.

Структура проекта внешней компоненты на C#

Для начала создадим проект в Microsoft Visual Studio с типом Библиотека классов (.NET Framework). Чтобы 1С могла взаимодействовать с нашей библиотекой как с внешней компонентой, нам необходимо реализовать COM-интерфейсы. Рассмотрим базовую структуру класса, который будет отвечать за работу с торговым оборудованием.

Проанализируем пример кода, в котором описывается основной интерфейс и класс компоненты. Важно использовать атрибуты Guid и ProgId, чтобы система могла однозначно идентифицировать наш объект в реестре Windows.


[GuidAttribute("0E2BFC3D-7FF8-4bb8-AC4D-2FAA332B80A3")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
public interface IWorkCompsMain
{
    string Version { get; }
}

[Guid("38B5DCD1-8FE9-4a46-B9C3-C9A1CD60F6E4")]
[ProgId("AddIn.CardReaderMR2000")]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComVisible(true)]
public class CardReader : ExtComponentBase, IWorkCompsMain
{
    private SerialPort sp;
    private string inputData = "";

    public CardReader()
    {
        ComponentName = "CardReaderMR2000";
    }

    [Export1c]
    public void Initialization()
    {
        sp = new SerialPort();
        sp.PortName = "COM4";
        sp.BaudRate = 9600;
        sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
        sp.Open();
    }
}

Обратите внимание на использование атрибута [Export1c]. Это кастомный атрибут, который часто применяется в базовых шаблонах (например, от RSDN) для автоматического экспорта методов и свойств в метаданные 1С. Без правильной реализации интерфейса ILanguageExtender 1С не "увидит" ваши методы.

Регистрация компоненты в операционной системе

После сборки проекта (Build) мы получаем DLL-файл. Для работы через COM его необходимо зарегистрировать. Выясним важный нюанс: разрядность утилиты регистрации должна совпадать с разрядностью клиентского приложения 1С. Если вы используете 32-битный клиент 1С (что является стандартом для большинства конфигураций на обычных формах), регистрацию нужно проводить через 32-битную версию regasm.exe, даже если ОС 64-битная.

Выполним регистрацию следующей командой от имени администратора:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe "D:\DLL\New.dll" /codebase /tlb

Параметр /codebase позволяет регистрировать библиотеку, не помещая её в GAC (Global Assembly Cache), что значительно упрощает процесс разработки и тестирования. Параметр /tlb создает библиотеку типов, которая может быть полезна для отладки.

Подключение компоненты в коде 1С

Рассмотрим два способа создания объекта. Первый способ — через механизм Новый COMОбъект. Этот метод позволяет обращаться к свойствам и методам, но не позволяет получать внешние события, так как 1С не инициализирует интерфейс обратного вызова.

Правильный способ для получения событий — использование метода УстановитьВнешнююКомпоненту или ПодключитьВнешнююКомпоненту. Разберем по шагам правильную последовательность действий в 1С:


// 1. Подключаем библиотеку
Результат = ПодключитьВнешнююКомпоненту("AddIn.CardReaderMR2000");

Если Результат Тогда
    // 2. Создаем экземпляр объекта
    Попытка
        ОбъектВК = Новый("AddIn.CardReaderMR2000");
        ОбъектВК.Initialization();
    Исключение
        Сообщить("Не удалось создать объект компоненты!");
    КонецПопытки;
КонецЕсли;

Если при вызове Новый("AddIn...") возникает ошибка "Тип не определен", это означает, что ProgID в коде C# не совпадает с тем, что вы указываете в 1С, либо регистрация прошла неудачно. Проверьте ветку реестра HKEY_CLASSES_ROOT на наличие вашего ProgId.

Генерация внешнего события (ExternalEvent)

Самая сложная часть — передача данных из фонового потока (чтение из порта) в основной поток 1С. В .NET событие DataReceived возникает в отдельном потоке. Если попытаться вызвать метод 1С напрямую, это может привести к аварийному завершению программы (Crash).

Проанализируем код внутри C#, который отвечает за отправку события:


void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    string data = sp.ReadExisting();
    // Важно: Async - это ссылка на интерфейс IAsyncEvent, 
    // которую 1С передает в метод Init() компоненты.
    if (this.Async != null)
    {
        this.Async.ExternalEvent("AddIn.CardReaderMR2000", "CardData", data);
    }
}

В 1С это событие будет перехвачено в процедуре ВнешнееСобытие формы или модуля приложения:


Процедура ВнешнееСобытие(Источник, Событие, Данные)
    Если Источник = "AddIn.CardReaderMR2000" Тогда
        Сообщить("Получены данные с карты: " + Данные);
    КонецЕсли;
КонецПроцедуры

Типичные проблемы и их решения

  1. Ошибка "Недостаточно фактических параметров": Часто возникает в обычных формах 1С при вызове методов без параметров. Убедитесь, что в C# методе нет необязательных аргументов, и в базовом классе компоненты правильно реализован метод GetNParams. В некоторых случаях помогает добавление фиктивного параметра в метод на стороне C#.
  2. Объект Async равен null: Это происходит, если объект был создан через Новый COMОбъект. Используйте только Новый("AddIn.Имя") после предварительного подключения компоненты.
  3. Вылет 1С (1cv8.exe) при получении данных: Это классическая проблема потокобезопасности. 1С не всегда корректно обрабатывает входящие COM-вызовы из сторонних потоков. Рекомендуется использовать потокобезопасные очереди или механизмы синхронизации (например, Control.Invoke, если есть скрытое окно, или специализированные обертки для 1С).
  4. Проблема разрядности: Помните, что 64-битная 1С не может загрузить 32-битную DLL и наоборот. При компиляции в Visual Studio лучше явно указывать целевую платформу (Target Framework: x86 или x64), а не "Any CPU".

Выясним еще один момент: при разработке на C# крайне важно корректно завершать работу с COM-портом. Обязательно реализуйте метод Close() или Dispose(), чтобы при закрытии 1С порт не оставался заблокированным в системе, что предотвратит ошибки при повторном запуске приложения.

Соблюдение этих правил позволит вам создать надежную и быструю внешнюю компоненту, которая обеспечит стабильную связь 1С с любым внешним оборудованием через COM-интерфейс.

← На главную