При разработке систем интеграции между 1С и внешними приложениями (например, на языке C#) программисты часто сталкиваются с неочевидным поведением платформы при использовании COM-соединения (V83.COMConnector или V82.COMConnector). Одной из самых коварных ошибок является NullReferenceException с текстом «Ссылка на объект не указывает на экземпляр объекта» на стороне вызывающего приложения. Давайте подробно разберем, почему это происходит и как устранить проблему.
Рассмотрим стандартную ситуацию: ваше приложение на C# подключается к базе 1С и пытается выполнить создание документа следующей строкой кода:
dynamic dr = connection1C.Документы.РеализацияТоваровУслуг.СоздатьДокумент();
Если в этот момент возникает ошибка «Ссылка на объект не указывает на экземпляр объекта», это означает, что метод СоздатьДокумент() вернул null вместо объекта документа. В 1С метод СоздатьДокумент сам по себе не может вернуть null — он либо создает объект, либо генерирует исключение. Однако при работе через COM-интерфейс, если в момент инициализации объекта происходит критический сбой компиляции модуля, платформа не может инициализировать COM-объект и возвращает пустое значение в вызывающую среду.
Ключевой момент: При вызове СоздатьДокумент() система 1С выполняет компиляцию всего модуля объекта, а также проверяет доступность всех общих модулей, к которым этот код обращается. Если в модуле есть синтаксические ошибки или обращения к недоступным в данном контексте процедурам, объект не будет создан.
Разберем ситуацию, когда разработчики внесли изменения в конфигурацию: добавили новый общий модуль или изменили существующий. Если в модуле объекта документа есть вызов функции из общего модуля, у которого в свойствах не стоит галочка «Внешнее соединение», то при попытке создания документа через COM произойдет ошибка компиляции. Контекст внешнего соединения просто «не видит» этот модуль.
Для решения этой проблемы выполним следующие действия:
Часто в модулях объектов 1С (особенно в старых конфигурациях на обычных формах) встречается код, вызывающий диалоговые окна, вопросы пользователю или формы. Во внешнем соединении (COM) интерфейсная часть полностью отсутствует. Попытка вызвать процедуру Предупреждение() или Вопрос() приведет к немедленному падению сессии.
Проанализируем пример кода, который может вызвать проблему:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Ошибочный код для COM-соединения
Если ДанныеЗаполнения = Неопределено Тогда
Предупреждение("Данные не заполнены!");
КонецЕсли;
КонецПроцедуры
Чтобы избежать ошибок, мы должны использовать инструкции препроцессора. Рассмотрим, как правильно переписать такой код:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
#Если Не ВнешнееСоединение Тогда
Если ДанныеЗаполнения = Неопределено Тогда
Предупреждение("Данные не заполнены!");
КонецЕсли;
#КонецЕсли
КонецПроцедуры
Использование директивы #Если Не ВнешнееСоединение Тогда гарантирует, что интерактивный код будет проигнорирован при подключении через COM-коннектор, и компиляция модуля пройдет успешно.
Многие разработчики пытаются обернуть создание документа в блок Попытка на стороне 1С, надеясь поймать ошибку, но это не помогает. Выясним причину: блок Попытка...Исключение обрабатывает ошибки времени выполнения (runtime). Ошибка отсутствия модуля или неверного контекста является ошибкой компиляции. Платформа 1С не может начать выполнение кода внутри блока Попытка, так как она не может скомпилировать сам контейнер (модуль объекта), где этот код находится. Именно поэтому выполнение «вылетает» еще до входа в алгоритм обработки ошибок.
Если визуальный осмотр кода не помогает, воспользуемся механизмом отладки внешних соединений. Это позволит нам точно увидеть, на какой строке и в каком модуле происходит сбой.
-debug).СоздатьДокумент() из C# выполнение остановится в 1С, и вы сможете пошагово пройти весь процесс инициализации.При использовании dynamic для работы с COM-объектами ошибки часто маскируются. Рассмотрим более надежный способ обработки исключений на стороне .NET, который поможет получить детальную информацию:
try
{
dynamic dr = connection1C.Документы.РЛ.СоздатьДокумент();
if (dr == null)
{
throw new Exception("1С вернула Null при создании объекта. Проверьте компиляцию модуля объекта.");
}
}
catch (System.Runtime.InteropServices.COMException ex)
{
// Здесь можно проанализировать ex.ErrorCode или ex.Message
Console.WriteLine("Ошибка COM: " + ex.Message);
}
Также не забывайте о корректном завершении сессии. Чтобы избежать зависших процессов 1cv8.exe в памяти сервера, всегда используйте принудительное освобождение объекта связи:
System.Runtime.InteropServices.Marshal.ReleaseComObject(connection1C);
Для стабильной работы создания объектов через COM-соединение необходимо соблюдать три правила:
#Если Не ВнешнееСоединение Тогда.Соблюдение этих принципов позволит вам избежать трудноуловимых ошибок и обеспечит надежную интеграцию между вашими программными продуктами и платформой 1С.