|
Внешняя компонента для 1с 8.2 на C# | ☑ | ||
---|---|---|---|---|
0
vudo
26.09.13
✎
13:24
|
Когда-то писал внешние компоненты для 1С.
Я наверное за два года что-то упустил :( Был у меня базовый класс для создания внешних компонент: ExtComponentBase (где брал уже не помню, но работало) Сейчас написал компоненту: namespace Comps { [GuidAttribute("3E00A8B5-817B-4cd8-8859-098216D9EBC7")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [ComImport] public interface IWorkCompsMain { string Version { get; } } [Guid("8D3D2B33-97B7-4ce6-8BBB-4D687BC5BFC3")] [ClassInterface(ClassInterfaceType.None)] [Transaction(TransactionOption.RequiresNew)] [ProgId("Comps")] public class Comps : ExtComponentBase, IWorkCompsMain { private string _version = ""; [Export1c] public string Version { get { return _version; } set { _version = value; } } public Comps() { ComponentName = "Comps"; _version = "100"; } } } Подписал строгим именем, выполнил: echo --------------------------------------------------- C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe "%~dp0/Comps.dll" /codebase C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen.exe install "%~dp0/Comps.dll" echo --------------------------------------------------- echo Done. pause Все прошло замечательно! Дальше из 1С (Толстый клиент - Управляемое) Попытка Загружено = ПодключитьВнешнююКомпоненту("D:\1C_DATA\OS\Внешняя компонента\Service\Comps\Comps\bin\Release\Comps.dll","Comps",ТипВнешнейКомпоненты.COM); Исключение Сообщить(ОписаниеОшибки()); КонецПопытки; Если Загружено Тогда ВК = Новый("Comps"); КонецЕсли; И тут ошибка: Тип не определен (Comps)! Какого не могу второй день понять... Кто знает? |
|||
49
H A D G E H O G s
27.09.13
✎
11:56
|
(47) Это же через ISink2 ?
А есть пример на Дельфях? |
|||
50
H A D G E H O G s
27.09.13
✎
11:58
|
(48) Интересно, для обработки этого 1С создает отдельный поток.
Надо будет поэкспериментировать. |
|||
51
Принт
27.09.13
✎
12:01
|
(34) буэ на ваш мавзолей
|
|||
52
Serginio1
27.09.13
✎
12:02
|
(49) На дельфях там все просто.
В потоке инициализируем поток. В Net там немного сложнее, да и с используя SynchronizationContext проще не думать о проблемах CoInitialize(nil); PEvent.ExternalEvent('Socket1C',Host,'"ПолучитьДанныеИЗстрокиИзСоккета"'); CoUnInitialize(); |
|||
53
Serginio1
27.09.13
✎
12:04
|
(49) Нет для этого не создает. Но вот если событие срабатыватся в другом потоке, нужно позаботьться что бы вызов был в потоке 1С
|
|||
54
vudo
27.09.13
✎
12:06
|
(46) Интересует не столько данная конкретная задача, сколько идеология в целом.
(48) Хм. Рекомендуешь использовать ActiveX? ДобавитьОбработчик мда много я пропустил... Надо будет покрутить. Спасибо. Но ушли в сторону.И все таки. Как получить многопоточность в 1с? |
|||
55
H A D G E H O G s
27.09.13
✎
12:07
|
(52) Что это?
Я хотел узнать, как реализовать отправку события из ВК, чтобы 1С его отловила через ДобавитьОбработчик Компонента.onsocketread,ПриПолученииДанных; |
|||
56
H A D G E H O G s
27.09.13
✎
12:08
|
(54) Как получить многопоточность в 1с?
CreateThread() Ваш К.О. |
|||
57
Serginio1
27.09.13
✎
12:11
|
(54) ты 37 внимательней посмотри. Там sp.DataReceived срабатыват при получении данных берет поток из пула потока и выполняет делегат
(sender, e) => { SerialPort sp1 = (SerialPort)sender; string indata = sp1.ReadExisting(); Sc.Send(d => EventTo1C.ExternalEvent("ДанныеОтСканера", sp1.PortName, indata), null); }; (55) Давно не брал я в руки Delphi. Но все тоже создаешь Event и подключаешься. Посмотри примеры по ActiveX. |
|||
58
vudo
27.09.13
✎
12:11
|
(56) Что-то вроде многопоточности...
На самом деле вопрос только в том куда в управляемой форме запихнуть значение ВК. Так что бы экзепляр объекта существовал пока открыта форма. |
|||
59
H A D G E H O G s
27.09.13
✎
12:13
|
(58) В Клиентскую переменную
|
|||
60
H A D G E H O G s
27.09.13
✎
12:14
|
&НаКлиенте
Перем ОбъектЗвук; &НаКлиенте Процедура ПриОткрытии(Отказ) ОбъектЗвук=Новый ("Addin.V8ADD.Sounds"); КонецПроцедуры |
|||
61
Serginio1
27.09.13
✎
12:29
|
||||
62
vudo
27.09.13
✎
12:40
|
(60) Спасибо.
|
|||
63
Serginio1
27.09.13
✎
13:02
|
(55) Вспомнил
http://www.sql.ru/forum/932430/activex-s-sobytiyami нужно реализовать IConnectionPointContainer http://www.compress.ru/article.aspx?id=10600&part=index21ext1 |
|||
64
H A D G E H O G s
27.09.13
✎
13:12
|
(63) Вооо, спасибо!
А то всякие COM+ |
|||
65
Serginio1
27.09.13
✎
13:35
|
Да http://users.atw.hu/delphicikk/listaz.php?id=2611&oldal=12
И подлючение в Вордовскому идет через IConnectionPointContainer procedure StartWordConnection(WordApp: _Application; WordDoc: _Document; var WordSink: TWordConnection); var PointContainer: IConnectionPointContainer; Point: IConnectionPoint; begin try { TWordConnection is the COM object which receives the notifications from Word. Make sure to free WordSink when you are done with it. } WordSink := TWordConnection.Create; WordSink.WordApp := WordApp; WordSink.WordDoc := WordDoc; // Sink with a Word application OleCheck(WordApp.QueryInterface(IConnectionPointContainer, PointContainer)); if Assigned(PointContainer) then begin OleCheck(PointContainer.FindConnectionPoint(ApplicationEvents, Point)); if Assigned(Point) then Point.Advise((WordSink as IUnknown), WordSink.AppCookie); end; // Sink with a Word document OleCheck(WordDoc.QueryInterface(IConnectionPointContainer, PointContainer)); if Assigned(PointContainer) then begin OleCheck(PointContainer.FindConnectionPoint(DocumentEvents, Point)); if Assigned(Point) then Point.Advise((WordSink as IUnknown), WordSink.DocCookie); end; except on E: Exception do ShowMessage(E.Message); end; end; |
|||
66
Serginio1
27.09.13
✎
13:59
|
||||
67
Serginio1
27.09.13
✎
14:17
|
||||
68
vudo
27.09.13
✎
15:20
|
А как сделать SetBufferEvent?
Сделал так: public bool SetBufferEvent(long depth) { return this.Async.SetEventBufferDepth(depth); } и в интерфейсах: public interface IAsyncEvent { /// Установка глубины буфера событий /// <param name="depth">Buffer depth</param> bool SetEventBufferDepth(long depth); /// Получение глубины буфера событий /// <param name="depth">Buffer depth</param> void GetEventBufferDepth(ref long depth); /// Посылка события /// <param name="source">Event source</param> /// <param name="message">Event message</param> /// <param name="data">Event data</param> void ExternalEvent( [MarshalAs(UnmanagedType.BStr)] String source, [MarshalAs(UnmanagedType.BStr)] String message, [MarshalAs(UnmanagedType.BStr)] String data ); /// Очистка буфера событий void CleanBuffer(); } из 1с: ВК.SetBufferEvent(300); Пишет не достаточно фактических параметров. Что не так? |
|||
69
vudo
27.09.13
✎
15:23
|
Ах да и еще в ExtComponentBase:
//интерфейс вызова событий в 1с protected IAsyncEvent Async { get { return asyncevent; } } |
|||
70
vudo
27.09.13
✎
15:53
|
забыл к методу добавить атрибут [Export1c]
|
|||
71
Serginio1
27.09.13
✎
16:03
|
SetEventBufferDepth тебе нужен из ВК
Описание: Устанавливает размер очереди событий для данного объекта. Если текущее количество событий в очереди больше устанавливаемой длины, последние события обрезаются. HRESULT ExternalEvent(BSTR bstrWho, BSTR bstrWhat, BSTR bstrData) Помещает событие в очередь, записывая источник события, наименование и параметры события. При обработке события эти данные передаются процедуре ОбработкаВнешнегоСобытия. При вызове метода ExternalEvent дальнейшая обработка события происходит следующим образом: событие записывается в очередь событий (если очередь полностью занята, событие теряется), затем при отсутствии системных событий из очереди берется первое событие (если очередь не пуста) и вызывается соответствующая функция ОбработкаВнешнегоСобытия. Этот процесс повторяется для всех объектов внешних компонент. Таким образом, обработка внешних событий синхронизируется с обработкой системных событий. Если у тебя Данные больше чем буфер то они обрезаются. Выход задать нужный размер, или записывать данные в свойство, откуда уже брать из 1С. |
|||
72
vudo
27.09.13
✎
16:09
|
(71)Да спасибо я уже сделал.
Атрибут забыл прописать методу. Теперь последняя проблема никак не удается запустить метод ассинхронно. 1С после вызова метода блокируется, пока неотработаются события порожденные этим методом. Х.з. что делать... Вызываю так: CompsListDelegate sd = GetList; IAsyncResult asyncRes = sd.BeginInvoke(new AsyncCallback(getedComps), null); где private void GetList() { NameGeting(); } и в свою очередь: public event NameGetingHandler NameGeting; Ну вот какого?!!! |
|||
73
vudo
27.09.13
✎
16:18
|
Уже не знаю с какой стороны и подползти...
Уже вроде все перепробовал. Должно же работать. Или оно отслеживает после вызова метода живой поток или нет? Так вроде в разных потоках ассинхронные вызовы выполняются... Как???? |
|||
74
Serginio1
27.09.13
✎
16:21
|
getedComps покажи
|
|||
75
H A D G E H O G s
27.09.13
✎
16:21
|
(73) Подползи со стороны Дельфи.
Там все делается 10 строчками кода из WinAPI |
|||
76
vudo
27.09.13
✎
16:24
|
(74)
private void getedComps(IAsyncResult result) { // } :) |
|||
77
vudo
27.09.13
✎
16:25
|
(75) Ну ты фанат. :)))
|
|||
78
Serginio1
27.09.13
✎
16:27
|
Проверь AppDomain.GetCurrentThreadId ()
(76) Ну и ни очем не говорит? CompsListDelegate dlgt = (CompsListDelegate ) ar.AsyncState; // Complete the call. s = dlgt.EndInvoke ( result) ; |
|||
79
Serginio1
27.09.13
✎
16:28
|
У тебя поток запускается но ничего не делает
|
|||
80
Serginio1
27.09.13
✎
16:31
|
(75) в C# еще проще через
Task.Factory.StartNew(() => { GetList()); }); Или по старинке new Thread(() => { GetList() }).Start(); |
|||
81
Serginio1
27.09.13
✎
16:36
|
||||
82
vudo
27.09.13
✎
16:37
|
(79) Ну как это не делает?
CompsListDelegate sd = GetList; Готовит на выполнение GetList IAsyncResult asyncRes = sd.BeginInvoke(new AsyncCallback(getedComps), null); Запускает выполнение getedComps - это обратный вызов(после завершения выполнения GetList). GetList() - замечательно выполняется! Иначе у меня бы вообще ничего в 1с не передавало бы... |
|||
83
vudo
27.09.13
✎
16:39
|
(81) Задачи спасибо покурю.
Но вот почему ассинхронные вызовы 1с так странно обрабатвыает? Хочется разобраться... |
|||
84
H A D G E H O G s
27.09.13
✎
16:46
|
(83) Ты не поверишь, сколько странного есть в 1С.
|
|||
85
H A D G E H O G s
27.09.13
✎
16:52
|
Например, размещение гиганского табличного документа в памяти.
Блоками по 16 мегабайт в созданных кучах, при этом, после очистки данного документа - кучи не удаляются, не ресайзятся, а тупо резервируются. Если заново открыть этот док - эти кучи снова задействуются, но попытка выделить память под что-то другое - ведет к падению по памяти (если не хватает памяти на создание новых куч). |
|||
86
Serginio1
27.09.13
✎
16:57
|
(83) где у тебя в getedComps
dlgt.EndInvoke ( result) |
|||
87
Serginio1
27.09.13
✎
16:59
|
Это дает, то что GetList() выполняется в потоке вызвавшем getedComps
|
|||
88
vudo
27.09.13
✎
18:02
|
(86) Я был уверен, что getedComps будет вызван в любом случае и передан делегату где будет подписка, а если подписки нет, то ничего не произойдет.
Вообщем-то я это проверял. Если в консоле запускаешь так как описано, Main идет до конца, хотя выполнение идет дальше, и консоль "умерает" только после того как завершится последняя команда из GetList(); Сейчас не могу, но сегодня попробую прямо указать выполнение в другом потоке и грохнуть породивший поток. |
|||
89
vudo
27.09.13
✎
18:04
|
(85) Гы... Если все будет гладко выполняться, то мощностей компьютеров пяти летней давности для 8-мки с головой. А кто китайского производителя поддержит?
|
|||
90
vudo
27.09.13
✎
18:06
|
(88) А дошло! Подписка в этом же потоке! Че-то туплю...
|
|||
91
vudo
30.09.13
✎
15:12
|
Нихрена не получается!
1С-ка блокируется пока живой хоть из одного потоков, а потом вываливает весь список внешних событий! Пробовал по всякому: //==== и так ===== new Thread(delegate() { GetList(); }).Start(); //==== и так ===== CompsListDelegate sd = GetList; IAsyncResult asyncRes = sd.BeginInvoke(new AsyncCallback(getedComps), null); //==== и так ===== Task.Factory.StartNew(() => { GetList(); }); Фантазия кончается... Как запустить метод асинхронно для 1С-ки??????? |
|||
92
H A D G E H O G s
30.09.13
✎
15:26
|
ППЦ.
Я ОбъектОбработку помещал в отдельный поток ВК, запускал ее экспортную процедуру, она там обсчитывала все, при этом выводя в окно сообщений (не стоит так делать) и давая работать с 1С параллельно. |
|||
93
vudo
30.09.13
✎
15:40
|
Гы. Сделал таймер:
public Comps() { ComponentName = "Comps"; NamesAll += new NamesAllHandler(onNamesAll); NameGet += new NameGetHandler(onNameGet); NameGeting += new NameGetingHandler(onNameGeting); //System.Threading.Timer tm = new System.Threading.Timer(); object state = null; tm = new System.Threading.Timer(new TimerCallback(TimerProc),state,0,5000); } кал на его срабатывание: private void TimerProc(object state) { if (startedList) { startedList = false; GetList(); } } При срабатывании блокирует 1С... Теперь точно уже все. Что системную службу писать? Это же бред! Хотя может попробовать в другом классе отлавливать?.. Счас! |
|||
94
vudo
30.09.13
✎
15:40
|
+ Ан нет смысла нету. Какая разница какой класс будет 1с-ку вешать...
|
|||
95
Serginio1
30.09.13
✎
16:08
|
Покажи GetList();
|
|||
96
Serginio1
30.09.13
✎
16:09
|
Покажи весь код вызова метода вызываемого из 1С
|
|||
97
vudo
30.09.13
✎
16:10
|
Все я 1Суку довел до истерики. Уходит в дамп когда из другого класса вызываю делегата на который подписаны события класса компоненты...
|
|||
98
vudo
30.09.13
✎
16:10
|
(96) Счас.
|
|||
99
vudo
30.09.13
✎
16:14
|
[Guid("8D3D2B33-97B7-4ce6-8BBB-4D687BC5BFC3")]
[ClassInterface(ClassInterfaceType.None)] [Transaction(TransactionOption.RequiresNew)] [ProgId("Addin.Comps")] public class Comps : ExtComponentBase, IWorkCompsMain { private string _version = ""; List<string> _listComps; public event NameGetHandler NameGet; public event NameGetingHandler NameGeting; public event NamesAllHandler NamesAll; private bool startedList; private SynchronizationContext Sc; [Export1c] public string Version { get { return _version; } set { _version = value; } } [Export1c] public List<string> ListComps { get { return _listComps; } set { _listComps = value; } } protected virtual void OnNameGet(string compName, string ipAdress) { NameGet(compName, ipAdress); } protected virtual void OnNamesAll(bool allOk) { NamesAll(allOk); } private void onNamesAll(bool allOk) { this.Async.ExternalEvent("onNamesAll", "done", "done"); } private void onNameGet(string compName, string ipAdress) { this.Async.ExternalEvent("onNameGet", "done Name", compName + ":" + ipAdress); } private void onNameGeting() { List<string> listComps = new List<string>(); ShellItem folder = new ShellItem((Environment.SpecialFolder)CSIDL.NETWORK); IEnumerator<ShellItem> e = folder.GetEnumerator(SHCONTF.FOLDERS); while (e.MoveNext()) { listComps.Add(e.Current.ParsingName); ListComps = listComps; OnNameGet(e.Current.ParsingName, ""); } OnNamesAll(true); } [Export1c] public void SetBufferEvent(Int32 depth) { this.Async.SetEventBufferDepth(depth); } public Comps() { ComponentName = "Comps"; NamesAll += new NamesAllHandler(onNamesAll); NameGet += new NameGetHandler(onNameGet); NameGeting += new NameGetingHandler(onNameGeting); } private void TimerProc(object state) { if (startedList) { startedList = false; GetList(); } } private void GetList() { NameGeting(); } [Export1c] public void GetListComs() { GetList(); //CompsListDelegate sd = GetList; //IAsyncResult asyncRes = sd.BeginInvoke(new AsyncCallback(getedComps), null); //new Thread(delegate() //{ // GetList(); // //................................ //}).Start(); Task.Factory.StartNew(() => { GetList(); }); ////t.Start(); //sd.EndInvoke(asyncRes); //Parallel.Invoke(() =>{getComps();}); // startedList = true; } private void getedComps(IAsyncResult result) { } private void getComps() { } [Export1c] public void ПолучитьСписокКомпьютеров() { GetListComs(); } public void Initialization() { } } |
|||
100
vudo
30.09.13
✎
16:16
|
&НаКлиенте
Процедура ПриОткрытии(Отказ) Попытка //Загружено = ПодключитьВнешнююКомпоненту("D:\1C_DATA\OS\Внешняя компонента\Service\Comps\Comps\bin\Release\Comps.dll","Comps"); Загружено = ПодключитьВнешнююКомпоненту("Addin.Comps"); Исключение Сообщить(ОписаниеОшибки()); КонецПопытки; ВК = Новый("Addin.Comps"); ПодключитьОбработчикОжидания("ПрочитатьСписокКомпьютеров",2,Истина); РазмерБуфера = 50; ВК.SetBufferEvent(250); КонецПроцедуры &НаКлиенте Процедура ПолучитьСписокКомпютеров(Команда) ВК.ПолучитьСписокКомпьютеров(); КонецПроцедуры |
|||
101
Serginio1
30.09.13
✎
16:27
|
Ну ты наворотил.
Зачем тебе обработчик ПодключитьОбработчикОжидания да еще через 2 секунды? Для этого у себя есть Async.ExternalEvent("onNamesAll", "done", "done"); Для проверки public void ПолучитьСписокКомпьютеров() { Task.Factory.StartNew(() => { Thread.Sleep(TimeSpan.FromSeconds(30)); Async.ExternalEvent("onNamesAll", "done", "done"); }); } Но лучше использовать SynchronizationContext Sc.Send(d => EventTo1C.ExternalEvent("onNamesAll", "done", "done"), null); |
|||
102
vudo
30.09.13
✎
16:32
|
(101) ПодключитьОбработчикОжидания он никаким боком. Там другая процедура подвязана.
Да в том-то и дело что Sleep по коду намного дальше (в подписке на события) тоже вешает 1С. |
|||
103
Serginio1
30.09.13
✎
16:33
|
У тебя onNameGeting() вызывается в осномном потоке.
А вот внутри onNameGeting() и запускай поток Task.Factory.StartNew(() => { List<string> listComps = new List<string>(); ShellItem folder = new ShellItem((Environment.SpecialFolder)CSIDL.NETWORK); IEnumerator<ShellItem> e = folder.GetEnumerator(SHCONTF.FOLDERS); while (e.MoveNext()) { listComps.Add(e.Current.ParsingName); ListComps = listComps; OnNameGet(e.Current.ParsingName, ""); } OnNamesAll(true); }); } |
|||
104
vudo
30.09.13
✎
16:33
|
+ Например в onNameGeting
|
|||
105
vudo
30.09.13
✎
16:34
|
(103) Счас.
|
|||
106
Serginio1
30.09.13
✎
16:34
|
(102) Проверь для начала 101.
А потом 103 |
|||
107
vudo
30.09.13
✎
16:36
|
(103) Все тоже...
|
|||
108
vudo
30.09.13
✎
16:38
|
(101) Как и предпологалось висит 30 сек...
|
|||
109
Serginio1
30.09.13
✎
16:39
|
(107) 101 делал?
|
|||
110
vudo
30.09.13
✎
16:39
|
(101)+(103) = 0
|
|||
111
vudo
30.09.13
✎
16:39
|
(109) Висит 30 сек и потом выдает done
|
|||
112
Serginio1
30.09.13
✎
16:40
|
Убери пописку
NamesAll += new NamesAllHandler(onNamesAll); NameGet += new NameGetHandler(onNameGet); NameGeting += new NameGetingHandler(onNameGeting); |
|||
113
vudo
30.09.13
✎
16:43
|
(112) done после 30 сек...
|
|||
114
vudo
30.09.13
✎
16:43
|
Я уже это все проходил, дружище...
|
|||
115
vudo
30.09.13
✎
16:45
|
Думаю тут все дело в том как 1с воспринимает работу компоненты. Может она ее блокирует, пока хотя бы один поток живой?
|
|||
116
Serginio1
30.09.13
✎
16:46
|
ИдПотока = Thread.CurrentThread.ManagedThreadId;
public void ПолучитьСписокКомпьютеров() { MessageBox.Show( {Thread.CurrentThread.ManagedThreadId.ToString()); Task.Factory.StartNew(() => { Thread.CurrentThread.ManagedThreadId.ToString()); Thread.Sleep(TimeSpan.FromSeconds(30)); Async.ExternalEvent("onNamesAll", "done", "done"); }); } |
|||
117
Serginio1
30.09.13
✎
16:48
|
Это только у тебя блокирует. У меня множество компонент работает. Может виной твой экспресс.
|
|||
118
vudo
30.09.13
✎
16:50
|
(117) Это как? В visual studio вроде своего компилятора нет, он с FrameWork работает...
|
|||
119
vudo
30.09.13
✎
16:51
|
(117) А может у тебя на сервере компоненты выполняются? Не?
|
|||
120
Serginio1
30.09.13
✎
16:53
|
(118) Нужно смотреть IL код. Сделай 116 и посмотри какой ManagedThreadId в основном потоке и в новом потоке.
У меня на толстом клиенте все работает. ВК на сервере не нужна так как нет смысла в Async.ExternalEvent |
|||
121
Serginio1
30.09.13
✎
16:54
|
И на этапе тестирования убери ПодключитьОбработчикОжидания
|
|||
122
vudo
30.09.13
✎
16:58
|
(116) Блин. В одном потоке.
Сделал так: MessageBox.Show( Thread.CurrentThread.ManagedThreadId.ToString()); Task.Factory.StartNew(() => { string ID = Thread.CurrentThread.ManagedThreadId.ToString(); Thread.Sleep(TimeSpan.FromSeconds(30)); Async.ExternalEvent("onNamesAll", ID, ID); }); И в окне и сообщении идентификатор 1. Какого? |
|||
123
Serginio1
30.09.13
✎
17:08
|
У тебя без инициализации потока Async.ExternalEvent должен был бы выдавать ошибку. А так значит в одно потоке выполняется.
Интересно а по старинке void ЗапуститьПотокДляСобытия1С() { MessageBox.Show( Thread.CurrentThread.ManagedThreadId.ToString()); var mStaThread = new Thread(d=> string ID = Thread.CurrentThread.ManagedThreadId.ToString(); Thread.Sleep(TimeSpan.FromSeconds(30)); Async.ExternalEvent("onNamesAll", ID, ID); ); mStaThread.Name = "STA Worker Thread"; mStaThread.SetApartmentState(ApartmentState.STA); mStaThread.Start(); } |
|||
124
vudo
30.09.13
✎
17:12
|
(123) Так я Async.ExternalEvent из базового класса наследую.
|
|||
125
Serginio1
30.09.13
✎
17:13
|
Да наследуй хоть откуда. Поток доллжен быть COM инициализирован SetApartmentState(ApartmentState.STA);
|
|||
126
vudo
30.09.13
✎
17:23
|
(123) Все тоже...
|
|||
127
vudo
30.09.13
✎
17:24
|
+ Один поток
|
|||
128
Serginio1
30.09.13
✎
17:27
|
Вообще public abstract class ServicedComponent : ContextBoundObject
Возьми мою компоненту и через неё попробуй |
|||
129
Serginio1
30.09.13
✎
17:31
|
http://rsdn.ru/article/dotnet/CSThreading1.xml#ESCBG
В этом случае CLR гарантирует, что только один поток сможет одновременно исполнять код в safeInstance. CLR делает это, создавая отдельный объект синхронизации и блокируя его при каждом вызове метода или свойства safeInstance. Область блокировки, в данном случае – объект safeInstance, называют контекстом синхронизации. Как это работает? Ответ находится в пространстве имен атрибута Synchronization – System.Runtime.Remoting.Contexts. О ContextBoundObject можно думать как об “удаленном” объекте, перехватывающем все вызовы методов. Чтобы сделать этот перехват возможным, CLR, когда создается AutoLock, фактически возвращает прокси-объект со всеми методами и свойствами AutoLock, который работает как посредник. Именно через это посредничество и работает автоблокировка. В целом перехват добавляет около микросекунды к вызову каждого метода. |
|||
130
Serginio1
30.09.13
✎
17:33
|
Или наследуйся оне от ServicedComponent
|
|||
131
Serginio1
30.09.13
✎
17:38
|
по сути тебе ServicedComponent нужен для авторегистрации.
Но ты можешь и сам поставить атрибуты для своего класса [ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true), Guid(ГуидКласса), ProgId("Addin.Comps")] |
|||
132
Serginio1
30.09.13
✎
17:48
|
Убери ServicedComponent и все у тебя будет прекрасно.
|
|||
133
vudo
05.10.13
✎
08:52
|
Ни чего не помогает.
Вызывается синхронно и все тут! :( |
|||
134
Бертыш
05.10.13
✎
10:06
|
УЦ№1 обещают курс по внешним компонентам. Ждем
|
|||
135
vudo
05.10.13
✎
13:32
|
Убираю ServicedComponent, перестает регестрироватся компонента ...
Все перепробовал - один поток хоть ты тресни! |
|||
136
vudo
05.10.13
✎
14:50
|
Все! Я её победил!
За границу потока удается забросить только через еще один класс и только после создания в нем потоков. Ну и передача данных через подписку на события (само собой)... Из (11) ExtComponentBase, и конечный результат такой: using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Management; using System.Threading; using Comps.Shell; using Comps.Shell.Interop; using System.Threading.Tasks; using System.Windows.Forms; using System.EnterpriseServices; namespace Comps { delegate void CompsListDelegate(); public delegate void NameGetHandler(string compName, string ipAdress); public delegate void NamesAllHandler(bool allOk); public delegate void NameGetingHandler(); [GuidAttribute("3E00A8B5-817B-4cd8-8859-098216D9EBC7")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [ComImport] public interface IWorkCompsMain { void GetListComs(); void ПолучитьСписокКомпьютеров(); string Version { get; } void SetBufferEvent(Int32 depth); } [Guid("8D3D2B33-97B7-4ce6-8BBB-4D687BC5BFC3")] [ClassInterface(ClassInterfaceType.None)] [Transaction(TransactionOption.Disabled)] [ProgId("Addin.Comps")] public class Comps : ExtComponentBase, IWorkCompsMain { private string _version = ""; List<string> _listComps; public event NameGetHandler NameGet; public event NamesAllHandler NamesAll; private GetAll GetAll; [Export1c] public string Version { get { return _version; } set { _version = value; } } [Export1c] public List<string> ListComps { get { return _listComps; } set { _listComps = value; } } protected virtual void OnNameGet(string compName, string ipAdress) { NameGet(compName, ipAdress); } protected virtual void OnNamesAll(bool allOk) { NamesAll(allOk); } private void onNamesAll(bool allOk) { this.Async.ExternalEvent("onNamesAll", "done", "done"); } private void onNameGet(string compName, string ipAdress) { this.Async.ExternalEvent("onNameGet", "done Name", compName + ":" + ipAdress); } private void onNameGeting() { } [Export1c] public void SetBufferEvent(Int32 depth) { this.Async.SetEventBufferDepth(depth); } public Comps() { ComponentName = "Comps"; GetAll = new GetAll(this); GetAll.NameGet += onNameGet; GetAll.NamesAll += onNamesAll; } [Export1c] public void GetListComs() { GetAll.OnNameGeting(); } [Export1c] public void ПолучитьСписокКомпьютеров() { GetListComs(); } public void Initialization() { } } public class GetAll { public event NameGetHandler NameGet; public event NameGetingHandler NameGeting; public event NamesAllHandler NamesAll; public GetAll(Comps myComps) { NameGeting += new NameGetingHandler(onNameGeting); } public void OnNameGeting() { Task.Factory.StartNew(() =>{NameGeting();}); } private void onNameGeting() { //Thread.Sleep(10000); List<string> listComps = new List<string>(); ShellItem folder = new ShellItem((Environment.SpecialFolder)CSIDL.NETWORK); IEnumerator<ShellItem> e = folder.GetEnumerator(SHCONTF.FOLDERS); while (e.MoveNext()) { listComps.Add(e.Current.ParsingName); OnNameGet(e.Current.ParsingName, ""); } NamesAll(true); } } } Всем спасибо! :) |
|||
137
Serginio1
05.10.13
✎
20:34
|
(135) Это как перестает регbстрироваться?
если установишь атрибут [ClassInterface(ClassInterfaceType.AutoDual), ComVisible(true), Guid(ГуидКласса), ProgId("Addin.Comps")] и с ключом /codebase все должно регистрироваться |
|||
138
vudo
11.10.13
✎
10:15
|
Долго не заходил был занят и не до компоненты было. :(
(137) Не знаю, не регистрируется и все. |
|||
139
vudo
11.10.13
✎
10:22
|
Еще вопрос внешниесобытия на сервере могут существовать?
Имеется ввиду подключение и подписка на внешние события на сервере 1С... |
|||
140
Serginio1
11.10.13
✎
11:23
|
(139) нет. Кто и когда их будет обрабатывать? Там привязка к вызываемому потоку, а этот поток может уже заниматься другой работой,т.к. используются пулы потоков
|
|||
141
vudo
11.10.13
✎
12:51
|
(140) Понятно. Т.е. реально многозадачность на серверах 1С можно реализовать только через регламентные задания...
|
|||
142
Serginio1
11.10.13
✎
13:35
|
(140) Можно передать ссылку на модуль с функцией для обратного вызова.
Попробуй. |
|||
143
Serginio1
11.10.13
✎
13:36
|
||||
144
vudo
11.10.13
✎
13:56
|
(143) Интересно, но не то - хотел на сервере отлавливать события компоненты.
|
|||
145
Serginio1
11.10.13
✎
14:01
|
(144) Тпопробуй 142. Передай модуль через метод ВК, и дергай нужный метод этого модуля через IDispatch (динамик)
Попробуй. И трассируй ошибки |
|||
146
Serginio1
11.10.13
✎
14:02
|
Тебе на сервере не ВК нужна а обычный ком.
|
|||
147
Serginio1
11.10.13
✎
14:08
|
Либо можешь запустить Фоновое задание которое будет запускать метод COM в котором будут запускаться потоки и дожидаться полного исполнения или передать ссылку на модуль который будет дергаться из COM.
|
|||
148
vudo
11.10.13
✎
14:17
|
(147) Спс
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |