NativeAPI. Внешние компоненты на С++ "для чайников"

15.08.19

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

В жизни каждого 1С-ника наступает момент, когда для выполнения задачи требуется код на другом языке программирования. На помощь приходят внешние компоненты, но как их писать, если последний раз вы брались за другой язык сто лет назад, сортируя массивы пузырьком на лабораторках в ВУЗе? Можно быстренько узнать только самое нужное, прочитав эту статью.

Скачать файлы

Наименование Файл Версия Размер
Шаблоны компонент
.rar 36,13Kb
301
.rar 36,13Kb 301 Скачать

Предисловие

В заголовок статьи вынесена фраза "для чайников". Под чайником я имел в виду в первую очередь себя. Все мои знания С++ остались на уровне 3-4 курса ВУЗа, когда я встал на кривую дорожку 1С. И все бы хорошо, но недавно встала задача, требующая написания внешней компоненты. Пришлось поворошить воспоминания и стряхнуть пыль со знаний C++. Оказывается, все не так страшно. Краткий ликбез написания внешних компонент я и хочу вам предложить.

Шаблон компоненты на ИТС

На диске ИТС имеется полная документация по механизму внешних компонент, дополненная примером проекта и шаблоном для собственной разработки. Материал так и называется "Технология внешних компонент". Документация - это прекрасно, но в ней еще надо разобраться, а времени, как обычно, мало. На самом деле, существует всего несколько ключевых моментов, на которые стоит обратить внимание, остальное - тлен и суета:)

Необходимые материалы

Для создания внешней компоненты нам понадобятся:

  1. Материал «Технология создания внешних компонент», расположенный на ИТС
  2. Шаблон пустой внешней компоненты, прилагающийся к материалу
  3. MS Visual Studio. Версия Express бесплатна и более чем достаточна для наших нужд.
  4. Наличие  базовых знаний синтаксиса C++, а именно:
  • Умение отличить объявление переменной от цикла или условия
  • Понимание того, что строк в чистом виде в C++ не существует, есть массивы, под которые явно требуется заморачиваться с памятью
  • Ну и само собой, требуется умение реализовать поставленную задачу на указанном языке. Как минимум, умение вызвать из C++ какую-то стороннюю библиотечку, которая сама все сделает.

Начинаем копать

Документация на Native API достаточно подробна. Если подвести резюме, то она говорит о следующем:

  1. Внешняя компонента позволяет расширить встроенный язык новым объектом (или несколькими). Т.е. мы создадим некий класс, который сможем создавать через оператор «Новый» и вызывать методы этого объекта из встроенного языка.
  2. Для того, чтобы наш объект работал, платформа будет «общаться» с ним по определенному протоколу, который мы и обязаны обеспечить.
  3. Собственно код компоненты условно состоит из двух частей: первая - регистрация самой компоненты в системе, вторая - работа нового класса и его взаимодействие с платформой.

Мы не будем залезать в особенности реализации, у нас сроки горят, да и компетенции маловато. Нам нужно быстро понять – в какое место нужно вписать свои строчки, чтобы компонента заработала. Для этого, берем шаблон компоненты с ИТС и открываем его в Visual Studio. Шаблон находится в папке template распакованного архива. Посмотрим, что у нас тут есть.

solution

Нас интересует файл AddInNative.cpp. Вся реализация заложена в нем. Он содержит заготовки всех нужных методов, нужно только их слегка настроить. Однако оказалось, что проще взять за основу не пустой шаблон, а разобраться с рабочим примером. В нем есть несколько полезных примочек, которых нет в пустом шаблоне. Когда придет понимание – нужно будет взять пустой шаблон и уже со знанием дела его доработать. Пример рабочей компоненты расположен в папке example\NativeAPI, а пустой шаблон – в папке template.

Откроем проект из папки example и в нем – файл AddInNative.cpp

В самом начале файла расположены объявления констант и вспомогательных функций. Нас интересуют следующие строчки:

1

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

Зеленой рамкой выделена строка, в которой объявлено имя класса. Честно признаюсь, я не вникал, что оно означает. Если его поменять, то ничего не работает. Поскольку изначально оговорились, что я «чайник», то мне простительно. :)

Таким образом, если наш объект будет содержать метод «ВыполнитьРасчет» и свойство «Адресат», то нам нужно описать это имя в массиве g_MethodNamesRu и g_PropNamesRu, соответственно.

Вызовы из языка 1С

Итак, наш объект будет содержать один метод и свойство, доступное для чтения и записи.

Пусть будет следующий сценарий использования:

НашОбъект = Новый(“AddIn.MyComponent.DataSender”); // DataSender – это имя из ф-ции RegisterExtensionAs (рассмотрена ниже).
НашОбъект.Адресат = «somemail@server.com»;
НашОбъект.ВыполнитьРасчет(СуммаПлатежа, «За коммунальные услуги»);

Имеется строковое свойство и метод с числовым и строковым параметром. Для того, чтобы все это заработало 1С выполняет примерно следующий протокол общения с компонентой:

2

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

Вернемся к нашему коду. Во избежание «волшебных чисел» в классе CAddInNative объявлены два перечисления, отвечающие за определение номеров методов и свойств. Откроем  файл CAddInNative.h и увидим их в самом начале:

3

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

Строки Unicode

Многие, наверное, знают, что платформа оперирует двухбайтовыми символами в формате Unicode. В шаблоне для этого объявлен специальный тип WCHAR_T. Этот тип является кросс-платформенной оберткой и обеспечивает одинаковый размер символа на Windows и на Linux. Стандартный тип wchar_t по размеру может отличаться на разных системах. Обратите также внимание, все строковые литералы объявляются с префиксом в виде буквы L. Это означает, что такая строка имеет тип wchar_t.

Есть простое правило: внутри компоненты строки обрабатываются как wchar_t (на Linux может быть 4 байта, в Windows – 2), но как только мы передаем строку в 1С или принимаем ее оттуда, то нужен WCHAR_T (строго 2 байта на всех системах).

Для преобразования одного типа строк в другие в шаблоне предусмотрены вспомогательные функции:

Первая – формирует WCHAR_T из стандартного wchar_t:

uint32_t convToShortWchar(WCHAR_T** Dest, const wchar_t* Source, uint32_t len = 0);

Вторая – наоборот. Формирует wchar_t из WCHAR_T.

uint32_t convFromShortWchar(wchar_t** Dest, const WCHAR_T* Source, uint32_t len = 0);

При взаимодействии с платформой всегда используется только WCHAR_T.

Тип Variant

Еще одна интересная вещь – это универсальный тип данных Variant. Он позволяет нам взаимодействовать с языком 1С, который, как известно, не типизирован и каждая переменная в нем может содержать что угодно. При обмене значениями используется именно этот тип. Мы передаем в метод ВыполнитьРасчет два параметра – число и строку. В компоненту «приедут» два значения Variant. На нас возлагается обязанность проверить их действительный тип. Никто не помешает передать в компоненту не число, а скажем, таблицу значений.

Хотя, я похоже, ошибаюсь. Мне кажется, что ТаблицуЗначений в NativeAPI передать все-таки не получится, т.к. ее нет в списке допустимых типов, но, тем не менее, можно передать Дату вместо Cтроки. Это тоже не есть хорошо. Мы должны проверить реальный тип переменной, приехавшей из 1С.

Тип Variant устроен несложно. Это структура, свойствами которой являются значения разных типов. Там есть свойства типа DATE, wchar_t, int и прочие. Главной частью Variant является свойство «vt» которое хранит настоящий тип переменной, и по которой можно понять, как именно трактовать данный Variant. Кроме того, объявлен ряд вспомогательных макросов, упрощающих работу с типом Variant.

Ближе к делу

Вроде бы, со вступлением всё. Предлагаю рассмотреть пример реализации внешней компоненты. В качестве ТЗ выступит пример компоненты с диска ИТС. Этот пример описывает следующие возможности:

  • Вывод текста в строку состояния главного окна;
  • Посылка внешнего события по таймеру;
  • Передача двоичных данных в 1С:Предприятие;
  • Реализация свойств;
  • Реализация процедур;
  • Реализация функций;

Компонента имеет следующий API:

  • Свойства:
    • Включен/IsEnabled;
    • ЕстьТаймер/IsTimerPresent;
    • Методы:
      • Включить/Enable;
      • Выключить/Disable;
      • ПоказатьВСтрокеСтатуса/ShowInStatusLine;
      • ВключитьТаймер/StartTimer;
      • ВыключитьТаймер/StopTimer;
      • ЗагрузитьКартинку/LoadPicture;

По таймеру возникает внешнее событие, на которое можно подписаться из кода 1С.

Руководствуясь имеющимися у нас знаниями, рассмотрим компоненту с самого начала.

Регистрация компоненты

Наш объект реализуется в виде отдельного класса C++, в данном случае – CAddInNative. Чтобы 1С смогла увидеть наш класс, библиотека dll должна экспортировать 3 функции:

  • GetClassObject
  • DestroyObject
  • GetClassNames

Эти экспорты можно увидеть в файле AddInNative.def в дереве проекта VisualStudio. Посмотрим на код этих функций:

4

Самая простая – функция GetClassNames – сообщает платформе 1С какие классы есть в нашей компоненте. Пусть гуру C++ меня поправят, мне кажется, что здесь нужно ответить платформе именами классов C++, чтобы она могла их к себе импортировать. Именно для этого служит массив g_kClassNames, тот самый, с зеленой «рамочкой». Специально не проверял, если нужно просто заставить компоненту работать, то следует оставить все, как есть в примере. Он и так рабочий, не стоит его ковырять до поры до времени.

Итак, GetClassNames, возвращает в платформу массив имен классов, реализующих полезные объекты внешней компоненты. В нашем примере компонента вернет в платформу массив из одного элемента с именем класса CAddInNative.

Обратите внимание, в платформу пойдет значение типа WCHAR_T, а имя класса в массиве g_kClassNames имеет тип wchar_t. Поэтому, выполняется приведение с помощью вспомогательной функции, о которой говорилось выше.

Следующая функция – GetClassObject. Вызывается, когда в коде предприятия мы написали «Новый». Платформа требует от нас создать новый экземпляр класса и вернуть ей указатель на новый объект.

Опять же, обратите внимание, первым параметром платформа говорит нам – какой именно класс создать (из тех, что дали ей методом GetClassNames). Поскольку у нас только один класс, то это имя здесь вообще не проверяется, просто создается объект через new и возвращается через выходной параметр pInterface.

И последняя обязательная экспортная функция – DestroyObject. Название говорит само за себя. Когда объект платформе больше не нужен, его требуется удалить. Нам передается указатель на ранее созданный объект. Освобождаем его с помощью delete и обнуляем ненужные указатели.

Описанные реализации достаточно универсальны. Если наша компонента реализует только один класс (как в примере), то эти функции нужно тупо скопировать к себе. Единственное условие – создать правильный класс в функции GetClassObject, если у вас он называется не CAddInObject, а как-то иначе.

Инициализация/завершение существования компоненты

После создания класса, реализующего компоненту, платформа вызывает методы этого класса. Перед началом работы платформа сообщит нам объект «самой себя», с которым мы можем вызывать те или иные методы самой платформы. Происходит это в методе Init. В примере объект платформы сохраняется в переменной m_iConnect.

idone

Далее, метод GetInfo должен вернуть номер версии «Технологии внешних компонент». На данный момент, это всегда версия 2.0, а метод всегда возвращает значение 2000.

Еще один важный метод – setMemManager. Позволяет выделять блоки памяти, которые будет освобождать сама платформа. Реализуется следующим образом:

mm

Мы просто сохраняем у себя указатель на менеджера памяти, который передает нам платформа. Потом, этим менеджером мы будем выделять память, освобождаемую самой платформой.

И опять  же, как и в случае с экспортными функциями, методы инициализации достаточно универсальны, их можно просто скопировать к себе и не заботиться об их «допиливании», пока это не станет действительно нужно.

Полезная нагрузка. Методы и свойства объекта компоненты

Регистрация

Ну и разумеется, мы создавали компоненту не ради ее инициализации, а ради какого-то полезного функционала. Настало время рассмотреть, как он реализуется.

Во-первых, мы должны зарегистрировать объект, который может быть создан и вызван из языка 1С. Данный объект регистрируется в методе RegisterExtensionAs.

 ras

В этом методе мы сообщаем платформе имя нашего класса, как оно будет видно из языка 1С. Именно по этому имени мы будем его создавать через «Новый». В данном случае, создание объекта будет выполняться следующим кодом:

ПодключитьВнешнююКомпоненту(Файл, "МояКомпонента", ТипВнешнейКомпоненты.Native);
ОбъектКомпоненты = Новый("AddIn.МояКомпонента.AddInNativeExtension");

Согласно документации, память для строки с именем класса выделяется менеджером памяти, и по этому адресу записывается имя – «AddInNativeExtension». Здесь можно безболезненно написать свое имя. Обратите внимание, опять происходит преобразование из wchar_t в платформенный WCHAR_T.

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

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

НашОбъект = Новый("AddIn.MyComponent.DataSender"); // DataSender – это имя из ф-ции RegisterExtensionAs (рассмотрена ниже).
НашОбъект.Адресат = "somemail@server.com";
НашОбъект.ВыполнитьРасчет(СуммаПлатежа, "За коммунальные услуги");

то будет выполнен следующий опрос:

  1. Есть ли свойство «Адресат»
  2. Поддерживает ли оно запись
  3. Есть ли метод ВыполнитьРасчет
  4. Сколько у него параметров
  5. Есть ли у него возвращаемое значение
  6. Какие умолчания у необязательных параметров (если есть)

Здесь полезнее всего смотреть в пример и сверяться с документацией. Реализация всех этих опросов довольно прямолинейна. За взаимодействие отвечает целый зоопарк методов. Все рассматривать не буду, они довольно хорошо документированы, а кроме того, реализуются просто. Рассмотрены будут только наиболее значимые моменты, в которые нам, как «чайникам», надо будет залезть своими ручонками :). Основной подход следующий: при первом упоминании того или иного свойства или метода платформа попросит нас поискать его по имени. Мы должны будем ответить уникальным номером данного свойства (метода). Все дальнейшее общение будет происходить только по номерам. Здесь-то и помогут упомянутые перечисления, хранящие эти номера. 

Свойства

Первое, что стоит рассмотреть – это инфраструктура свойств. Платформа запрашивает существование свойства методом FindProp

fp

Платформа передает нам имя искомого свойства в виде WCHAR_T. Оно преобразуется в wchar_t вспомогательным методом, и происходит поиск этого текста сначала в англоязычных термах, а затем в русскоязычных. Вернуть мы должны номер свойства. Обратите внимание, здесь задействована вспомогательная функция findName. Ее реализация есть в примере, но нет в пустом шаблоне компоненты. Кажется целесообразным перетаскивать ее к себе, если в компоненте планируются двуязыячные термы.

Далее, метод GetPropName выполняет обратную задачу, получает имя свойства по его номеру. Строка с именем также выделяется через менеджер памяти предприятия. Подозреваю, что метод GetPropName совместно с GetNProps используется, когда мы разворачиваем свойства объекта «плюсиком» в отладчике. Тогда платформа получит общее число свойств и для каждого из них запросит имя.

Следующая пара методов IsPropReadable/IsPropWritable. Здесь все просто, для указанного номера свойства мы должны сказать можно ли его читать/писать.

Получение и запись значений выполняются методами GetPropVal/SetPropVal. Здесь стоит остановиться подробнее. Мы начинаем работать с типами 1С:Предприятия, а значит, на сцену выходит Variant.

dd

Шаблон компоненты определяет набор вспомогательных макросов для упрощения работы с Variant. Первый из них – это проверка типа значения. Например, макрос TV_VT позволяет проверить/установить тип значения. Определены также именованные константы для каждого из поддерживаемых типов. Эти константы и их соответствия типам 1С:Предприятия перечислены в документации.

Макрос TV_BOOL получает из варианта булево значение, с которым можно работать. По аналогии получаются целые значения (TV_INT), строки (TV_WSTR) и другие. Точные значения есть в коде, их всегда можно посмотреть.

Важный момент – мало присвоить варианту какое-то значение, нужно также присваивать и действительный тип. Обратите внимание на GetPropVal. Помимо присваивания TV_BOOL = true идет присваивание типа: TV_VT = VTYPE_BOOL. Если тип не присвоить, платформа не будет знать – какой тип значения ей вернули. Разумеется, можно накосячить и задать неверный тип. Часто это сопровождается падением платформы.

Подведем итог вышесказанного:

Получаем значение из варианта:

bool someVariable = TV_BOOL(pVariant);

Записываем значение в вариант:

TV_VT(pVariant) = VTYPE_BOOL; // действующий тип данных

TV_BOOL(pVariant) = someBooleanVariable; // устанавливаем само значение

А теперь – горбатый методы!

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

  • Если метод может возвращать значение, значит, его можно использовать в «Вычислить» и записывать справа от операции присваивания в языке 1С. Если нет, то это процедура и подобные вещи будут приводить к исключению «Использование процедуры как функции»
  • У метода есть параметры. Платформа должна знать их количество. Если при вызове указано аргументов больше чем в сигнатуре метода, то возникает ошибка «Слишком много параметров»
  • Если методу передано недостаточное количество аргументов, значит, некоторые из них могут быть необязательными, а если необязательных параметров нет, то возникает ошибка «Недостаточно параметров».
  • При вызове, если это процедура, то возвращаемого значения быть не может. Если это функция, то есть возвращаемое значение. Его тоже нужно обработать.

Есть ряд простых методов, назначение которых понятно из их имен и из документации. Сюда относятся HasRetVal, GetNParams, GetParamDefValue. Их предлагаю не рассматривать, примера более чем достаточно. Наш интерес будет направлен в сторону непосредственной реализации полезной нагрузки. Она реализуется в методах CallAsProc и CallAsFunc. Первый отвечает за вызов процедур, второй – за вызов функций. Отличаются они тем, что CallAsFunc имеет дополнительный выходной параметр, в котором мы передадим платформе возвращаемое значение функции.

Вызов осуществляется следующим образом: платформа передает нам номер вызываемого метода, массив фактических параметров и их количество. Мы должны проанализировать номер метода и скормить ему переданные параметры. В случае функции мы должны также записать что-то в возвращаемое значение.

 p

В примере номер метода анализируется в switch/case и в зависимости от номера выполняется логика метода. Для методов Включить/Выключить просто устанавливается флажок. Интересен метод ПоказатьВСтрокеСтатуса. Он показывает то, что ему передали в строке состояния окна 1С:Предприятия. Для этого используется объект подключения к платформе m_iConnect, тот, что был «выдан» нам при регистрации компоненты. Полный перечень его возможностей описан в документации.

Интересный момент. Здесь, в примере, не проверяется тип приехавшего из 1С значения, а просто вызывается SetStatusLine со строковой частью Variant. Я подозреваю, что если вызвать метод компоненты из языка 1С, передав туда число или дату (вместо строки), то работать ничего не будет… Опять же, пусть гуру поправят, но кажется, что указатель pwstrVal будет указывать неизвестно куда, если из предприятия приехало скажем, число, а не честная строка. При вызове SetStatusLine, платформа попытается прочитать с неизвестного адреса строку и, скорее всего, упадет. Лучше всегда проверять ожидаемый тип. Мало ли чего.

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

1

Во-первых, здесь проверяется количество переданных параметров. Если их нет, то вызов признается неудачным. Возвращается false, что трактуется платформой, как ошибка вызова.

Далее, здесь проверяется тип переданного параметра. Если это узкая строка (VTYPE_PSTR), то используется char-овая часть варианта. В примере написано paParam->pstrVal, но можно воспользоваться макросом TV_STR, будет то же самое, но еще и соблюдено единообразие работы с вариантом.

Если это широкая строка (VTYPE_PWSTR), то выполняется преобразование сначала к wchar_t, а затем к char. Дело в том, что нам из языка 1С в данный метод передается путь к файлу, который затем используется в функции fopen(char*). Эта функция на вход требует тип char*, а из платформы к нам придет WCHAR_T.  Для корректной работы и выполняются преобразования строк.

Ну и последнее, если это вообще не строка, то вызов признается неудачным, возвращается false.

Далее будет открыт файл, и в случае ошибки будет выдано сообщение (это код для краткости пропущен). Если все хорошо, то в 1С возвращаются двоичные данные картинки.

2

Мы выделяем память под двоичные данные менеджером памяти. Это логично, двоичные данные станут полноценным объектом внутри платформы, и распоряжаться ими должна именно она. Память выделяется для варианта pvarRetValue, представляющего собой возвращаемое значение функции внешней компоненты.

В выделенный буфер считывается файл целиком, кроме того, обязательно указывается байтовый размер в свойстве варианта strLen и тип данных варианта VTYPE_BLOB. Если память выделится удачно, то возвращаем true, как признак удачного вызова всей функции.

Таким образом, когда в языке 1С будет написано:

ДвоичныеДанные = Компонента.ЗагрузитьКартинку("C:\pic.jpg");

будет вызван метод CallAsFunc объекта компоненты с передачей пути и возвратом двоичных данных, как описано выше.

В случае успеха переменная ДвоичныеДанные будет содержать полноценный объект языка 1С. Когда он выйдет из области видимости вся занятая им память будет освобождена платформой. Именно поэтому выделялась она через менеджер памяти.

Заключение

Рассказ писался чайником для чайников, поэтому, скорее всего, пестрит терминологическими неточностями. Тем не менее, цель статьи – быстрое введение во внешние компоненты. Если в сжатые сроки, без лишних заморочек, без долгих разбирательств нужно быстро сделать компоненту, то я надеюсь, что эта статья вам поможет. Если от каких-либо моих ошибок вам, как гуру C++, стало плохо – сообщайте в комментариях, будем исправлять.

Спасибо за внимание.

См. также

Медиадисплей. Рекламный информационный монитор для покупателя.

Разработка внешних компонент POS терминал Рабочее место Розничная торговля Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Рестораны, кафе и фаст-фуд Реклама, PR и маркетинг Управленческий учет Платные (руб)

Монитор покупателя может отображать текущую покупку на кассовом месте, показывать видеорекламу, баннеры, во время простоя разворачивать рекламу на весь экран. Можно использовать в качестве графического меню-борда в кафе и видеовывески. Управление выводом на телевизор через hdmi-приставку на базе Windows или Android. В качестве устройства отображения можно использовать Android-планшеты, фоторамки с Android, монитор любого Windows-компьютера, доступного по сети. Настраивается ЛЮБОЙ ДИЗАЙН экрана!

16800 руб.

30.05.2017    52055    34    69    

43

Внешняя компонента для сканирования (замена TWAIN-компоненты БСП) (Native Win 32/64)

Разработка внешних компонент Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

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

2400 руб.

12.05.2020    26160    131    99    

82

Внешняя компонента печати PDF (Native Win 32/64)

Разработка внешних компонент Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

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

1500 руб.

17.09.2018    35012    104    123    

111

Мастер создания внешних компонент 1С (технология COM) для DELPHI 6/7/8/2005/2006/2007/2008/2010/XE/XE2/XE3

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

Средство для сверхбыстрой разработки внешних компонент 1С:Предприятия 7.7 и 8 по технологии COM на всех версиях DELPHI, начиная с 6.

2000 руб.

28.03.2013    53969    35    14    

68

Внешняя компонента для подключения 1С к телефонии Asterisk

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

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

2400 руб.

04.05.2018    44900    116    64    

60

QR-код с логотипом компании (обычная и управляемая форма)

Разработка внешних компонент Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Как известно, стремление сделать свою рекламную продукцию запоминающейся и выделяющейся — верный путь к успеху. Сегодня, мы поговорим с вами о том, что можно сделать с обычным черно-белым QR-кодом, чтобы он стал более живым и привлекательным. Если вам не терпится попробовать сделать QR-код с логотипом компании, то эта обработка для вас!

2400 руб.

22.06.2016    30822    4    4    

8

Внешняя компонента 1С и С++. Продолжаем разговор.

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

А давайте запилим 8.3.26 до релиза, или оповещение с сервера...

19.02.2024    3906    starik-2005    28    

52

Внешние компоненты 1С и язык C++

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

Некоторые практические аспекты создания внешних компонент на языке С++ для платформы 1С 8.3++.

26.01.2024    4680    starik-2005    32    

39
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
127. fixin 4252 17.12.20 15:06 Сейчас в теме
(102) ну так передавать массив можно, возвращать нельзя.
97. Evil Beaver 8100 10.08.18 12:47 Сейчас в теме
В С/С++ нет строк. Совсем. И объяснять что именно там вместо строк есть и как с этим жить - одного комментария не хватит.
98. Evil Beaver 8100 10.08.18 12:55 Сейчас в теме
Если взять Ваш кусок кода:

name = "Не удалось подключится к кассе"; // эти байты лежат на стеке текущего метода. После выхода из метода они уничтожатся.
// выделяем память, под строку, которую надо вернуть в 1С. Почему-то выделяем ее по адресу 3-го параметра... Скорее всего это неверно.
m_iMemory->AllocMemory((void**)&(paParams + 3)->pstrVal, sizeof(name));
TV_VT(paParams + 3) = VTYPE_PSTR;
TV_STR(paParams + 3) = name; // в указатель paParams[3]->pstrVal записали адрес байт, лежащих на стеке


// вернулись на уровень кода платформы

// 1. платформа передавала нам параметры метода как paParams, а ответ ждет в другом указателе - "что-то-там-result"
// 2. платформа грохает массив с переданными параметрами, т.к. он ей не нужен
// 3. в месте, где должен быть ответ - так и осталась пустая строка
// 4. память выделенная через AllocMemory - утекла или все-же по счастливой случайности освободилась (точнее скажут разрабы платформы).
99. markers 274 10.08.18 13:22 Сейчас в теме
(98) "в другом указателе - "что-то-там-result" это pvarRetValue? Странно, ибо
TV_VT(paParams + 2) = VTYPE_I4;
TV_INT(paParams + 2) = result;

передает в 1С значение result. Есть же входящие параметры и исходящие. Или я не правильно понял.
В любом случае, спасибо!
100. markers 274 28.08.18 07:40 Сейчас в теме
(99) Вот решение:
	name = "Failed to connect to VikiPrint";
	size = strlen(name);
	m_iMemory->AllocMemory((void**)&(paParams + 3)->pstrVal, size);
	TV_VT(paParams + 3) = VTYPE_PSTR;
	memcpy((void*)(paParams + 3)->pstrVal, name, size);
	(paParams + 3)->strLen = size;

Обратите внимание, чтоб возвращать сообщения на Русском языке, необходимо использовать функции получения размера и копирования значения в памяти для Unicode строк, ибо в ASCII таблице один символ занимает 1 байт и представленный в моём примере вариант получения размера строки под буфер strlen допустим для ASCII строк где размер занимаемый в памяти равняется количеству символов, но с Unicode таблицей это не работает, так как в ней каждый НЕ ASCII символ кодируется 2-4 байтами в зависимости от типа Unicode кодировки.
101. Evil Beaver 8100 28.08.18 18:50 Сейчас в теме
(100) Этот код некорректно будет работать с русскими буквами.

name - это неюникодная однобайтовая строка. Правильно объявить ее, как wchar_t, законвертить ее в двухбайтовую встроенным в шаблон компоненты методом и отправить в 1С, копируя в allocated-массив по 2 байта.
105. shanginre 06.02.19 08:14 Сейчас в теме
Коллеги, привет!

Такой важный вопрос. А внешнюю компоненту обязательно нужно делать только в вижуал студии, или можно в другой IDE сделать? По идее разницы никакой не должно быть, но спрашиваю на всякий случай, так как сами 1С на ИТС такую IDE рекомендовали...
106. tyasytova 29.06.19 18:07 Сейчас в теме
Большое спасибо! Собрала свою компоненту, но при подключении компоненты выходит ошибка {ВнешняяОбработка.СканированиеИРаспознавание.МодульОбъекта(302)}: Ошибка при вызове метода контекста (ПодключитьВнешнююКомпоненту)
КодВозврата = ПодключитьВнешнююКомпоненту("C:\repos\1CGetImageFragmentAddIn.dll", "1CGetImageFragmentAddIn", ТипВнешнейКомпоненты.Native);
по причине:
Недопустимое значение параметра (параметр номер '1') (Некорректное имя компоненты)
Может есть какие то тонкости по настройке проекта?
107. spacecraft 29.06.19 19:51 Сейчас в теме
(106)
КодВозврата = ПодключитьВнешнююКомпоненту("C:\repos\1CGetImageFragmentAddIn.dll", "1CGetImageFragmentAddIn", ТипВнешнейКомпоненты.Native);

Символическое имя компоненты не должно начинаться на цифру.
Из СП:

ПодключитьВнешнююКомпоненту(<Местоположение>, <Имя>, <Тип>)
Параметры:
<Имя> (обязательный)
Тип: Строка.
Символическое имя подключаемой внешнего компонента.
Имя должно удовлетворять правилам именования встроенного языка.
tyasytova; +1 Ответить
108. tyasytova 01.07.19 16:08 Сейчас в теме
(107) Спасибо помогло, компонента успешно устанавливается
И валится потом с ошибкой:
{ВнешняяОбработка.СканированиеИРаспознавание.МодульОбъекта(312)}: Тип не определен (AddIn.GetFragment.AddInNativeExtension)
109. markers 274 01.07.19 21:55 Сейчас в теме
(108)
	МакетСКомпонентой = "ОбщийМакет.ExtraComp";
	ИмяКомпоненты = "ExtraCompAddIn";
	ТребуетсяУстановкаКомпоненты = Не ПодключитьВнешнююКомпоненту(МакетСКомпонентой, ИмяКомпоненты);
	Если ТребуетсяУстановкаКомпоненты Тогда
		Попытка
			УстановитьВнешнююКомпоненту(МакетСКомпонентой);
			Если Не ПодключитьВнешнююКомпоненту(МакетСКомпонентой, ИмяКомпоненты) Тогда
				Возврат;
			КонецЕсли;
		Исключение
			Возврат;
		КонецПопытки;
	КонецЕсли;
	алкИнтерфейсКомпоненты = Новый("AddIn." + ИмяКомпоненты + "." + ИмяКомпоненты);
	алкКомпонентаПодключена = Истина;
	ВерсияКомпоненты = алкИнтерфейсКомпоненты.Version();
Показать
tyasytova; +1 Ответить
110. androgin 02.07.19 11:52 Сейчас в теме
(109) в исключении нужно выводить описание ошибки
111. markers 274 02.07.19 15:26 Сейчас в теме
(110) это уже по вкусу. Суть ответа не меняется. От куда копировал код, это не требовалось
112. heinzenberg 07.08.19 16:40 Сейчас в теме
Может кто подскажет, в чем может быть проблема.
Собираю компоненту из примера с итс, все работает.
Дополняю в *.h перечисление Methods. В *.cpp дополняю g_MethodNames, g_MethodNamesRu и методы HasRetVal, CallAsFunc. Собираю, ошибок нет.
При попытке установить внешнюю компоненту получаю ошибку: Установка внешней компоненты не выполнена! В процессе установки произошла ошибка! Возможно, отсутствует компонента для используемого клиентского приложения.

Возврат до первоначального состояния иногда приводит к работе, а иногда нет.
Что я не так делаю?
113. heinzenberg 07.08.19 16:51 Сейчас в теме
(112)upd
Видимо была проблема в том, что в рамках одного сеанса устанавливались несколько версий одной компоненты. При перезапуске 1С все чинится.
114. falces 22.11.19 07:37 Сейчас в теме
Автор, подскажи пожалуйста как бы ты реализовал получение списка окон 1С?
116. user1309444 22.11.19 08:29 Сейчас в теме
118. markers 274 22.11.19 08:31 Сейчас в теме
(116) Гуглите "Получение списка открытых окон C++"
117. markers 274 22.11.19 08:30 Сейчас в теме
(114) Я конечно не автор, но NativeAPI не подразумевает штатного взаимодействия с окнами 1С (в отличии от устаревшей технологии COM), следовательно взаимодействие с окнами 1С должно выполняться ровно так же, словно это обычная независимая программа. Это моё ИМХО.
119. user1309444 22.11.19 14:42 Сейчас в теме
(117) А как же "GetAppMDIFrame"? Или я ошибаюсь?
115. user1309444 22.11.19 08:27 Сейчас в теме
Подскажите пожалуйста кто может. Взял шаблон ВК с ИТС. Прописал методы и свойства. Хочу теперь чтобы по вызову свойства у меня возвращался список окон 1С. Как это реализовать? Что нужно прописать и самое главное где? Как ни пытался я что либо сделать - не получается. Прошу помощи плиз!
120. KingLion 24.11.19 13:59 Сейчас в теме
Доброго времени суток!
Сейчас в платформе рекомендован асинхронный режим вызова функций, но если создать компоненту в соответствии с этим шаблоном, то методы компонента будут вызываться в синхронном режиме. В таком случае если в свойствах конфигурации установить режим запрета синхронных вызовов, то пользоваться ими будет нельзя.
Подскажите пожалуйста, есть ли возможность создавать компоненты с асинхронными версиями методов?
Спасибо.
121. markers 274 24.11.19 15:01 Сейчас в теме
(120) Нет, платформа сама генерирует асинхронные вызовы для любой NativeAPI компоненты, просто перед методами нужно писать "НачатьВызов" для получения значения свойства в начале написать НачатьПолучение и для установки свойства НачатьУстановку. Для компоненты абсолютно ничего не меняется.
122. markers 274 24.11.19 15:15 Сейчас в теме
(121) Примеры:
Компонента.НачатьВызовИмяМетода(ОписаниеОповещения, Параметр1, Параметр2);
Описание процедуры в которую приходит ответ:
Процедура ВК_ПослеПолучения(Результат, Аргументы, Данные) Экспорт
Результат - результат выполнения функции, этот параметр отсутствует для процедуры
Аргументы - массив переданных параметров при вызове компоненты
Данные - Данные переданные при создании описания оповещения

Компонента.НачатьПолучениеВерсия(ОписаниеОповещения);
Описание процедуры в которую приходит ответ:
Процедура ВК_ПолучениеВерсии_Завершение(ВерсияКомпоненты, Данные) экспорт

Компонента.НачатьУстановкуРежим(ОписаниеОповещения, НовоеЗначение);
Описание процедуры в которую приходит ответ:
Процедура ВК_ПослеУстановкиРежима(Данные) экспорт
123. KingLion 24.11.19 16:14 Сейчас в теме
(122) Спасибо огромное. Теперь и в справке нашёл.
124. evgeny43 32 13.04.20 12:21 Сейчас в теме
Добрый день. Мне кажется что в объяснении в строках:

Вернемся к нашему коду. Во избежание «волшебных чисел» в классе CAddInNative объявлены два перечисления, отвечающие за определение номеров методов и свойств. Откроем файл CAddInNative.h и увидим их в самом начале:

CAddInNative.h вы скорее всего имели ввиду файл AddInNative.h ?
125. ilnur75 15.12.20 13:20 Сейчас в теме
Visual Studio 2019.
скачал данный пример ИТС.
сделал сборку для 64 разрядной виндовс 8.1.

Внешняя компонента в 1С подключается.
Только в отладчике в компоненте я вижу крякозабры.

как установить локализацию на рус.язык?
в учебнике нашел что обязательно должен быть главный метод int main() и потом можно установить локализацию.
А этом примере не используется этот метод, как сделать чтобы нормально читалось?
126. fixin 4252 17.12.20 15:05 Сейчас в теме
Как пример из 1С открыть в VS 2019?
Проект не открывает, пишет разные ошибки.
Может создать новый проект и подключить туда файлы, как?
128. lnnd 16 07.03.21 20:25 Сейчас в теме
У меня ошибка в шаблоне, подскажите, как исправить
Прикрепленные файлы:
129. tormozit 7133 22.07.21 22:50 Сейчас в теме
Сегодня отправил в 1С код своей ВК, созданной по этому шаблону и был удивлен замечанием
"нельзя выделять память для возврата значений с помощью new или malloc, т.к. это приведет к утечке памяти и к нестабильности работы программы" ( https://its.1c.ru/db/metod8dev#content:3221:hdoc )
Это я про функцию
long GetClassObject(const WCHAR_T* wsName, IComponentBase** pInterface)
{
    if(!*pInterface)
    {
        *pInterface= new CAddInNative;
        return (long)*pInterface;
    }
    return 0;
}
Показать
130. tormozit 7133 23.07.21 07:24 Сейчас в теме
(129) Тут исходный код https://github.com/tormozit/RDT_Common_1C/blob/master/AddInNative.cpp . Может ли внешняя компонента зависать на небольшом проценте рабочих мест из-за этого?
132. tormozit 7133 24.07.21 11:05 Сейчас в теме
131. tormozit 7133 24.07.21 11:04 Сейчас в теме
(129) Я неверно трактовал замечание. Некорректная работа с памятью у меня и в примере из статьи - в функции GetClassNames(), которая возвращает указатель на динамически выделенную во вложенном вызове convToShortWchar() память. Чтобы возвращать в 1С указатель на динамически выделяемую память, нужно выделять ее менеджером памяти платформы. Я же переделал на возвращение на статически выделенную память.
Evil Beaver; +1 Ответить
133. user670049_Decimusverum 23.08.21 00:24 Сейчас в теме
Добрый день, у нас есть проект по написанию внешней компоненты по технологии natıve apı для интеграции 1С и фискального регистратора, мы бы хотели с Вами сотрудничать.Можете пожалуйста поделится контактами?
134. markers 274 23.08.21 03:11 Сейчас в теме
(133) Я не разработчик драйверов, но вам достаточно взять требования к разработке драйверов подключаемого оборудования: https://its.1c.ru/db/metod8dev/content/4829/hdoc (есть версия 3.4, но я не смог её найти) и разрабатываете драйвер строго по ним. Так же там есть ссылка на общие рекомендации по написанию внешней компоненты для 1С
135. Quantum81 6 10.12.22 15:18 Сейчас в теме
Как новичку, бросилось в глаза:
Понимание того, что строк в чистом виде в C++ не существует, есть массивы, под которые явно требуется заморачиваться с памятью

https://en.cppreference.com/w/cpp/string
И вообще, сейчас там куча сахара в плюсах. При наличии string, map, set, vector ... auto, лямбд и прочего, на плюсах сча вполне спокойно можно питонить. Здесь же си подобные строки типа, но они так уж страшны и наверно если в либах поискать, наверняка есть функции по работе с ними.
Зеленой рамкой выделена строка, в которой объявлено имя класса. Честно признаюсь, я не вникал, что оно означает. Если его поменять, то ничего не работает. Поскольку изначально оговорились, что я «чайник», то мне простительно. :)

Как я понимаю, это имя экспортируемого класса. Класс мы переопределяем из абстрактного класса ComponentBase, который нам дают
class CAddInNative : public IComponentBase

Если присмотреться в CAddInNative.cpp, то там определяются "просто" функции и методы, и методы класса CAddInNative. см. скриншот.

Но тут я уже плаваю как новичок. Мы вроде бы в здесь сами создаем объект и передаем указатель на него в 1С. Но имя класса зачем-то все равно нужно платформе.
long GetClassObject(const WCHAR_T* wsName, IComponentBase** pInterface)
{
    if(!*pInterface)
    {
        *pInterface= new CAddInNative;
        return (long)*pInterface;
    }
    return 0;
}
Показать


Статья огонь. Не потеряла актуальности. Пойду дальше разбираться.
Прикрепленные файлы:
136. itfix 12.01.23 14:37 Сейчас в теме
(135)
https://en.cppreference.com/w/cpp/string
И вообще, сейчас там куча сахара в плюсах. При наличии string, map, set, vector ... auto, лямбд и прочего, на плюсах сча вполне спокойно можно питонить. Здесь же си подобные строки типа, но они так уж страшны и наверно если в либах поискать, наверняка есть функции по работе с ними.

std::string - это массив char символов;
char символы в сути своей - это int(ы).
Думаю автор данного высказывания это имел ввиду.
По мимо чисел в плюсах есть, например, указатели, которые не являются числами.
139. zels 171 16.02.23 06:50 Сейчас в теме
Как имея файл ВК (dll-ку) определить - она Native или COM?
140. markers 274 16.02.23 07:07 Сейчас в теме
(139) Если есть файл MANIFEST.xml то можно по нему узнать, вот пример манифеста, где в поле "type" указано что перед нами COM компонента:
<?xml version="1.0" encoding="UTF-8" ?>
<bundle xmlns="http://v8.1c.ru/8.2/addin/bundle">
    <component os="Windows" path="ScanOPOS.dll" type="COM" arch="i386" />
 </bundle>
Если же нет, то можно например открыть данную DLL программой PE Explorer (могут быть и другие программы, которые позволяют посмотреть ресурсы PE файла), где можно найти секцию TYPELIB и вот если она есть, то перед нами COM компонента.
https://i.imgur.com/m8TQ95e.png
141. zels 171 16.02.23 14:53 Сейчас в теме
140) Намек понял. Смущает, что в прикрепленном файле нет такой секции. Хотя судя по его имени должна быть...
Прикрепленные файлы:
IskraKKT_COM_2002_32_IskraKKT.dll
142. markers 274 16.02.23 15:59 Сейчас в теме
(141) Похоже что действительно COM. Этому есть два подтверждения:
1) Я нашел этот встроенный драйвер в конфиге, только более новой версии, он как две капли похож на ваш и в его манифесте, написано что он COM
2) Решил посмотреть секцию экспорта методов DLL и нашел различие, в вашем файле:
https://i.imgur.com/lSxYJlB.png
Есть методы присущие регистрации COM объекта. А вот какие экспортные методы у NativeAPI:
https://i.imgur.com/VOUxsV4.png
143. user1868425 30.06.23 10:09 Сейчас в теме
Я скачал ваш шаблон но он не компелируется из-за этой ошибки : error C2371: 'int8_t': redefinition; different basic types
Я не знаю что с этим делать , вроде sdtint.h нигде не используется
144. Evil Beaver 8100 30.06.23 12:33 Сейчас в теме
(143) проекты С++ могут не компилироваться по тысяче причин и мне сложно сказать, что конкретно у вас не так. Но вообще, статья уже очень старая и внешние компоненты нынче принято разрабатывать с помощью вот этого шаблона https://github.com/Infactum/addin-template. С ним делать компоненты намного проще. Но текст статьи все еще актуален и им можно руководствоваться. Так же автор шаблона показывает как им пользоваться вот тут https://www.youtube.com/live/Nf1Mn_r2NJQ?feature=share
Оставьте свое сообщение