Книга знаний

1С:Предприятие / Приемы программирования / Внешние компоненты

Внешние компоненты 1С на .NET: работа с типами 1С:Предприятия

В статье описаны приемы работы с интерфейсом AppDispatch (который позволяет обращаться из ВК к глобальному модулю и данным 1С по технологии OLE Automation), передача параметров ссылочного типа (документы, справочники и т.п.) в/из ВК и приемы предотвращения зависания 1С в памяти. К статье приложен работающий пример тестовой внешней компоненты на VB.NET.Автор статьи: romix | Редакторы:
Последняя редакция №4 от 18.02.06 | История
URL: http://kb.mista.ru/article.php?id=62

Ключевые слова: AppDispatch, OLE, .NET, VB.NET, зависает в памяти, остается в памяти, освобождение памяти, Marshal.Release, Option Strict On disallows late binding, сборщик мусора, ReleaseComObject


Это продолжение статьи
Книга знаний: Написание внешних компонент для 1С на VB.NET и C#

Материал основан на документации 1С «Технология создания внешних компонент», статье с диска ИТС, faq Соарона и собственных экспериментах. Чтобы отыскать требуемые примеры кода, используйте характерные ключевые слова в поисковых системах: AppDispatch, IDispatch, сообщения об ошибках и т.п.

Поправки и дополнения приветствуются.

Обращение к 1С из ВК по OLE Automation


Предположим, что я хочу обратиться из внешней компоненты к справочнику товаров.
Нет проблем:
                    Dim obj0 As Object

                    obj0 = obj1C.CreateObject("Справочник.Товары")
                    obj0.ВыбратьЭлементы()
                    obj0.ПолучитьЭлемент()
                    MessageBox.Show("Товар: " + obj0.Наименование)

Не правда ли красиво – свойства и методы написаны по-русски.
Таким же способом можно обращаться к глобальному модулю и вообще делать все, что позволяет делать OLE-доступ к 1С. Необходимо правильно объявить переменную obj1C, о чем написано ниже. Для простоты освоения вы можете сразу загрузить «подопытный» работающий пример, и попытаться проделать с ним несколько экспериментов.


Option Strict On disallows late binding



Однако, чтобы это стало возможным, в свойствах проекта вырубаем «строгий режим» типизации переменных:
OptionStrict = "Off" 

Немного подумав, почему VB.NET ругается на «Option Strict On disallows late binding», я заменил эту настройку в файле с расширением .vbproj. Поскольку все настройки теперь хранятся в XML, а мне лениво ползать по меню, я проделал эту настройку текстовым редактором FAR.

Объявление переменной для AppDispatch



Глобальную переменную obj1C я определяю следующим образом:
     Dim obj1C As Object 
   
И инициализирую (в методе внешней компоненты) ее так:
     obj1C = V7Data.V7Object.AppDispatch

Свойство V7Data.V7Object ранее (в методе Init) определено как
V7Data.V7Object = pConnection

Где pConnection – параметр этого метода (см. образец кода).

Как гласит документация (и подтверждает суровая практика) в методе
Init свойство AppDispatch еще не инициализировано. Это и понятно: 1С должна «как следует» загрузиться, после чего сможет предоставлять различные внешние  интерфейсы.

Поэтому я вставляю инициализацию obj1C не в метод Init внешней компоненты, а непосредственно в пользовательский метод:
      Case Methods.methTest  '//Реализуем метод для тестирования доступа к 1С
      If g_flagInit = False Then
         obj1C = V7Data.V7Object.AppDispatch
         Marshal.Release(Marshal.GetIDispatchForObject(obj1C))
         g_flagInit = True
      End If

Основной строчкой здесь является
obj1C = V7Data.V7Object.AppDispatch

Это присвоение нашей переменной ссылки на AppDispatch.

Флажок g_flagInit  – это просто глобальная булева переменная, которая предотвращает повторную инициализацию obj1C. Вы можете воспользоваться отдельным методом для инициализации, чтобы не иметь дела с глобальными флажками.

Ниже по тексту идет уже непосредственная работа с объектом 1С:
      Dim obj0 As Object

      obj0 = obj1C.CreateObject("Справочник.Товары")
      obj0.ВыбратьЭлементы()

и т.д.

Предотвращение зависания 1С в памяти



Marshal.Release – метод, который уменьшает счетчик ссылок на obj1C (иначе 1С, подобно призраку, зависает в памяти, и снимается только диспетчером задач по Ctrl-Alt-Del – Диспетчер задач, вкладка Процессы...).

В других средах разработки, например, Delphi, требуется колдовать с _AddRef – здесь же колдовство и танцы с бубнами показали единственный рабочий вариант, при котором призрак зависшей (как “Ghost in the Shell”) 1С не норовит остаться в памяти ПК.


Передача агрегатных объектов в ВК



Предположим, что я хочу передавать во внешнюю компоненту не только строки и числа, но и, например, ссылки на элементы справочников. А также получать их же обратно из 1С.

Для тестирования этого режима работы я добавляю во внешнюю компоненту еще несколько методов, которые из кода 1С 7.7 выглядят следующим образом:
//*******************************************
Процедура Выполнить()
    
    net.УстановитьЗначение(ВыбТовары);
    зн=net.ПолучитьЗначение();
    Сообщить("зн="+зн);
    net.Закрыть();
КонецПроцедуры


Значение ВыбТовары – это ссылка на элемент справочника «товары». Я передаю ее в ВК методом net.УстановитьЗначение(ВыбТовары), а затем получаю это же значение из ВК методом зн=net.ПолучитьЗначение();

Вызов net.Закрыть(); я использую, как вы уже, наверное, догадались, для предотвращения зависания 1С в памяти после закрытия. Вот как я реализую эти тестовые методы:
    Case Methods.methSetValue
    '//Реализуем метод для установки значения из 1С в внешнюю компоненту
         g_var = paParams.GetValue(0)

    Case Methods.methGetValue
    '//Реализуем метод для чтения значения в 1С из внешней компоненты

       pvarRetValue = g_var

    Case Methods.methClose
    '//Реализуем метод для очистки переменной (иначе 1С зависает в памяти)

       g_var = Nothing
       GC.Collect()
       GC.WaitForPendingFinalizers()


Глобальная переменная g_var определена так:
Dim g_var As Object

Или, более строго:
<MarshalAs(UnmanagedType.IDispatch)> Dim g_var As Object


Поскольку наблюдаются проблемы с зависанием 1С в памяти, я очищаю ссылочную переменную g_var, присваивая ей «пустое» значение Nothing, после чего запускаю «сборку мусора»:
       GC.Collect()
       GC.WaitForPendingFinalizers()

Так сказать, глобальная зачистка территории от призраков.

Способ зачистки, который рекомендует YuriPar
ВК 1С на .NET: призрак OLE-доступа или почему 1С зависает в памяти

10 - 30.12.05 - 11:30
В конце дай Marshal.ReleaseComObject(AppDispatch). Все освободится, Сборщик мусора сам все уберет.



Пример исходного кода внешней компоненты для скачивания:

http://x-romix.narod.ru/vb_OLE.zip
(скачивать ЛЕВОЙ кнопкой мыши, 53К).
Для компиляции примера требуется Visual Studio.NET с установленным VB.NET.




Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика