Библиотека классов для создания внешней компоненты 1С на C#

01.03.15

Разработка - Разработка внешних компонент

В статье предложен набор классов-оберток над служебными интерфейсами 1С:Предприятия, позволяющий реализовать внешнюю компоненту в виде обычного класса .NET

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Библиотека для создания внешних компонент на C#
.zip 9,60Kb
241
241 Скачать (1 SM) Купить за 1 850 руб.

and it will, I hope, soon seem

as clear as a mountain creek!

Bertrand Meyer

 

Любой программист, которому приходилось написать несколько внешних компонент 1С:Предприятия, наверняка задумывался о странностях реализации интерфейсов IInitDone и ILanguageExtender. Зачем каждый раз полностью копировать реализацию некоторых методов, вроде FindProp или GetPropName? Почему так неудобно передаются параметры вызовов из 1С в CallAsProp и CallAsFunc в виде массивов? И почему нарушен один из основополагающих принципов объектно-ориентированного программирования (ООП) - прямое отображение? (Речь идет о таинственном объекте в 1С, который создается с помощью

ОбъектКомпоненты = Новый("AddIn.SomeName");

но который никак не представлен во внешней компоненте!). В этой статье автором предложен набор классов, который скрывает сложности служебных интерфейсов 1С, включая все трудности маршаллига COM-интерфейсов параметров 1С:Предприятия и позволяет написать внешнюю компоненту, просто создав обычный класс .Net на C#.

 

КАК ПОЛЬЗОВАТЬСЯ

 

Сначала покажем, как написать внешнюю компоненту с помощью библиотеки, прилагаемой в качестве примера к данной статье. Читатели не интересующиеся архитектурой, следующий раздел могут не читать. Но оценить, насколько все стало проще и элегантнее, наверное, сможет каждый. Настройки проекта в Visual Studio, как зарегистрировать dll внешней компоненты и другие нюансы, существенные для начинающих, здесь не объясняются.

Итак, вначале создадим в проекте на C# в Visual Studio типа "Class library" новый открытый (public) класс. Он может быть статическим, тогда наличие (разумеется статического) конструктора не обязательно, либо обычным динамическим, в этом случае обязательное требование - присутствие публичного конструктора по-умолчанию (без параметров), так как это класс и будет представлением того самого виртуального объекта 1С AddIn. Дальше также просто: открытые свойства класса - это свойства объекта, если свойство только get - значит в 1С оно будет доступно только для чтения, set - для записи. Открытые методы класса - методы объекта AddIn с полным соответствием с возвращаемым значением и параметрами. Например:

public class SomeName
{
 public SomeName() 
 {
  InstanceName = "SomeName";
 }

 public bool IsEnabled {get; set;}
 public string InstanceName {get; private set;}
 public object Make(string How, int Count) 
 {
   if (IsEnabled)
   {
    InstanceName = String.Empty;
    for (int i=0;i<Count;++i)
     V8Context.CreateContext().V8Message(MessageTypes.Info,How);
   }
  return null;
 }
}

такой класс будет виден в 1С как объект AddIn.SomeName со свойствами IsEnabled типа булево для чтения и записи, InstanceName - только для чтения и методом Make, возвращающим произвольное значение. Не забываем об ограничениях типов 1С:Предприятия: параметры и свойства могут быть типов string, bool, int, double, decimal, DateTime и object, который может инкапсулировать перечисленные до него типы, содержать null (в 1С Неопределено) либо передавать COM-объект, созданный в компоненте и реализующий интерфейс IDispatch. (В net это реализуется созданием класса с атрибутами [ComVisible] и [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]). Возможна передача массивов этих типов, но в 1С они будут соответствовать не объекту Массив, а COMSafeArray. Класс конечно же может иметь и скрытые (private или protected) поля, свойства, методы, они будут скрыты и для 1С.

