Имя: Пароль:
1C
1С v8
Внешняя компонента для 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) Спс
Требовать и эффективности, и гибкости от одной и той же программы — все равно, что искать очаровательную и скромную жену... по-видимому, нам следует остановиться на чем-то одном из двух. Фредерик Брукс-младший