Имя: Пароль:
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)!

Какого не могу второй день понять...
Кто знает?
1 Serginio1
 
26.09.13
13:29
2 Serginio1
 
26.09.13
13:32
ПодключитьВнешнююКомпоненту("Comps"));
         
    ВК = новый("Comps");
3 vudo
 
26.09.13
13:35
(2)ПодключитьВнешнююКомпоненту("Comps")
Уже проходил возвращает Ложь.
4 Serginio1
 
26.09.13
13:35
Но я использую ВК http://1c.proclub.ru/modules/mydownloads/personal.php?cid=115&lid=2019

Сообщить(ПодключитьВнешнююКомпоненту("AddIn.AddInFromITypeInfo"));
         
    ВК= новый("AddIn.AddInFromITypeInfo");
    
     ВК.LoadOleObject("Comps");
5 Serginio1
 
26.09.13
13:35
(3) А реально она у тебя ВК или просто COM объект?
6 vudo
 
26.09.13
13:37
(5) По технологии создания внешних компонент примерно двух годичной свежести...
Там наследуется ExtComponentBase
7 vudo
 
26.09.13
13:38
(4) Спасибо конечно, но мне нужно решить через C#.
8 vudo
 
26.09.13
13:39
(1) На форумы RSDN без регистрации перестали пускать :( Блин! Куда мир катится...

Там хоть о чем?
9 vudo
 
26.09.13
13:42
(8)+ Ан нет просто по прямой ссылке не пустило... Что там мне искать?
10 Serginio1
 
26.09.13
13:45
11 vudo
 
26.09.13
13:46
Нашел где брал ExtComponentBase! На том же rsdn:

http://www.rsdn.ru/forum/dotnet/3471534.1
12 Serginio1
 
26.09.13
13:48
Раз ПодключитьВнешнююКомпоненту не проходит значит не зарегестрирован или не видит IInitDone,
  ILanguageExtender

Может вызываешь на стороне сервера, тогда нужно регистрировать через 64 разрядный regasm.exe
13 vudo
 
26.09.13
13:52
(12) НаКлиенте

IInitDone сейчас гляну...
14 Serginio1
 
26.09.13
13:54
В отладчике VS посмотри
15 Serginio1
 
26.09.13
13:55
У тебя  ExtComponentBase: ServicedComponent,IInitDone,ILanguageExtender
поддерживает.
16 vudo
 
26.09.13
13:55
(15) Та отож... :(
17 vudo
 
26.09.13
13:56
(14) Там смотреть не на что - одна переменная... :(
18 vudo
 
26.09.13
14:02
Что-то еще... Вот только что?
19 Serginio1
 
26.09.13
14:13
В отладчике помотри на ExtComponentBase А имеено на методы InitDone. Вообще доходит ли до них.
20 vudo
 
26.09.13
14:17
Вот ссука... Прости господи что ругаюсь!
В документации ведь ясно написано, что ProgID имеет вид Vendor.Component, где в качестве первой части Vendor используется Addin.

Таким образом должно быть не [ProgId("Comps")], а [ProgId("Addin.Comps")]
Плюс к этому в калс добавить пустой метод

public void Initialization()
{
}

И после этого все работает!

Вызов

Загружено = ПодключитьВнешнююКомпоненту("Addin.Comps");
ВК = Новый("Addin.Comps");

На такую куйню столько времени.

И Спасибо  Serginio1 за поодержку. :))))

Йахо!!!! Пошел дальше ковырять.
21 vudo
 
26.09.13
14:51
(19) А как в отладчике посмотреть для вызова 1с?
22 oleg_km
 
26.09.13
14:56
(21) Можно я? Открываешь конфигуратор, запускаешь предприятие, открываешь студию, открываешь проект с ВК, в дебагере говоришь приаттачиться к процессу 1С Предприятие, ставишь точки останова в нужных местах, запускаешь Загружено = ПодключитьВнешнююКомпоненту("Addin.Comps");
ВК = Новый("Addin.Comps");
23 vudo
 
26.09.13
15:01
(22) А как дебагер в студио без отладки открыть?
24 oleg_km
 
26.09.13
15:07
(23) Дебаггер в студии всегда есть. Меню просто щелкаешь Debug -> Attach to Process... Ну у меня VS2010. ну и dll нужно естетственно билдить в отладочном варианте
25 vudo
 
26.09.13
15:10
VS2010 Express
Отладка -> Подключиться к отладке не вижу :(
26 oleg_km
 
26.09.13
15:22
Подключиться к процессу... тогда уж
27 vudo
 
26.09.13
15:42
(26) Пусть так а результат тот же - нету...
28 Serginio1
 
26.09.13
15:49
Project\Properties\Debug\Start external programm
устанавливаешь нужный путь к 1cestart.exe например
C:\Program Files (x86)\1cv82\common\1cestart.exe
29 oleg_km
 
26.09.13
15:53
(28) У меня так не получалось, очень много возникало остановок на запуске, какие-то исключения, где нужно жать Continue. Мне кажется проще приаттачиться к уже запущенному 1С перед вызовом ВК
30 Serginio1
 
26.09.13
16:00
согласен. Редко сейчас программирую на C#.
(25) Ну поставь более навороченный вариант.
31 vudo
 
26.09.13
16:00
(28) Неа
В Express там только Аргументы командной строки и Рабочий каталог :(
32 vudo
 
26.09.13
16:02
(30) Ладно, пока так справляюсь. Загоняю значения в поля классов и смотрю в 1с.
33 H A D G E H O G s
 
26.09.13
16:21
(32) Жесть.
Еще уж через ShowMessage() отлаживай...
34 H A D G E H O G s
 
26.09.13
16:21
Ох уж эта ваша C++
35 oleg_km
 
26.09.13
16:58
(34) А в чем разница с 1С? В 1С все то же, слегка усечено только
36 vudo
 
27.09.13
09:43
Продолжаю воевать с вк в управляемых формах...
Куда загонять  созданный COM объект? В хранилище значений? Так а с асинхронными вызовами как?
Что-то не соображу...
37 Serginio1
 
27.09.13
10:32
public void ПодключитьСканер(int НомерПорта)
        {
            sp = new SerialPort("COM" + НомерПорта.ToString());

            sp.BaudRate = 9600;
            sp.Parity = Parity.None;
            sp.StopBits = StopBits.One;
            sp.DataBits = 8;
            sp.Handshake = Handshake.None;

            sp.DataReceived += (sender, e) => {
                SerialPort sp1 = (SerialPort)sender;
                string indata = sp1.ReadExisting();
                Sc.Send(d => EventTo1C.ExternalEvent("ДанныеОтСканера", sp1.PortName, indata), null);
                    
                
            };

            sp.Open();

        
        }


Где  SynchronizationContext Sc; поле Класса Которое можно Инициировать в Init

SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
                Sc = SynchronizationContext.Current;
38 Serginio1
 
27.09.13
10:32
(36) А ты на сервере вызываешь?
39 vudo
 
27.09.13
10:51
(38) Нет пока на клиенте отлаживаю. И хочу с клиентом разобраться.
40 vudo
 
27.09.13
10:56
(37)А какой эффект я получу от SynchronizationContext?
Если на пальцах?
41 vudo
 
27.09.13
11:03
+ Я хочу получить от своей компоненты получить асинхронные вызовы в открытую форму. После вызова процедуры (нажатие кнопки) например:
ВК.ПолучитьКомпютеры();

должен получить через ExternalEvent по одному компьютеры в сети. Как-то так;

ВК = Новый("Addin.Comps");
Я же не должен каждый раз вызывать, а значит должен где-то эту ВК хранить. Вот и вопрос где?
Да еще и так, что бы она генерировала события для формы?
42 Serginio1
 
27.09.13
11:32
(40) На пальцах вызов будет в потоке 1С. Вообще IAsyncEvent
ассинхронный, но нужно Нетовский поток инициализировать и прочее. У меня не получилось. Проще воспользоваться SynchronizationContext.

Сделак ВК переменной формы.
А зачем тебе асинхронные вызовы  для ВК.ПолучитьКомпютеры();
Долгая операция?
EventTo1C.ExternalEvent
В форме ловится через

Процедура ВнешнееСобытие(Источник, Событие, Данные)
    Если Источник="ДанныеОтСканера" Тогда

           ОбработатьШтрихКод(Данные)
    КонецЕсли;
КонецПроцедуры
43 vudo
 
27.09.13
11:40
(37)Почитал об SynchronizationContext.
В принципе я делаю тоже, но только через делегаты:

        public void GetListComs()
        {

            CompsListDelegate sd = getComps;
            IAsyncResult asyncRes = sd.BeginInvoke(new AsyncCallback(getedComps), null);


        }

И события генерируются пока существует экземпляр вызывающего класса.

Так вот т.к. вызовы асинхронные, то выполнение продолжается после вызова

ВК = Новый("Addin.Comps");
ВК.ПолучитьКомпютеры();

На этом выполнение 1с процедуры завершается и экземпляр ВК  уничтожается, передавать события некому и нечему. Успевает передать только первый компьютер (через ВнешнееСобытие истественно).

Так что бы этого не происходило, необходимо ВК  держать открытой пока открыта форма по аналогии

Перем ВК;// как 8.1

"Я художник! Я так вижу!" (с) :)
44 H A D G E H O G s
 
27.09.13
11:44
Хрень какая-то.
45 H A D G E H O G s
 
27.09.13
11:45
Возвращайте рассово верную ТЗ, просто дописывая строки в отдельном потоке ВК.

В обработке внешнего события - удаляйте строки ТЗ, которые обработали.
46 H A D G E H O G s
 
27.09.13
11:45
Как у вас там все ... "непросто"
47 Serginio1
 
27.09.13
11:51
(43) Нет SynchronizationContext обеспечивает вызов делегата из потока в котором был создан этот SynchronizationContext.

Вообще в восьмерке есть подписка на события и можно ВК не использовать
http://stackoverflow.com/questions/10052722/manage-activex-net-event-by-javascript

v8: Вопрос по NetObjectToIDispatch
48 Serginio1
 
27.09.13
11:55
Смотри

msword = Новый COMОбъект("Word.Application");
ДобавитьОбработчик msword.DocumentChange,ПриИзмененииДокумента;

Процедура ПриИзмененииДокумента()
    Сообщить("Документ изменен");
КонецПроцедуры
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) Спс
Программист всегда исправляет последнюю ошибку.