После создания и реализации класса, необходимо "подключить" его к библитеке. Для этого копируем папку AddIn из шаблона библиотеки и создаем простой класс-заглушку:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using V8.AddIn;

[ComVisible(true)]
[Guid("6a81d0a9-6441-463f-a0c9-ec7b1f2cbd56")] // произвольный Guid-идентификатор Вашей компоненты
[ProgId("AddIn.SomeComponent")] // это имя COM-объекта, по которому Вы будете ее подключать
public class Some : LanguageExtenderAddIn
{
 public Some() : base(typeof(SomeName), 1000) {}
}

Класс LanguageExtenderAddIn содержит реализацию всей интерфейсной части компоненты, в его конструктор передается описание типа объекта компоненты и номер версии (он может быть 1000 или 2000). Подключается компонента инструкцией:

ПодключитьВнешнююКомпоненту("AddIn.SomeComponent");

В целом все, проект собирается и компонента готова. Остались мелкие детали.

Вывод сообщений, дополнительные интерфейсы. Реализованы с помощью класса V8Context. Это синглетон, его не следует создавать явно, а вызывать конструкцией:

V8Context.CreateV8Context()

Он содержит перезагруженные методы V8Message, выводящие текст в окно сообщений или диалог с предупреждением об ошибке. Например,

V8Context.CreateV8Context().V8Message(MessageTypes.MsgboxInfo, "Текст сообщения");

выведет информационный диалог с текстом. Также класс V8Context имеет свойство AsyncEvent, реализующее интерфейс IAsyncEvent для отправки сообщений в 1С.

Русскоязычные синонимы, параметры по умолчанию устанавливаются с помощью атрибутов Alias и HasDefaultValue. В качестве примера, дополним класс SomeName:

public class SomeName
{
 public SomeName() {}
 
 [Alias("Включена")]
 public bool IsEnabled {get; set;}
 [Alias("ИмяЭкземпляра")]
 public string InstanceName {get; private set;}

 [Alias("Выполнить")]
 public object Make(string How, [HasDefaultValue(1)] int Count) { return null;}
}

Второй параметр метода Make при вызове из 1С:Предприятия может быть пропущен, в этом случае он имеет значение 1. Покажем примерный код в 1С для работы с этой компонентой:

ПодключитьВнешнююКомпоненту("AddIn.SomeComponent");
ОбъектКомпоненты = Новый("AddIn.SomeName");
ОбъектКомпоненты.Включена = Истина;
Если ПустаяСтрока(ОбъектКомпоненты.InstanceName) Тогда
 ОбъектКомпоненты.Выполнить("Быстро");
КонецЕсли;

ИНТЕРФЕЙСЫ ВНУТРЬ И НАРУЖУ

(УСТРОЙСТВО БИБЛИОТЕКИ)


Для улучшения какого-либо программного решения, необходимо выяснить, что в нем не устраивает. Изучив примеры создания внешних компонент с дисков ИТС, ответ напрашивается сам собой - отсутствие подходящего коннектора между addin объектом компоненты и 1С:Предприятием. И дело не в том, что в примерах он (как класс) вообще не реализован, а в том что даже написав его, мы были бы вынуждены вызывать свойства и методы через их описания массивами строк. Код этого объекта все равно бы находился внутри класса, реализующего ILanguageExtender. Net Framework с самой первой версии имеет замечательный механизм отражения своих метаданных - пространство имен Reflection. Полезность его использования при создании компонент была отмечена в статье (http://rsdn.ru/article/dotnet/cs1c.xml), но автор остановился на пол пути и не отделил реализацию компоненты от интерфейсной части 1С.

Технология внешних компонент предоставляет ряд интерфейсов, из которых IInitDone и ILanguageExtender нужны только для использования внутри 1С. 1С:Предприятие по ним распознает внешнюю компоненту и управляет ей. Для программиста их реализация - лишняя работа, поэтому мы попытаемся их отделить. Начнем с IInitDone, имеющего три метода и создадим его реализацию:

 

using System;
using System.Runtime.InteropServices;

namespace V8.AddIn
{
 [ComVisible(true), Guid("bc631c98-2f0b-49b9-b722-b7e223e46059")]
 public abstract class InitAddIn : IInitDone
 {
  private int m_Version;
  protected InitAddIn(int Version)
  {
   this.m_Version = Version;
  }
  void IInitDone.Init([MarshalAs(UnmanagedType.IDispatch)] object pConnection)
  {
   new V8Context(pConnection);
  }
  void IInitDone.Done()
  {
   GC.Collect();
   GC.WaitForPendingFinalizers();
  }
  void IInitDone.GetInfo([MarshalAs(UnmanagedType.SafeArray)] ref object[] pInfo)
  {
   pInfo.SetValue(this.m_Version, 0);
  }
 }
}

подключение компоненты начинается с вызова Init, в нем мы инициализируем V8Context объектом 1С. Оставшийся код очевиден: храним версию компоненты и принудительно собираем мусор при закрытии 1С в методе Done. В принципе после этого уже можно написать компоненту, например так:

 

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using V8.AddIn;

[ComVisible(true)]
[Guid("73D8A32F-8195-4482-B845-71B6535DC079")]
public class VoidComponent : InitAddIn
{
 public VoidComponent() : base(1000) {}
}

Это компонента, не реализующая расширения встроенного языка, о ней многие забывают. Такие компоненты могут вызывать внешние события в 1С, например от какого-то оборудования и выводить сообщения. При реализации ILanguageExtender прийдется воспользоваться всей мощью пространства Reflection. Как уже было видно в примере, в конструктор абстрактного класса LanguageExtenderAddIn передается описание типа класса компоненты (Type). Через него необходимо выполнять вызовы свойств и методов класса. Вначале посмотрим на объвление, конструктор и служебные члены класса:

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace V8.AddIn
{
 [Guid("43295454-83da-49a0-beca-58a9f6ac1ef0"), ComVisible(true)]
 public abstract class LanguageExtenderAddIn : InitAddIn, ILanguageExtender
 {
  private string m_Name;
  private PropertyInfo[] m_Properties;
  private MethodInfo[] m_Methods;

  private object m_Wrapper;

  private void InitWrapperInfo(Type WrapperType, BindingFlags flags)
  {
   this.m_Name = WrapperType.Name;
   this.m_Properties = WrapperType.GetProperties(flags);
   this.m_Methods = WrapperType.GetMethods(flags);
  }

  protected LanguageExtenderAddIn(Type WrapperType, int Version) : base(Version)
  {
   ConstructorInfo constructor = WrapperType.GetConstructor(Type.EmptyTypes);
   if (constructor == null)
   {
    this.InitWrapperInfo(WrapperType, BindingFlags.Static | BindingFlags.Public);
	return;
   }
   this.m_Wrapper = constructor.Invoke(null);
   this.InitWrapperInfo(WrapperType, BindingFlags.Instance | BindingFlags.Public);
  }

Объект m_Wrapper - это экземпляр класса компоненты. Мы храним описание его свойств и методов в массивах m_Properties и m_Methods. При отсутствии конструктора по умолчанию, полагаем что имеем дело со статическим классом, для которого вызов Invoke не нужен. Покажем два простых примера, реализацию RegisterExtensionAs и GetNProps:

void ILanguageExtender.RegisterExtensionAs([MarshalAs(UnmanagedType.BStr)] ref string bstrExtensionName)
{
 bstrExtensionName = m_Name;
}
void ILanguageExtender.GetNProps(ref int plProps)
{
 plProps = this.m_Properties.GetLength(0);
}

Далее при реализации методов ILanguageExtender необходмо вызывать обращаться к классу компоненты через их описания, не забывая существование русских синонимов (для этого нужно получать значения атрибута Alias):

void ILanguageExtender.FindProp([MarshalAs(UnmanagedType.BStr)] string bstrPropName, ref int plPropNum)
{
 plPropNum = 0;
 Type typeFromHandle = typeof(AliasAttribute);
 for (int i = 0; i <= this.m_Properties.GetUpperBound(0); i++)
 {
  AliasAttribute aliasAttribute = (AliasAttribute)Attribute.GetCustomAttribute(this.m_Properties[i], typeFromHandle);
  if (this.m_Properties[i].Name.ToUpper() == bstrPropName.ToUpper() || (aliasAttribute != null && aliasAttribute.AliasName.ToUpper() == bstrPropName.ToUpper()))
  {
   plPropNum = ++i;
   return;
  }
 }
}
void ILanguageExtender.GetPropVal(int lPropNum, ref object pvarPropVal)
{
 PropertyInfo propertyInfo = this.m_Properties[lPropNum - 1];
 try
 {
  pvarPropVal = propertyInfo.GetValue(this.m_Wrapper, null);
 }
 catch (Exception ex)
 {
  V8Context v8Context = V8Context.CreateV8Context();
  if (ex.InnerException!=null)
   v8Context.V8Message(MessageTypes.Fail, ex.InnerException.Message, ex.InnerException.Source);
  else
   v8Context.V8Message(MessageTypes.Fail, ex.Message, ex.Source);
 }
}

Обработку исключений необходимо делать в компоненте, так как любой Exception из net framework в 1С будет восприниматься как исключение в mscorlib.dll без расшифровки. В следующем примере показана реализация GetParamDefValue и обработка атрибута HasDefaultValue:

 

void ILanguageExtender.GetParamDefValue(int lMethodNum, int lParamNum, ref object pvarParamDefValue)
{
 ParameterInfo element = this.m_Methods[lMethodNum - 1].GetParameters()[lParamNum];
 HasDefaultValueAttribute hasDefaultValueAttribute = (HasDefaultValueAttribute)Attribute.GetCustomAttribute(element, typeof(HasDefaultValueAttribute));
 if (hasDefaultValueAttribute != null)
 {
  pvarParamDefValue = hasDefaultValueAttribute.DefaultValue;
 }
}

Вызовы методов компоненты выполняются через Invoke, с ними как и с полным кодом примера можно ознакомиться в прилагаемом файле.

Таким образом, в данной библиотеке полностью отделены реализации служебных интерфейсов от логики внешней компоненты, что позволит программистам сосредоточится на выполняемых ею задачах.

См. также

Разработка внешних компонент Программист Платформа 1С v8.3 1C:Бухгалтерия Платные (руб)

Позволяет автоматизировать работу с картинками. С помощью компоненты можно измерять размер изображений, поворачивать их, наносить водяные знаки, конвертировать из одного формата в другой. Будет очень полезна для интернет-магазинов и всех, кому постоянно требуется работать с различными графическими форматами. Выполнена по технологии NativeAPI. Работает с форматами: jpg (jpeg), png, bmp, gif, tif

3600 руб.

02.09.2010    77966    73    280    

191

Разработка внешних компонент Программист Платформа 1С v8.3 1C:Бухгалтерия 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 Платные (руб)

Внешняя компонента позволяет работать c TWAIN-совместимым оборудованием (сканерами, камерами) . Полностью совместима со стандартной TWAIN-компонентой из БСП и может применяться как ее замена без изменения вызовов, при этом может работать с 64-разрядной платформой, а так же имеет расширенную функциональность, например, сохранение результата непосредственно в PDF без использования сторонних утилит. Прекрасно работает на сервере, тонком клиенте и веб-клиенте (проверена работа в браузерах Google Chrome, Mozilla Firefox и Microsoft Internet Explorer).

3000 руб.

12.05.2020    29301    139    100    

92

Разработка внешних компонент Программист Платформа 1С v8.3 1C:Бухгалтерия Платные (руб)

Внешняя компонента позволяет печатать PDF файлы непосредственно из 1С, не используя при этом сторонних программ. Прекрасно работает на сервере, тонком клиенте и веб-клиенте. Основана на проекте PDFium из состава проекта Chromium/Chrome

1500 руб.

17.09.2018    37223    115    128    

116

Разработка внешних компонент Телефония, SIP Программист Платформа 1С v8.3 1C:Бухгалтерия Россия Платные (руб)

Внешняя компонента выполнена по технологии Native API для 1С 8.х, обеспечивает доступ к программным АТС Asterisk (FreePBX, Elastix) через AMI интерфейс. Через него можно управлять многими функциями Asterisk (определение номеров, перевод звонков, набор телефона и т. д.)

2400 руб.

04.05.2018    47790    125    66    

68

Разработка внешних компонент Системный администратор Программист Стажер Бесплатно (free)

Библиотека для работы с базами SQLite из 1С на основе внешней компоненты. Для Linux и Windows, бесплатно и с открытым исходным кодом!

14.01.2025    2821    bayselonarrend    14    

48

Разработка внешних компонент Программист Платформа 1С v8.3 1C:Бухгалтерия Россия Бесплатно (free)

В статье описывается приложение-конструктор внешних компонент (native API). Конструктор упрощает процесс разработки за счет удобного добавления всех нужных функций и процедур в графическом режиме, с указанием их параметров и типов параметров. На выходе приложение генерирует готовый код на С++ и Rust и позволяет сразу приступить к реализации, без настройки API компоненты вручную.

04.12.2024    5607    kovalevdmv    26    

77

Разработка внешних компонент Программист Платформа 1С v8.3 1C:Бухгалтерия 1С:Управление торговлей 11 Платные (руб)

Внешняя компонента для конвертации PDF файлов в картинки без использования дополнительных программ. Работает на сервере и в тонком клиенте.

2400 руб.

25.06.2024    1369    3    4    

3
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. I_G_O_R 70 02.03.15 23:50 Сейчас в теме
к сожалению в СП написано, что подключение компоненты, созданной по технологии com, не работает на сервере.
18. _Devill 26.09.17 10:30 Сейчас в теме
Пытаюсь создать внешнюю компоненту с помощью вашей библиотеки. 1С выдает ошибку : Тип не определен (AddIn.SomeName)
ОбъектКомпоненты = Новый("AddIn.SomeName");
Код компоненты:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using V8.AddIn;

namespace V8.AddIn
{

    [ComVisible(true)]
    [Guid("9fe0db43-beef-4358-b46a-1fb0f80c9bd6")] // произвольный Guid-идентификатор Вашей компоненты
    [ProgId("AddIn.SomeComponent")] // это имя COM-объекта, по которому Вы будете ее подключать
    public class Some : LanguageExtenderAddIn
    {
        public Some() : base(typeof(SomeName), 1000) { }
    }

    public class SomeName
   { 
        public SomeName() { }

        [Alias("Включена")]
        public bool IsEnabled { get; set; }
        [Alias("ИмяЭкземпляра")]
        public string InstanceName { get; private set; }

        [Alias("Выполнить")]
        public object Make(string How, [HasDefaultValue(1)] int Count) { return null; }
        
    }

    
}
Показать


Подскажите пожалуйста что делаю не так?
19. spacecraft 26.09.17 10:55 Сейчас в теме
(18)
ОбъектКомпоненты = Новый("AddIn.SomeName");

[ProgId("AddIn.SomeComponent")] // это имя COM-объекта, по которому Вы будете ее подключать
Оно?
2. nixel 1444 04.03.15 11:24 Сейчас в теме
И линукс-системы в пролете.
Но идея отличная!
3. IgorKissil 360 04.03.15 11:57 Сейчас в теме
В статье описана старая технология внешних компонент, которая работает только на клиенте и только на Windows. Несмотря на то, что 1С позиционирует свою открытость к интеграции, поле инструментов для создания компонент NativeAPI сильно уменьшилось, фактически остался только C++. Пример их создания от 1С с точки зрения архитектуры имеет те же недостатки, которые описаны в статье, но методы преодоления сложнее, т.к. в C++ нет отражений.
5. I_G_O_R 70 08.05.15 13:59 Сейчас в теме
(3) на .NET тоже можно сделать компоненту NativeAPI используя Hosting CLR
4. AlexanderKai 16.04.15 13:43 Сейчас в теме
Кто-нибудь переписывал шаблон компоненты на Си (без плюсов)?
6. IgorKissil 360 04.08.15 06:52 Сейчас в теме
To 5: Можно сделать компоненту, можно вызывать через COM+, через Web сервисы в конце концов. Но все это через проксю, иными словами в отдельном процессе, следовательно присутствуют накладные расходы на межпроцессное взаимодействие (в том числе и в отдельном AppDomain, как в Вашей компоненте). Внешние компоненты 1С как com'овские так и нативные работают в общем адресном пространстве с 1С.
7. I_G_O_R 70 04.08.15 19:40 Сейчас в теме
(6) Я умею запускать и в основном домене, и даже использовать раннее связывание, при этом скорость значительно выше по сравнению с опубликованной компонентой, но конечно медленнее, чем компонента написанная только на с++. Но я и не утверждаю, что моя компонента и сам способ лучшие, у них единственный плюс - это простое развертывание, на сервер клиента бывает проблематично что-нибудь установить, а Native API компонента не требует установки в системе.
8. quick 584 20.10.15 14:38 Сейчас в теме
Я такую штуку делал в Delphi XE2, очень удобно методы подключать декораторами.
9. Serginio 943 29.12.15 14:32 Сейчас в теме
Работая с Глобальным контекстом проще работать через DynamicObject

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Dynamic;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ТестВК
{

    class ДинамикГК : DynamicObject, IDisposable

{
        dynamic ГК1С;
        Type ТипГК;
        object App1C;

        void УничтожитьОбъект(object Объект)
        {
            Marshal.Release(Marshal.GetIDispatchForObject(Объект));
            Marshal.ReleaseComObject(Объект);


        }
  public ДинамикГК(dynamic ГК1С)
        {
            ТипГК = ГК1С.GetType();
            App1C = ГК1С.AppDispatch;
            this.ГК1С = ГК1С;


        }
    // установка свойства
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
         try
        {
        ТипГК.InvokeMember(binder.Name, BindingFlags.SetProperty, null, App1C, new object[]{value});
        return true;
        }
         catch (Exception)
         {
         }
         return false;
    }
    // получение свойства
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        try
        {
            result = ТипГК.InvokeMember(binder.Name, BindingFlags.GetProperty, null, App1C, null);
            return true;
        }
        catch (Exception)
        {  
        }
        result = null;
        return false;
    }
    // вызов метода
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
       // dynamic method = members[binder.Name];
       // result = method((int)args[0]);
       // return result != null;
        if (binder.Name=="ЗакрытьОбъект")
        {

            Dispose();
            result = null;
            return true;

        }


        try
        {
            if (args.Length == 1 && args[0].GetType() == typeof(System.Object[]))
                result = ТипГК.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, App1C, (System.Object[])args[0]);
            else
                result = ТипГК.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, App1C, args);

            return true;
        }
        catch (Exception)
        {
        }
        result = null;
        return false;
    }

    bool disposed = false;
      public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern. 
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            if (ГК1С != null)
            {
                УничтожитьОбъект(ГК1С);
                УничтожитьОбъект(App1C);
                ГК1С = null;
                App1C = null;
                // Free any other managed objects here. 
                //
            }
        }

        // Free any unmanaged objects here. 
        //
        disposed = true;
    }

  }


}
Показать


И использование


 public dynamic Новый( params object[] Параметры)
    {

        return ГК.NewObject(Параметры);
    }



ГК = new ДинамикГК(Object1C);

 ГК.Сообщить("Привет из ВК", ГК.СтатусСообщения.Важное);


dynamic Тз = Новый("ТаблицаЗначений");
    dynamic Колонки = Тз.Колонки;
    Колонки.Добавить("КолонкаЧисло", ПолучитьОписаниеТиповЧисла(9, 0));
    Колонки.Добавить("КолонкаЧисло4", ПолучитьОписаниеТиповЧисла(7, 2));

Показать


Подробне здесь http://infostart.ru/public/238584/
10. itworks 52 12.06.17 17:23 Сейчас в теме
Добрый день!
Подскажите пожалуйста! Сделал сборку с тестовым классом. В целом библиотека подключается, свойства читаются, методы вызываются. Но столкнулся с непонятным поведением.
Если вызывать метод отправки внешнего события в 1С несколько раз подряд, то в 1С обработчик внешнего события вызывается только один раз для первого вызова.
Кроме того, попробовал внутри метода класса запустить таймер, который каждую секунду должен выводить сообщение в 1С и дергать внешнее событие. Методы, которые вызываются в обработчике таймера не отрабатываются в 1С, как-будто обработчик таймера вообще не срабатывает. не могу понять в чем проблема.

namespace V8.AddIn
{
	public class MyTest1C
	{
		public MyTest1C()
		{
			this.InstanceName = "MyTest1C";
		}

		private Timer timer;

		[Alias("Включена")]
		public bool IsEnabled { get; set; }

		[Alias("ИмяЭкземпляра")]
		public string InstanceName { get; private set; }

		[Alias("Выполнить")]
		public void Make(string How, int Count)
		{
			if (IsEnabled)
			{
				timer = new Timer(1000);
				timer.AutoReset = true;
				timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
				timer.Start();

				V8Context.CreateV8Context().V8Message(MessageTypes.Info, "Hello!"); // Работает
				V8Context.CreateV8Context().V8Message(MessageTypes.Info, "Hello!"); // Работает
				V8Context.CreateV8Context().AsyncEvent.ExternalEvent("Test1", "Test2", "Test3"); // Работает
				V8Context.CreateV8Context().AsyncEvent.ExternalEvent("Test1", "Test2", "Test3"); // Не работает
			}
		}

		void timer_Elapsed(object sender, ElapsedEventArgs e)
		{
			V8Context.CreateV8Context().V8Message(MessageTypes.Info, "Hello!");		// Не работает
			V8Context.CreateV8Context().AsyncEvent.ExternalEvent("Test1", "Test2", "Test3"); // Не работает
		}
	}
}
Показать
11. I_G_O_R 70 12.06.17 21:26 Сейчас в теме
(10) Добрый день!
Вы явно пользуетесь не моей компонентой.
12. itworks 52 12.06.17 22:01 Сейчас в теме
(11) Я пользуюсь библиотекой, которую скачал в этой статье с помощью большой зеленой кнопки "Скачать".
"Библиотека для создания внешних компонент на C#"
Она не Ваша?
13. I_G_O_R 70 13.06.17 12:30 Сейчас в теме
(12) Я прошу прощения, мне вообще не стоило отвечать, это же не моя публикация))
просто уведомление пришло на почту, а я не внимательно прочитал...
16. IgorKissil 360 02.07.17 16:28 Сейчас в теме
(10) Сообщения пропадают из-за того, что Вы скорее всего не задали размер буфера. Что касается таймеров, Вы используете объект из пространства Threads или Timers, а они многопоточные. Многозадачность порождает проблемы даже в nativeAPI-компонентах, не говоря уж о .net. Ну хочет 1С, чтобы мы использовали их асинхронные вызовы, что тут поделаешь! Попробуйте прикрутить Timer из WinForms - он singlethreaded
14. twin 28.06.17 14:19 Сейчас в теме
Ну рабочий пример бы тут не помешал в архиве конечно.
15. twin 29.06.17 10:08 Сейчас в теме
Хотел сказать что код компоненты надо обернуть в

namespace V8.AddIn {

}

а то тип не будет виден.

В самой студии убедитесь, что у вас в Проект -> Свойства -> Сборка -> Регистрация для COM-Взаимодействия стоит галка
17. twin 17.07.17 15:05 Сейчас в теме
Подскажите, а как из кода вызвать
Состояние(<ТекстСообщения>, <Прогресс>, <Пояснение>, <Картинка>)
?
20. _Devill 26.09.17 12:02 Сейчас в теме
(19)
нет
ПодключитьВнешнююКомпоненту("AddIn.SomeComponent");
ОбъектКомпоненты = Новый("AddIn.SomeName");
21. spacecraft 27.09.17 16:14 Сейчас в теме
(20) ясно. Не там.
Там: конструктор класса пустой. В нем нужно заполнить InstanceName, тогда будет 1С видеть.
public SomeName() 
 {
  InstanceName = "SomeName";
 }
22. _Devill 28.09.17 07:29 Сейчас в теме
(21)
Заработало. Проблема была в том что 1С x64 была запущена.
23. _Devill 28.09.17 08:30 Сейчас в теме
24. _Devill 04.10.17 15:39 Сейчас в теме
Добрый день, не могу понять почему 1С видит только 3 свойства

using System;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Net;
    using System.Net.Sockets;
    using System.Text.RegularExpressions;
    using System.Text;
    using System.Threading;
    using System.IO;
    using V8.AddIn;


    namespace V8.AddIn
    {
        public class SomeName
        {
            private Socket clientSocket;

            [Alias("Пароль")]
            public string Password { get; set; }
            [Alias("IPАдрес")]
            public string IPAdress { get; set; }
            [Alias("Порт")]
            public int Port { get; set; }
            [Alias("ИмяПользователя")]
            public string Name { get; set; }


            [Alias("Подключиться")]
            public bool Connection()
            {


                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(IPAdress), Port);
                clientSocket.Connect(serverEndPoint);

                // Login to the server; manager.conf needs to be setup with matching credentials.
                clientSocket.Send(Encoding.ASCII.GetBytes("Action: Login\r\nUsername: "+ Name + "\r\nSecret: "+ Password + "\r\nActionID: 1\r\nEvents: off\r\nEventmask: call\r\n\r\n"));

                int bytesRead = 0;
                byte[] buffer = new byte[1024];
                bytesRead = clientSocket.Receive(buffer);
                string response = "";
                response = Encoding.ASCII.GetString(buffer, 0, bytesRead);

                if (Regex.Match(response, "Message: Authentication accepted", RegexOptions.IgnoreCase).Success)
                {
                    // Send a ping request the asterisk server will send back a pong response.
                    return true;

                } else
                {
                    return false;
                }

            }
            public SomeName()
            {

            }
        }

        [ComVisible(true)]
        [Guid("9fe0db43-beef-4358-b46a-1fb0f80c9bd6")] // произвольный Guid-идентификатор Вашей компоненты
        [ProgId("AddIn.Some")] // это имя COM-объекта, по которому Вы будете ее подключать
        public class Some : LanguageExtenderAddIn
        {
            public Some() : base(typeof(SomeName), 1000) { }
        }
    }
Показать
25. sersoft 03.03.21 14:52 Сейчас в теме
Добрый день, смотрю давно комментариев не было :)

Но я скачал данную библиотеку классов для реализации нативной библиотеки для работы с эквайринговой системой.

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

Не покажите пример кода на C# как создать внешнее событие чтобы можно было его отловить в обработчкие ВнешнееСобытие(Источник, Событие, Данные)

Заранее спасибо.
Оставьте свое сообщение