При интеграции платформы 1С 7.7 со сторонними библиотеками на платформе .NET разработчики часто сталкиваются с ошибками вида отсутствует CLSID или отсутствует интерфейс IInitDone. Выясним причину этой проблемы: в 1С 7.7 существует принципиальная разница между специализированной Внешней Компонентой (ВК) и стандартным COM-объектом (ActiveX/Automation).
Когда разработчик пишет обычный класс на C# и пытается подключить его методом ЗагрузитьВнешнююКомпоненту() или ПодключитьВнешнююКомпоненту(), 1С ожидает найти реализацию строгих внутренних интерфейсов платформы (таких как IInitDone, ILanguageExtender). Если этих интерфейсов в библиотеке нет, платформа выдает ошибку. Разберем по шагам, как правильно оформить и подключить библиотеку C# к 1С 7.7, а также рассмотрим альтернативные способы выполнения XSLT-трансформации.
Если перед нами стоит задача выполнить прикладные расчеты или преобразования (например, трансформацию XML), реализовывать сложный интерфейс внешней компоненты IInitDone нет никакой необходимости. Достаточно экспортировать класс C# как стандартный COM-сервер и обращаться к нему через обычный метод 1С СоздатьОбъект().
Проанализируем требования к исходному коду на C#:
XmlDocument) напрямую в 1С 7.7 нельзя.Console.WriteLine, Console.ReadLine), так как 1С 7.7 запускается в оконном режиме GUI и не имеет консольного ввода-вывода. Попытка вызвать чтение из консоли может привести к глухому зависанию программы.Посмотрим на пример правильной реализации класса на C#:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml;
using System.Xml.Xsl;
namespace MyXsltLib
{
[Guid("68F9ECEF-B19A-4F8B-AE0F-47B16180D52C")]
[ComVisible(true)]
public interface ITransform
{
string StartTest();
string DoTransform(string xmlFilePath, string xsltFilePath);
}
[Guid("F62AA00E-235B-488C-BD81-D7A8470B3EDF")]
[ProgId("MyXsltLib.Transform")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Transform : ITransform
{
public Transform()
{
}
public string StartTest()
{
return "Тестирование прошло успешно";
}
public string DoTransform(string xmlFilePath, string xsltFilePath)
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltFilePath);
using (StringWriter writer = new StringWriter())
{
using (XmlReader reader = XmlReader.Create(xmlFilePath))
{
xslt.Transform(reader, null, writer);
}
return writer.ToString();
}
}
}
}
Разберем процесс сборки и регистрации компоненты в операционной системе:
x86 (или Any CPU с отключенной опцией Prefer 32-bit). Сборка под x64 в 1С 7.7 работать не будет.regasm.exe строго из 32-разрядного каталога .NET Framework, добавив параметры /codebase и /tlb для экспорта библиотеки типов:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe /codebase /tlb "C:\PathToDll\MyXsltLib.dll"
Теперь обратимся к библиотеке из кода 1С 7.7. Обратите внимание: команды ЗагрузитьВнешнююКомпоненту() и ПодключитьВнешнююКомпоненту() здесь не используются. Создание происходит напрямую по зарегистрированному идентификатору ProgId:
Перем Трансформер, Результат;
Попытка
Трансформер = СоздатьОбъект("MyXsltLib.Transform");
Исключение
Сообщить("Не удалось создать COM-объект MyXsltLib.Transform: " + ОписаниеОшибки(), "!");
Возврат;
КонецПопытки;
// Проверяем работу метода
Сообщить(Трансформер.StartTest());
// Выполняем XSLT-преобразование
Результат = Трансформер.DoTransform("D:\1.xml", "D:\3.xsl");
Сообщить("Преобразование завершено, длина ответа: " + СтрДлина(Результат));
Рассмотрим подробнее задачу трансформации XML. Для применения шаблонов XSLT не обязательно разрабатывать собственную сборку на C#. В составе операционной системы Windows уже присутствует мощный COM-парсер MSXML2.DOMDocument, который штатно поддерживается в 1С 7.7.
Посмотрим на пример выполнения преобразования напрямую из встроенного языка 1С 7.7:
Перем XMLДок, XSLДок, РезультатТрансформации;
XMLДок = СоздатьОбъект("MSXML2.DOMDocument.6.0");
XMLДок.async = 0;
XMLДок.resolveExternals = 0;
Если XMLДок.load("D:\1.xml") = 0 Тогда
Сообщить("Ошибка загрузки XML: " + XMLДок.parseError.reason, "!");
Возврат;
КонецЕсли;
XSLДок = СоздатьОбъект("MSXML2.DOMDocument.6.0");
XSLДок.async = 0;
XSLДок.resolveExternals = 0;
Если XSLДок.load("D:\3.xsl") = 0 Тогда
Сообщить("Ошибка загрузки XSLT: " + XSLДок.parseError.reason, "!");
Возврат;
КонецЕсли;
// Выполняем трансформацию
РезультатТрансформации = XMLДок.transformNode(XSLДок);
Сообщить("Результат успешно получен:");
Сообщить(РезультатТрансформации);
Если логика на C# сложна или на рабочих станциях пользователей ограничены права администратора (из-за чего нельзя зарегистрировать библиотеку в реестре утилитой regasm), можно скомпилировать проект как исполняемый файл (.exe). Запуск такого приложения из 1С выполняется через объект WScript.Shell с ожиданием завершения процесса:
Перем WshShell, КоманднаяСтрока, КодВозврата;
WshShell = СоздатьОбъект("WScript.Shell");
КоманднаяСтрока = """C:\PathToApp\XsltConverter.exe"" ""D:\1.xml"" ""D:\3.xsl"" ""D:\out.xml""";
// Третий параметр 1 означает ожидание завершения работы утилиты
КодВозврата = WshShell.Run(КоманднаяСтрока, 0, 1);
Если КодВозврата = 0 Тогда
Сообщить("Файл успешно преобразован!");
Иначе
Сообщить("Произошла ошибка при выполнении конвертера. Код ошибки: " + КодВозврата, "!");
КонецЕсли;
Таким образом, если требуется взаимодействие через библиотеки типов, создавайте класс с атрибутами [ComVisible(true)] и подключайте его через СоздатьОбъект(). Если же задача ограничивается обработкой XML и XSLT, проще и надежнее использовать встроенный системный парсер MSXML2.DOMDocument.