Разработка внешних компонент на .NET (C#) для 1С 8.2
#1
Отправлено 21 февраля 2012 - 08:55
Суть проблемы следующая:
Для решения поставленной задачи необходимо разработать внешнюю компоненту (.dll) (.NET C# VS08) и обрабатывать в 1С (8.2) внешнее событие, генерируемое этой компонентой.
С регистрацией компоненты в Windows с помощью RegAsm.exe проблем нет (в реестр добавляется запись, классы компоненты там есть).
Подключение компоненты в 1С по ProgID тоже проходит успешно, а вот при попытке создать экземпляр - выдает ошибку следующего содержания "{Обработка.ТестВнешнейКомпоненты.Форма.Форма.Форма(56)}: Тип не определен (AddIn.TestDLL3)".
Мною изучено:
http://www.gotdotnet...sanshin-R/6626/
http://www.gotdotnet...forums/2/53505/
http://www.forum.mis....php?id=436704/
Выкладывать исходники не вижу смысла, потому что даже ни один из примеров, приведенных по этим ссылкам, я не смог привести в работоспособное состояние... (Ошибка аналогичная.) Да и метод научного тыка себя уже порядком исчерпал.
Может кто знает, какие подводные камни могут встретиться в подобных разработках? В чём может быть моя проблема ? Или, хотя бы, приведите, пожалуйста, работоспособные примеры разработанных внешних компонент.
Буду очень благодарен любой помощи или консультации.
Заранее, спасибо!
#2
Отправлено 21 февраля 2012 - 09:30
Как подключаете?
Не было ли ничего полезного в гугле при поиске по словам "Тип не определен (AddIn."?
#3
Отправлено 21 февраля 2012 - 10:21
#4
Отправлено 22 февраля 2012 - 10:02
[CODE]
RegAsm.exe TestDLL3.dll /codebase /tlb: TestDLL3.tlb
@pause
[/CODE]
Потом испльзую обработку(не внешнюю), функция выглядит:
&НаКлиенте Процедура Подключить() Попытка Если ПодключитьВнешнююКомпоненту("AddIn.TestDLL3") = 1 Тогда //Plugin = Новый ("AddIn.TestDLL3"); Предупреждение("Component AddIn.TestDLL3 successfuly loaded"); Иначе Предупреждение("Component AddIn.TestDLL3 not found"); КонецЕсли; Исключение Предупреждение("Error while loading AddIn.TestDLL3"); КонецПопытки; КонецПроцедуры
Тут всё работает успешно, функции интерфейса IInitDone() отрабатывают.
А вот когда я пытаюсь создать экземпляр:
&НаКлиенте Процедура Action() Попытка Plugin = Новый ("AddIn.TestDLL3"); Исключение Plugin = 0; Предупреждение(ОписаниеОшибки()); КонецПопытки; Если Plugin<>0 Тогда Plugin.TestExtEvent("Test"); КонецЕсли; КонецПроцедурыстрока Plugin = Новый ("AddIn.TestDLL3") вылетает с ошибкой.
Выгугливание данной проблемы дает мнго вариатов решения(загрузка компоненты в макет, регистрация), но мне пока что ничего из этого не помогло. И нигде не могу найти рабочий проект.
#5
Отправлено 22 февраля 2012 - 10:07
Может как то так
Плагин = Новый COMОбъект("AddIn.TestDLL3");
#6
Отправлено 22 февраля 2012 - 12:37
uza (22 февраля 2012 - 10:07) писал:
Может как то так
Плагин = Новый COMОбъект("AddIn.TestDLL3");
Как результат, ошибка с неопределенным типом излечилась, но теперь я не могу обработать внешнее событие, которое генерируется компонентой...
Можешь поподробнее рассказать про этот аспект?
Насколько я понял, читая 1с-форумы, в 8.2 существует 2 вида внешних компонент COM и Native.
СОМ объекты не позволяют отлавливать внешние события и вообще крайне ограничены в своей функциональности.
В найденных примерах, которые якобы являются рабочими, использовались компоненты Native и как раз синтаксис вида
Plugin = Новый ("AddIn.TestDLL3");
Код генерации события
public void TestExtEvent([MarshalAs(UnmanagedType.BStr)] string Msg) { System.Windows.Forms.MessageBox.Show("Creation event"); try { HOST.evt.ExternalEvent(@"External Event", @"AddIn.TestDLL3", @"Returning " + Msg); System.Windows.Forms.MessageBox.Show("Event Created"); } catch { throw new COMException(@"Failed to execute TestExtEvent() method"); } }
Сообщение отредактировал alexburn: 22 февраля 2012 - 12:41
#7
Отправлено 24 февраля 2012 - 11:35
Яж быдлокодер на 1Сках и бэйсиках. И вообще моя родина - Индусия.
#8
Отправлено 26 февраля 2012 - 14:31
Plugin = Новый ("AddIn.TestDLL3");должен быть не ProgID, а пространство имен. Т.е. когда вы во внешней компоненте реализовали интерфейс ILanguageExtender, то в процедуре RegisterExtensionAs этого интерфейса вы же возвращаете пространство имен. Оно и должно быть указано аргументом в функции Новый, например:
Plugin = Новый ("AddIn.MyFirstAddIn");
#9
Отправлено 27 февраля 2012 - 07:52
shurikvz (26 февраля 2012 - 14:31) писал:
Plugin = Новый ("AddIn.TestDLL3");должен быть не ProgID, а пространство имен. Т.е. когда вы во внешней компоненте реализовали интерфейс ILanguageExtender, то в процедуре RegisterExtensionAs этого интерфейса вы же возвращаете пространство имен. Оно и должно быть указано аргументом в функции Новый, например:
Plugin = Новый ("AddIn.MyFirstAddIn");
В примерах, которые приведены по ссылкам, про этот интерфейс не сказано ни слова, и я не реализовал его.
Сейчас читаю http://www.rsdn.ru/a...dotnet/cs1c.xml, но тут тоже много белых пятен: отсутствие реализации метода RegisterExtensionAs и многих других.
Буду очень благодарен за помощь!
#10
Отправлено 27 февраля 2012 - 10:07
Смотрите, все зависит от того, что у вас будет делать компонента. Если из 1С вы туда никакие данные передавать не будете, то достаточно в компоненте реализовать интерфейс IInitDone, и все.
Т.е. чтобы было понятно как работает, сделайте следующее: пишите реализацию интерфейса IInitDone (там всего 3 метода), при этом в метод Init() этого интерфейса вставляете запуск таймера (Timer), ну допустим с интервалом 5 сек (не принципиально). В событии срабатывания таймера шлете "HOST.evt.ExternalEvent(@"External Event", @"AddIn.TestDLL3", @"Returning ");".
С компонентой все (зарегистрировать ее не забудьте).
А в обработке 1С просто при открытии пишите ПодключитьВнешнююКомпоненту("AddIn.TestDLL3"); И в обработчике формы ОбработкаВнешнегоСобытия(Источник, Событие, Данные) - ловите свое событие. Все. Кстати подключать компоненту надо всего один раз. Т.е. она будет подключена пока полностью не закроете 1С:Предприятие (клиентскую часть).
Но такой простой вариант - вряд ли возможен. Вам же надо наверно все-таки как-то общаться с компонентой (что-то ей посылать). Тогда без реализации ILanguageExtender не обойтись.
Пример - есть в этой статье на rsdn, он рабочий, я проверял. Если выкрою чуть-чуть времени - постараюсь накатать статью с примером и выложить.
#11
Отправлено 27 февраля 2012 - 10:44
#12
Отправлено 27 февраля 2012 - 12:40
Как я уже писал, методы интерфейса IInitDone отрабатывают у меня отлично, причём все, в том числе и Done() при закрытии клиента. Проблема возникает, когда я пытаюсь вызвать метод класса компоненты, который не входит в стандартные интерфейсы(думал даже может его туда надо вписать). Как человек имеющий некоторое представление об ООП, я пытаюсь создать экземпляр класса в 1С и тут сталкиваюсь с указанной ошибкой, так что видимо без интерфейса ILanguageExtender мне никак не обойтись.
За статью с примерами, думаю, многие будут очень благодарны, потому что реально актуальной информации в интернете я сейчас найти не могу на эту тему.
З.Ы. По поводу статьи: непонятно, где объявляются переменные, которые инициализируются в методе RegisterExtensionAs... Как я понял из статьи, для vs2003 эта проблема решается наследованием класса от ServicedComponent, или нет ? Разъясни, пожалуйста, этот момент.
#13
Отправлено 27 февраля 2012 - 13:23
KimboSlice (27 февраля 2012 - 12:40) писал:
public class Component : IInitDone
{
Hashtable nameToNumber;
Hashtable numberToName;
Hashtable numberToParams;
Hashtable numberToRetVal;
и т.д.
public void RegisterExtensionAs([MarshalAs(UnmanagedType.BStr)] ref String extensionName)
{
try
{
// initialize data members
nameToNumber = new Hashtable();
numberToName = new Hashtable();
numberToParams = new Hashtable();
numberToRetVal = new Hashtable();}
и т.д.
Проще говоря логика реализации этой процедуры в статье на rsdn следующая: она перебирает все интерфейсы класса внешней компоненты, для "системных интерфейсов" (таких как IDisposable, IManagedObject, IServicedComponentInfo и.т.д.) и обязательных для внешней компоненты 1С (таких как IInitDone, ILanguageExtender) мы ничего не делаем, а для всех остальных берем методы описанные в этих интерфейсах, и собственно получаем из них: имя метода, количество параметров и т.д. Нам это необходимо для полной реализации интерфейса ILanguageExtender (т.е. посмотри на остальные методы объявленные в этом интерфейсе - нам необходимо будет возвращать количество процедур, количество параметров в процедуре, искать процедуру по имени). Можно было и "в ручную" прописывать это в соответствующих функциях (т.е. условно например для HRESULT GetNProps(long *plProps)):
Если ИмяМетода = "а" То КоличествоПараметров = 1; ИначеЕсли ИмяМетода = "б" То КоличествоПараметров = 3; КонецЕсли; Возврат КоличествоПараметров;Но так как сделано в том примере ведь намного "красивее".
Ну и вот. Исходя из вышесказанного, помимо всего того, что описано в статье надо будет сделать одну вещь: описываешь свой интерфейс с нужными функциями (теми которые будешь вызывать), наследуешь класс компоненты дополнительно от этого интерфейса, ну и естественно в классе надо не забыть реализовать методы объявленного интерфейса. Т.е. условно получится:
public interface MyMethods //<------- { public void TestExtEvent([MarshalAs(UnmanagedType.BStr)] string Msg); }наследуете и реализуете:
public class Component : ServicedComponent, IInitDone, ILanguageExtender, MyMethods //<------- { .... public void TestExtEvent([MarshalAs(UnmanagedType.BStr)] string Msg) { System.Windows.Forms.MessageBox.Show("Creation event"); try { HOST.evt.ExternalEvent(@"External Event", @"AddIn.TestDLL3", @"Returning " + Msg); System.Windows.Forms.MessageBox.Show("Event Created"); } catch { throw new COMException(@"Failed to execute TestExtEvent() method"); } } }
После этого метод TestExtEvent можно будет вызвать в 1С.
#14
Отправлено 27 февраля 2012 - 13:41
#15
Отправлено 27 февраля 2012 - 16:00
extensionName = componentName;Вот эта строчка в методе, но переменной componentName значение нигде не присваивается, поясните пожалуйста, какое значение нужно присвоить componentName, я так понимаю это должна быть связка <пространство имен компоненты>.<имя класса>
#16
Отправлено 27 февраля 2012 - 16:16
KimboSlice (27 февраля 2012 - 16:00) писал:
extensionName = componentName;Вот эта строчка в методе, но переменной componentName значение нигде не присваивается, поясните пожалуйста, какое значение нужно присвоить componentName
Plugin = Новый ("AddIn.<вот здесь>");
Например напишите в с#:
extensionName = "MySuperPuperAddIn";значит в 1С будете создавать как:
Plugin = Новый("AddIn.MySuperPuperAddIn");
З.Ы. Тот комментарий о котором я писал к статье (в #14 сообщении) - не совсем рабочий, проверил. Во первых нет наследования от класса ILanguageExtender (без этого не работает), и во вторых определение внешней процедуры отдельным классом - тоже не работает (ну у меня не заработало по крайней мере) (надо реализовывать через интерфейс, как я писал в #13).
#17
Отправлено 27 февраля 2012 - 16:16
componentName = "AddIn.TestDLL3"; extensionName = componentName;Всё прошло на ура, экземпляр класса был создан успешно, и метод
public void TestExtEvent([MarshalAs(UnmanagedType.BStr)] string Msg)
{
System.Windows.Forms.MessageBox.Show("Creation event");
try
{
HOST.evt.ExternalEvent(@"External Event", @"AddIn.TestDLL3", @"Returning " + Msg);
System.Windows.Forms.MessageBox.Show("Event Created");
}
catch
{
throw new COMException(@"Failed to execute TestExtEvent() method");
}
}
успешно был вызван и отработал без ошибок, но внешнее событие 1С-ка не поймала... С чем это может быть связано ?Нужно ли чтобы класс наследовал интерфейс IAsyncEvent ?
Сообщение отредактировал KimboSlice: 27 февраля 2012 - 16:18
#18
Отправлено 27 февраля 2012 - 16:21
KimboSlice (27 февраля 2012 - 16:16) писал:
KimboSlice (27 февраля 2012 - 16:16) писал:
#19
Отправлено 28 февраля 2012 - 12:07
Теперь столкнулся с другой проблемой: в функционал разрабатываемой компоненты входит прослушивание порта и в генерация события, в случае поступления определенной информации. Изначально этот функционал был реализован в .net приложении, и там всё это работало методом создания стороннего потока, в котором прослушивался порт, а в основной поток данные передавались с помощью соответствующего делегата. Так вот при создании потока в компоненте, 1С-ка виснет. Может кто знает с чем это связано ? И как организуются такие задачи в целом ?
#20
Отправлено 28 февраля 2012 - 13:29
KimboSlice (28 февраля 2012 - 12:07) писал:
KimboSlice (28 февраля 2012 - 12:07) писал:
Количество пользователей, читающих эту тему: 1
0 пользователей, 1 гостей, 0 анонимных









