Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

Взаимодействие с COM-объектами из NET на примере внешней компоненты для 1С:Предприятия
Библиотека классов, предоставляемых NET-Framework, позволяет разработчику осуществить тесную интеграцию своего приложения как с существующими COM-объектами, так и создать новые, следуя определенным соглашениям. Дополнительные трудности могут возникнуть при использовании приватных объектов, экспортируемых во внешние библиотеки приложений, созданных сторонними производителями. Такие библиотеки часто называются AddIn-компонентами. Здесь мы рассмотрим процесс создания внешней библиотеки для системы 1С:Предприятие версий 7.5-7.7 средствами NET и реализацию страницы свойств COM-объекта.

Введение

Библиотека классов, предоставляемых NET-Framework, позволяет разработчику осуществить тесную интеграцию своего приложения как с существующими COM-объектами, так и создать новые, следуя определенным соглашениям. Дополнительные трудности могут возникнуть при использовании приватных объектов, экспортируемых во внешние библиотеки приложений, созданных сторонними производителями. Такие библиотеки часто называются AddIn-компонентами. Здесь мы рассмотрим процесс создания внешней библиотеки для системы 1С:Предприятие версий 7.5-7.7 средствами NET и реализацию страницы свойств COM-объекта.

Создание внешней компоненты 1С

1С:Предприятие подключает внешнюю компоненту двумя способами: по указанному ProgID через CreateInstance, либо по имени файла компоненты. В последнем случае 1С пытается выполнить DllRegisterServer для саморегистрации файла через rgs-скрипт, затем ищется строка с ID=100 из ресурсов компоненты, содержащая ProgID объекта. Ясно, что при написании CLR-кода последняя возможность отпадает, поскольку у NET-компонент совсем другой принцип регистрации и другой метод хранения ресурсов. Поэтому из 1С:Предприятия необходимо использовать только метод ПодключитьВнешнююКомпоненту(ProgID), где ProgID должен иметь вид AddIn.xxx, что нам может помочь достичь атрибут ProgIdAttribute.

Ключевым для работы внешней компоненты является интерфейс IInitDone:

	interface IInitDone : IUnknown
	{
		[helpstring("method Init")] HRESULT Init([in] IDispatch *pConnection);
		[helpstring("method Done")] HRESULT Done();
		[helpstring("method GetInfo")] HRESULT GetInfo([in,out] 
			SAFEARRAY (VARIANT) *pInfo);
	};

Его должен реализовывать объект внешней компоненты. Кроме того, библиотека типов, поставляемая фирмой 1С, содержит ряд других интерфейсов для расширения встроенного языка и других целей, рассматривать которые мы не будем. Конечно можно воспользоваться готовым tlb-файлом и средствами NET создать COM callable wrapper (проще говоря добавить ссылку на COM-библиотеку из проекта), но тогда следует согласится с тем, что множество параметров типа VARIANT будут преобразованы в малоудобные System.Array или Object, в то время как из документации известна их более строгая типизация. Наш интерфейс в NET будет выглядеть так:

<Guid("AB634001-F13D-11d0-A459-004095E1DAEA"), 
	_ InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IInitDone
  Sub Init(<MarshalAs(UnmanagedType.IDispatch)> ByVal pConnection As Object)
  Sub Done()
  Sub GetInfo(ByRef pInfo() As Object)
End Interface

Реализующий его объект компоненты:

<ComVisible(True), ProgId("AddIn.V7SQLClient"), Guid("ххх")> _
Public Class V7AddIn
  Implements IInitDone


Private Sub Init(<MarshalAs(UnmanagedType.IDispatch)> 
		ByVal pConnection As Object) Implements IInitDone.Init
    Try
      ContainerCoordinator.V7Object = pConnection
    Catch
      Throw New COMException("Unknown V7 object context", COMError.S_FALSE)
    End Try
End Sub

Private Sub Done() Implements IInitDone.Done
    ContainerCoordinator.V7Object = Nothing
End Sub

Private Sub GetInfo(ByRef pInfo() As Object) Implements IInitDone.GetInfo
    pInfo.SetValue("1000", 0)
End Sub

End Class

Страницы свойств

Внешняя компонента 1С:Предприятия как и любой COM-объект может иметь страницу свойств. Для ее реализации средствами NET необходимо реализовать в объекте интерфейс ISpecifyPropertyPages:

<Guid("B196B28B-BAB4-101A-B69C-00AA00341D07"), 
	InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface ISpecifyPropertyPages
  Sub GetPages(<Out()> ByRef pPages As CAUUID)
End Interface
´--------------------------------------------------------------------------
<StructLayout(LayoutKind.Sequential)> _
Public Structure CAUUID
  Public cElems As Integer
  Public pElems As IntPtr
End Structure

Метод GetPages возвращает GUID страницы свойств:

Public Sub GetPages(ByRef pPages As CAUUID) Implements ISpecifyPropertyPages.GetPages
    pPages.cElems = 1
    pPages.pElems = Marshal.AllocCoTaskMem(Marshal.SizeOf(GetType(Guid)))
    Marshal.StructureToPtr(New Guid("601F0360-AAF2-4b89-A3BA-CB26967519F3"), 
		pPages.pElems, False)
End Sub

Страницу свойств будет выводить класс, реализующий стандартный интерфейс IPropertyPage, декларацию которого опустим:

<ComVisible(True), Guid("601F0360-AAF2-4b89-A3BA-CB26967519F3")> _
Public Class V7AddInPropertyPage
  Implements IPropertyPage

  Public Sub New()
    pPage = New PropPageControl()
    bDirty = False
  End Sub

  Public Sub GetPageInfo(ByRef pPageInfo As propPageInfo) 
		Implements IPropertyPage.GetPageInfo
    Try
      pPageInfo.cb = Marshal.SizeOf(pPageInfo)
      pPageInfo.pszTitle = "Внешние данные"
      pPageInfo.cx = 300
      pPageInfo.cy = 250
    Catch
      Throw New COMException("Invalid PageInfo structure", COMError.E_POINTER)
    End Try
  End Sub


  Private m_PageSite As IPropertyPageSite
  Private WithEvents pPage As PropPageControl
  Private bDirty As Boolean

  Private Sub pPage_DirtyChanged() Handles pPage.DirtyChanged
    bDirty = True
    m_PageSite.OnStatusChange(1)
  End Sub

End Class

Класс PropPageControl не обязательно должен быть видимым извне (public). Он наследуется от System.Windows.Forms.UserControl и соответственно доступен для редактирования из Visual Studio Designer. Если взаимодействие с объектом IPropertyPageSite осуществляется через события, как в примере, то нельзя использовать делегаты.


Может пригодится:


Автор: Кисиль Петрович Игорь
Прочитано: 9070
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру