Создание dll в delphi 7 для 1с
Есть dll без исходников, для нее есть интерфейс на delphi. Стоит задача подружить эту библиотеку с 1С. На сколько понял с прочитанного в интернете, на основе интерфейса можно сделать dll по COM технологии.
Как правильно написать такую dll, чтобы функция из примера была доступна из 1С?
Да, это враппер, причём достаточно простой. Но вопрос у вас общий, поэтому ответ - да, это реализуемо :)
> вопрос только зачем этот костыль нужен. а так хоть две промежуточных длл пишите. – teran Есть бизнес система с которой можно взаимодействовать через эту dll. Напрямую с 1С она не работает, поэтому приходится извращаться.
Может есть какая-нибудь статья или пример кода для похожего решения? Или хотя бы примерная структура для такой dll?
3 ответа 3
Ваша библиотека будет связующим звеном между 1C и сторонней библиотекой без исходного кода:
То, что вы описали - попытка реализовать связь:
Осталось реализовать связь между 1C и вашей библиотекой.
Чтобы начать разработку библиотеки по технологии COM в Delphi нужно выбрать: File -> New -> Other и там найти ActiveX Library, новый проект будет выглядить приблизительно так:
Далее к проекту добавить COM-сервер: File -> New -> Other и найти COM Object, выглядеть в новых версиях Delphi будет как-то так:
В старых версиях Delphi так:
В полях ClassName (CoClassName) нужно ввести английское название, по которому 1C и будет загружать вашу библиотеку после регистрации в системе, например: MaximLibrary1C
После написания прослойки (куда вы перенесете свой вышеописанный код) и окончания разработки на целевой машине вашу новую .dll нужно зарегистрировать в системе, как-то так:
Конечно, имя проекта лучше задать более вменяемое, а не Project1. На машине с Delphi зарегистрировать можно из среды в меню "Run". Из самой 1C вашу библиотеку после регистрации в системе можно будет загружать как-то так:
Насколько мне известно, многие 1С-ники хотели бы изучить написание внешних компонент, чтобы поднять свое магическое искусство 1С на качественно иную ступень.
Что этому может помешать? Во-первых, известный синдром компонентофобии (который исторически берет свое начало от криво написанных внешних компонент). Во-вторых –синдром клинически запутанного кода. OLE-программирование – это не самая простая штука, и, как говорится, «не всякая птица долетит до середины Днепра» (особенно, если эта «птица» – программист 1С).
Я предлагаю вашему вниманию шаблон внешней компоненты, который, как я надеюсь, достаточно прост для понимания (я постарался его значительно упростить по сравнению с типовым примером из «Технологии создания внешних компонент») и стабилен (везде, где это возможно, я использую обработку исключительных ситуаций).
Сборка проекта
Для компиляции примера потребуется среда разработки Delphi 6 или 7.
Файл проекта - TestVK.dpr.
Откройте этот файл (например, двойным щелчком мыши из Проводника).
Нажмите сочетание клавиш Ctrl-F9 (или пункт меню Project-Compile). Если все прошло нормально, в этой же папке образуется готовая внешняя компонента TestVK.dll (для проверки, а все ли хорошо, ее можно удалить, и получить готовую TestVK.dll еще раз).
Проверка работоспособности DLL
В комплект примера входит тестовая конфигурация 1С:Предприятие 7.7.
Переименование DLL
Первое, что я делаю при создании новой внешней компоненты – переименовываю уже существующий образец.
Переименуйте TestVK.dpr так, как вы хотите (например, MyVK.dpr).
Произведите замену всех вхождений подстроки TestVK в файлах проекта на нужное вам имя внешней компоненты.
Подсказка: чтобы открыть другие модули проекта, используйте пункт меню View-Units…
Программный код 1С, разумеется, также нужно не забыть изменить так, чтобы заменить все подстроки «TestVK».
Важно: замените значение CLSID внешней компоненты, чтобы новая DLL, с точки зрения Windows, стала действительно новой.
Чтобы сгенерировать новый CLSID, нажмите сочетание клавиш Ctrl-Shift-G.
Попробуйте скомпилировать новый проект – 1С должна «увидеть» вашу новую внешнюю компоненту, которая создана на основе другой ВК, но содержит полный набор ее свойств и методов.
Что такое свойства и методы?
Новички могут задаться вопросом, а что такое свойства и что такое методы?
В коде 1С свойства выглядят как, своего рода, «переменные», объекта, доступные через точку, например
Здесь объект – имеет имя vk (посмотрите, как он объявляется и инициализируется в глобальном модуле 1С).. Этот объект поддерживает свойства и методы.
В этом коде я установил свойству "Заголовок" текстовое значение (посмотрите, как будет работать пример, если установить этому свойству другое значение заголовка, например, «Здесь был romix», или не устанавливать его вовсе).
Метод объекта – это, своего рода, «функция» объекта, доступная «через точку».
Изменение списка свойств и методов ВК
В модуле AddinObj.pas за количество свойств отвечают участки кода, которые я пометил (*2*), (*5*), (*6*), (*8*), (*11*) а за количество методов - (*3*), (*7*), (*9*), (*10*), (*12*).
Я завел в шаблон по 5 свойств и методов, но что нужно сделать, чтобы их стало 6, например, в приведенном ниже фрагменте кода, - я надеюсь, понятно без объяснений.
Вы можете завести свойства и методы «с запасом» - лишние заготовки не повредят (их можно будет оставить пустыми).
Программирование функциональности свойств
Откройте (через меню View – Units…) модуль vk_object.pas
Для свойств вы увидите примерно такой код, продублированный, с небольшими отличиями, несколько раз: Это самая важная часть наших действий, которую важно постараться понять.
Что я здесь делаю?
Программирование функциональности методов
Для методов код похожий:
Этот абзац можно воспроизвести несколько раз (что и сделано в примере), заменив meth1 на meth2, meth3 и т.д.
Приведенные ниже строчки устанавливают русское и английское имя метода.
Попробуйте изменить то или другое, перекомпилировать проект и посмотреть, что получится.
я устанавливаю количество параметров метода. Попробуйте изменять это количество (например, установить значение 3) и посмотреть, что получится.
Подробнее код я опишу ниже – но сначала полезно потренироваться со вставкой в него отладочной печати (именно так я исследую код).
Возвращаемое значение функции
Чтобы вернуть значение из функции, надо установить переменную g_Value, например:
Отладочная печать
Вы можете в качестве теста вписать в функциональность метода что-то свое, например,
Этот вызов покажет стандартное окно предупреждения с кнопкой ОК. Или вот так:
Во втором случае, если Delphi будет ругаться при компиляции, добавьте Dialogs в раздел uses модуля.
Получение параметров функции
В своей функции я завел две переменные для хранения параметров:
Сейчас мы их заполним значениями, полученными из 1С.
Параметры нумеруются, начиная с 0 (давняя традиция программистов на языке С).
Чем отличаются AsString и AsInteger, надеюсь, понятно.
Этот код можно было бы написать и так:
Отладочная печать параметров
При отладке полученные из 1С значения полезно выводить на экран. Но как это сделать?
Я обычно использую следующий прием:
Чтобы показать строковые переменные, я пишу так:
А числовые значения и значение типа "дата-время" я отображаю примерно так:
Функциональность методов
Получив все значения из 1С, можно приступать к собственно написанию полезного кода.
Узнавать, как работают те или иные функции API, можно в поисковых машинах или в сборниках Delphi FAQ, которые в изобилии выложены в сети Интернет.
2.Г енератор проекта внешней компоненты, позволяющий получить готовый проект за несколько секунд. Остается только добавлять свойства и методы своей компоненты с помощью визуального редактора. Все идентификаторы, имена, интерфейсы уже прописаны генератором проекта.
Введение
Что это такое:
- Это компонент для DELPHI (любой версии), позволяющий значительно упростить создание внешних компонент 1С (технология COM)
- Это генератор проекта внешней компоненты, позволяющий получить готовый проект за несколько секунд. Остается только добавлять свойства и методы своей компоненты с помощью визуального редактора. Все идентификаторы, имена, интерфейсы уже прописаны генератором проекта.
Почему до сих пор создавать по технологии COM
- Эта технология дает возможность написания универсальной компоненты, которая будет работать для всех версий 1С:Предприятия под windows 7.7/8.0/8.1/8.2/8.3
- Многие старые компоненты написаны по этой технологии. Для создания их современной замены без изменения конфигурации 1С необходимо использовать именно эту технологию.
- Например, для подключения новых видов торгового оборудования к типовым программам, лишенным теперь внешних обработок обслуживания оборудования.
Почему DELPHI
- Относительно невысокая стоимость самой среды разработки.
- Обилие в сети бесплатных или дешевых компонент для работы с чем угодно.
- Наименьшее время разработки.
- Многие программисты 1С перешли с паскаля и им достаточно просто освоить DELPHI.
Почему мой проект, ведь полно в сети различных проектов на эту тему в том числе, бесплатных
- Включены все исходные коды.
- Готовый проект внешней компоненты 1С можно получить за несколько секунд, не разбираясь в том, как там что устроено.
- Экспортируются и используются все документированные 1С интерфейсы.
- Свойства и методы внешней компоненты можно добавлять визуально, как объекты обычной коллекции.
- Подробная документация
Начало работы
Содержимое архива
- 1C_ADDIN_HELPER. Компонент для DELPHI. Его надо установить. Инструкция ниже.
- 1C_ADDIN_ProjectCreator. Генератор проекта внешней компоненты. Инструкция ниже.
- 1C_ADDIN_DEMO. Демо-проект внешней компоненты, сделанный по данной технологии. Также включены обработки 1С 7.7 и 1С 8.2 для проверки работы компоненты. Инструкция ниже.
ШАГ 1. Установка компонента DELPHI
Добавляем путь к папке1C_ADDIN_HELPER в библиотеку DELPHI.
Меню: Tools – Environment options - Library path
Добавляем путь к папке1C_ADDIN_HELPER в библиотеку DELPHI.
Меню: Tools – options - Library –library path
Компонент появляется в палитре DELPHI
Компонент появляется в палитре DELPHI
Данный шаг необходимо выполнить один раз.
ШАГ 2. Генерация проекта внешней компоненты.- Запускаем PrCreator.exe из папки 1C_ADDIN_ProjectCreator
- Указываем:
- Путь к папке, в которой будет создан проект внешней компоненты
- Имя библиотеки внешней компоненты (имя dll-ки)
- Имя объекта внешней компоненты. Т.е имя, под которым ее объект можно будет создавать в 1С с помощью функций Новый() или СоздатьОбъект().
- Если у компоненты должна быть страница свойств, ставим галочку «Нужна страница свойств».
- Нажимаем большую кнопку «Создать». В указанной папке появляется DELPHI-проект внешней компоненты 1С с указанными параметрами.
- Его можно открывать в DELPHI.
ШАГ 3. Как добавлять функционал внешней компоненты.
- Весь функционал компоненты реализуется в модуле Un_DM_List.pas, основной объект которого унаследован от TDataModule. Это дает возможность простого использования компонентов из палитры компонент DELPHI.
- Добавление свойств и методов внешней компоненты осуществляется через коллекции (T1CMethCollection) и (T1CPropCollection) объекта AddinFPList уже добавленного в проект генератором проектов.
- Чтобы добавить свойство внешней компоненты 1С, щелкаем по (T1CPropCollection)
Добавляем элемент в коллекцию и прописываем его свойства:
- Английское название
- Русское название
- Признак «IsReadOnly» запрещает 1С записывать в это свойство что либо.
Описываем события у нашего свойства:
procedure TDM_List.AddinFPListProps0Get(var OldValue: OleVariant);
Это событие возникает, когда 1С пытается прочитать что либо из данного свойства. Прочитает она ровно то, что мы передадим в параметр OldValue. Тип OleVariant позволяет передавать строки, числа, даты, а также более сложные структуры, поддерживаемые 1С.
procedure TDM_List.AddinFPListProps0Set(var NewValue: OleVariant);
Это событие возникает, когда 1С пытается записать что либо в данное свойство. Значение, которое 1С хочет записать, содержится в переменной NewValue. Мы можем обработать его, как хотим. Например, сохранить в одном из свойств нашего объекта. Тип OleVariant может быть преобразован в строку, число, или дату явным присваиванием. Компилятор DELPHI в этом случае берет работу по преобразованию типов на себя.
- Чтобы добавить метод внешней компоненты 1С, щелкаем по (T1CMethCollection)
Добавляем элемент в коллекцию и прописываем его свойства:
- Английское название
- Русское название
- Количество параметров
- Признак «IsFunction» сообщит 1С, что этот метод может возвращать значения.
Описываем событие у нашего метода:
procedure TDM_List.AddinFPListMethods0Execute(var Params: PSafeArray;
В переменную Params 1C передает параметры метода. Получить их можно, используя функцию GetNParam , добавленную в проект генератором. Эта функция имеет два параметра. В первый передается массив Params, во второй – номер параметра, который мы хотим получить. Нумерация параметров с нуля!
Param1:=GetNParam(Params,0); //Получаем первый параметр из массива
Можно также записать в Params значение некоторого параметра. Тогда 1С получит это значение после вызова метода (параметры передаются по ссылке). Для этого можно использовать функцию PutNParam, также имеющуюся в проекте. Онаимеет три параметра. В первый передается массив Params, во второй – номер устанавливаемого параметра, в третий – значение, которое мы хотим передать. Нумерация параметров с нуля!
PutNParam(Params,0,Param1); //Установим значение первого параметра для 1С
Ну и в случае, если наш метод может возвращать значения, можно передать возвращаемое значение в переменную Ret. Тип OleVariant позволяет передавать строки, числа, даты, а также более сложные структуры, поддерживаемые 1С.
Ret:='Тест'; //Передаем строковое значение в качестве результата работы метода
Дополнительные возможности
- Объект DM_List экспортрует стандартные интерфейсы 1С:
- _pEvent : IAsyncEvent;
- _pErrorLog : IErrorLog;
- _pProfile : IPropertyProfile;
- _pStatusLine : IStatusLine;
Ими можно пользоваться в соответствии с их стандартным 1С-ким описанием. В поставляемом демо-проекте есть пример их использования.
- ВАЖНО: 1С-8 не реализует возможности интерфейса ExtWndSupport. Поэтому генератор проекта не добавляет экспорт этого интерфейса в проект. Вы можете сделать это самостоятельно в методе Init, описанном в AddInObj.pas.
- Опционально генератор проекта может добавить в проект страницу свойств компоненты.
Обмен данными между объектом компоненты и страницей свойств осуществляется через унаследованный интерфейс IPropertyLink. В модуле страницы свойств описаны два метода:
- UpdatePropertyPage. Запрашивает свойства из объекта и отображает их на форме страницы свойств.
- Вызывается метод get_Config объекта DM_List, описанный в модуле Un_DM_List.pas
- Передается структура TConfig, описанная в проекте в модуле AddInLib.pas . По сути это запись (RECORD).
- Что нужно сделать для того, чтобы добавить какой-либо параметр для передачи из компоненты в страницу свойств:
- Добавить элемент в структуру TRecord
- В методе get_Config объекта DM_List прописать его заполнение.
- В методе UpdatePropertyPage страницы свойств прописать его отображение на форме.
- Вызывается метод put_Config объекта DM_List, описанный в модуле Un_DM_List.pas
- Передается та же структура TConfig.
- Что нужно сделать для того, чтобы добавить какой-либо параметр для передачи со страницы свойств в компоненту:
- В методе UpdateObject страницы свойств прописать заполнение элемента структуры CFG по данным формы.
- В методе put_Config объекта DM_List прописать реакцию на изменение настройки со стороны страницы свойств.
- Методы LoadProps() и SaveProps() объекта DM_List.
- Данные методы вызываются автоматически при создании и уничтожении объекта, соответственно
Полезные знания
- Для того, чтобы в 1С-8 компоненту можно было подключать по имени объекта, т.е писать ПодключитьВнешнююКомпоненту(«Addin.MyObj»), файл внешней компоненты надо зарегистрировать в реестре с помощью команды regsvr32. В проекте, создаваемом генератором, добавлен командный файл Register.cmd, выполняющий это действие.
- Сложности могут возникнуть с передачей типа БУЛЕВО между 1С и внешней компонентой. 1С 7.7 такого типа вообще не знает. 1С-8 передает его в COM-компоненты в странном виде.
Описание демо-проекта, включенного в поставку
Причины купить
1. На создание проекта внешней компоненты всегда уходит время.
2. Добавлять свойства и методы внешней компоненты стандартными средствами долго и неудобно.
3. Мой проект позволит Вам сэкономить кучу времени
4. Ваше время дороже тысячи рублей:)
Достоинства
1.Включены все исходные коды.
2.Готовый проект внешней компоненты 1С можно получить за несколько секунд, не разбираясь в том, как там что устроено.
3.Экспортируются и используются все документированные 1С интерфейсы.
4.Свойства и методы внешней компоненты можно добавлять визуально, как объекты обычной коллекции.
5.Подробная документацияГарантия возврата денег
ООО "Инфостарт" гарантирует Вам 100% возврат оплаты, если программа не соответствует заявленному функционалу из описания. Деньги можно вернуть в полном объеме, если вы заявите об этом в течение 14-ти дней со дня поступления денег на наш счет.
Программа настолько проверена в работе, что мы с полной уверенностью можем дать такую гарантию. Мы хотим, чтобы все наши покупатели оставались довольны покупкой.
1CNativeLib - библиотека Delphi для создания внешних компонент (ВК) 1С по технологии Native API. Библиотека легка в использовании и позволяет заниматься непосредственно функционалом ВК, не отвлекаясь на соблюдение инструкций, предоставленных фирмой 1С.
Для того, чтобы создать ВК с помощью 1CNativeLib, достаточно создать проект DLL, написать класс с реализацией функционала вашей ВК и зарегистрировать этот класс при загрузке dll. Минимальный проект DLL с реализацией класса с одним методом выглядит так:
function Hello(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: integer): boolean;
function TMyClass.Hello(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: integer): boolean;
V8SetWString(RetValue,'Привет из Delphi!'); //устанавливаем результат функции
result := True; //Устанавливаем флаг, что функция завершилась успешно
with ClassRegList.RegisterClass(TMyClass, 'MySuperExtention', 'TMyClass') do
AddFunc('Hello', 'Привет', @TMyClass.Hello, 0); //регистрируем функцию
Всё необходимое содержится в одном модуле v8napi. pas. В прилагаемом архиве сам модуль, пример, более подробное описание и шаблон для нового проекта.
Специальные предложения
А может кто подскажет, можно ли в функцию ВК, написанную по NativeAPI, передавать массив или может структуру? И как это делать? В HasRetVal определил метод, как функцию, в GetNParams задал количество параметров данного метода - 1. Метод называется "Подключить". Если передаю скалярный параметр - все нормально (Компонента.Подключить(1)), а если пытаюсь передать массив или структуру (Компонента.Подключить(Массив)) - выдает ошибку в 1С - неверный аргумент.
Извините что не в тему, но мне тяжеловато работать с Делфями :cry:
Есть ли такое же только на С++? (Borland Builder или Visual C++)Возможно ли использование на FPC+Lazarus?
И еще - было бы неплохо и для v77 аналогичный ВК-класс сделать.Возможно ли использование ?
И еще - было бы неплохо и для v77 аналогичный ВК-класс сделать.
Для FPC+Lazarus надо допиливать. Сходу не заработало, но заработает.
Для v77 можно сделать, но вроде как уже и так хватает.есть возможность как то передавать не простые данные в ВК, а ссылки на элементы справочников или документов и уже внутри ВК с этими элементами работать?
если можно примерчик небольшой(9) Я так понимаю что не предусмотрен возврат и ссылок на таблицу значений или на какую другую коллекцию значений?
(13) Можно передавать только простые типы данных и вернуть из ВК двоичные данные. Вроде всё пока. Остальное 1С блокирует.
Скажите, пожалуйста, возможно ли с использованием NativeApi организовать поток (Delphi), который будет независимо выполнять определенные действия, и генерить в нужных ситуациях внешнее событие в 1С 8. В моем случае нужно опрашивать весы подключенные к com порту с периодичностью хотя бы раз в секунду и если они подключены при изменении веса отсылать данные в 1С. Обработчик ожидания не устраивает, так как 1С работает однопоточно и очень сильно висит при опросе com порта.
есть вопрос. Заключается он в том, что в ВК на технологии СОМ обработка ошибок во ВК производилась функцией RaiseLastOSError и все работает ОК, а вот теперь вроде сделал на Native API, и при вызове данной функции ВК, 1Ска закрывается (вылетает). какие методы есть решения? не подскажете.
(23) mur611,
V8.AddError(wcode: word; const source: PWideChar;
const descr: PWideChar;
scode: integer): boolean;см. документацию от 1С
есть вопрос, как вернуть массив? входные параметры функции - число, строка, а вот вернуть функция должна массив или olevariant, каа быть?
(25) igor_kav, только генерировать строку с внутренним представлением любой коллекции (массив, структура, список значений, и т.д.), а в 1С уже преобразуешь с помощью ЗначениеИзСтрокиВнутр(). К сожалению, я не смог найти ни одного внятного описания структуры внутреннего представления ТаблицыЗначений, а по всем остальным коллекциям формат довольно простой.
Сам на основе данного шаблона делал компоненту для внутреннего использования, с возвратом из функции массива. Если нужно, напиши, кину пример кода.Вот как раз и пример со структурой, у массива формат еще проще:
Кхм, понятия не имею. Честно говоря, ни разу за всю практику не сталкивался с необходимостью использования многомерных массивов. Но, если размышлять логически, то сам формат представления для массива таков:
Логично предположить, что если описание тпа подставить Массив, и а в значение - внутреннюю строку вложенного массива, то должно получиться то, что нужно.
Но надо проверять, конечно. Попозже гляну.
И действительно, для вложенных массивов достаточно в описание значения вместо строки передать строку , сформированную аналогично.Пару функций удалось сделать и использовать в 1С, но написал третью функцию в dll. при попытке использования в 1с именно этой третьей функции, 1с вылетает с ошибкой "Программа 1Сv8 не работает Возникшая проблема привела к прекращению работы программы. бла-бла". Самое интересное, что для тестирования создал проект VLC на delphi, поместил в него код функции. В VLC-проекте ФУНКЦИЯ РАБОТАЕТ!
Какие есть варианты решения?
поставил исключение в процедуре _CallAsFunc и получил ошибку:
Внешняя компонента : Invalid pointer operation.
Ошибка! : Ошибка при вызове метода контекста (ПолучитьМоиДанные): Ошибка внешней компонентыПрочитал, что СКОРЕЕ ВСЕГО УТЕЧКА ПАМЯТИ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ STRING, но как решить ума не приложу.
Кто сталкивался, ПОМОГИТЕ!
(41) от утечки памяти такого не бывает. такое бывает когда используешь указатель, который ни на что не указывает.
Но только в DLL, в EXE все нормально работает. В чем же все-таки причина?
(45) спасибо! :) ошибку нашел! все, как всегда, было банально просто. RIO не освобождал.
Спасибо за проделанную работу, очень нужную вещь ВК NativeAPI на Delphi создали.Можно ли передать функции параметр типа ТаблицаЗначений или XDTO пакет и как его потом в delphi разобрать?
(54) клиента 64 же не существует.
компилировалось Delphi XE2 и Delphi XE3.
в каталоге 1С есть .dt-шник, это база, где в общий макет залиты dll-ки с манифестом в зипе, dll-ки откомпилены delphi xe3, в любом случае все исходники там же
и есть обработка, которая запускает подключение компоненты на сервере
в любом случае, если есть возможность, попробуйте сами.
(58) vladon, попробуй такой вариант. у меня вроде работает. на сервере не проверял(нету у меня). проверял тестовой программой, которая загружает dll и читает список методов и свойств ВК. старая твоя ВК не грузилась, теперь стала грузиться. в архиве вариант модуля v8napi.pas. отпишись заработало или нет.
(63) не сочтите за наглость, но, так сказать, во избежание возможных недоразумений, можно при следующем обновлении в программных модулях указать тип лицензии на исходный код? например, Apache 2.0 (наиболее предпочтительная и либеральная), X11, или Modified BSD (неограниченное использование). или двойную лицензию GPL v2 и GPL v3 (на выбор пользователя).
хотим тут один небольшой проектик замутить на базе модуля для FreePascal под лицензией GPL v2, в целях экономии времени на рутину хотим использовать Ваш модуль ;-)
Мегаценная вещь, спасибо автору большое! Но возник вопрос, мне очень нужно сделать так, чтобы во время работы какой либо одной функции вызванной по nativeapi из 1С, произошла передача данных (к примеру установка свойства формы или генерация внешенего события с передачей данных в 1С). Например:
//процедура вызываемая из 1С
function TMyClass.SleepFunc(RetValue: PV8Variant; Params: PV8ParamArray; const ParamCount: integer; var v8:TV8AddInDefBase): boolean;
var
ms: Integer;
begin
ms := V8AsInt(@Params[1]); // к примеру 100.000
//тут хочу вызвать исключение в 1С и передать в него строку "Привет я пошел спать!" или как-то иначе
sleep(ms);
//допустим тут еще раз хочу вызвать исключение
//или установить свойство заголовка на форме или переменной модуля 1С. "Привет я проснулся!"
result := True; //завершается вызванная функция
end;
После некоторых исследований, было установлено, что к примеру если вызвать во время работы функции sleep (или любой другой) функцию, например, вызова внешнего события, то оно генерируется не в то время, где я вызываю ExternalEvent, а только по выходу из основной функции. То есть у меня никак не получается передавать в 1С, например строку промежуточного результата работы функции во время ее работы. Все уходит в 1С только по выходу из нее. Как решить подобную задачу?в модуле для FPC не нашёл функцию V8SetPWideChar ( возврат в 1С строки, представленной в FPC типом PWideChar )
дописал. может, кому, пригодится:
в модуле для FPC ошибка в function _GetParamDefValue, вызывающая падение в случае, если параметры по умолчанию не заданы, а 1с видит, что методу передано меньше параметров и пытается запросить параметр по умолчанию
правильный вариант кода:
что-то не ясен момент: в описании технологии Native API сказано, что BLOB (Двоичные данные) могут только возвращаться из компоненты в 1С, про передачу BLOB из 1С в компоненту ничего не сказано. при попытке передать ДвоичныеДанные в параметре метода 1С ругается на неверный параметр (до компоненты даже дело не доходит).
однако в Вашем модуле есть функция по получению BLOB V8AsBlob(). У Вас получилось передать ДвоичныеДанные в компоненту? не поделитесь рецептом?(69) andrewks, я не помню, что пробовал. ну если не дает, то значит нельзя. А V8AsBlob() наверное на всякий случай сделал.
Раз уж добавили поддержку Lazarus, может попробуем и под Linux скомпилить?
Вот тут есть готовая виртуальная машина с установленным Lazarus , попробовал в нем скомпилить выложенную демку, но она не подключается в контексте сервера 1С под x64 Ubuntu. Есть мысли? Спасибо!(74) У меня нет к сожалению ни одной ВК под linux, поэтому трудно сказать, дал бы кто попробовать.
(75) andrewks, ну и что, главное что стоит настроенный Lazarus и компилит, в т.ч. и приложенный тут пример ВК(76) UncleVader, я к тому, что если у Вас есть доступ к серваку с убунтой х64, то, может, стоит скомпилить прямо на нём? у меня на ноуте стоит убунта, но она там х32
(77) andrewks, Чтоб на нем скомпилить туда надо поставить Lazarus, а для меня это китайская грамота ((
Во вложении скомпиленная в упомянутой (73) системе, попробуйте может у Вас подключитсяНу ты в отладчике посмотри где глючит. А ProcessMessages тебе зачем? Поставь вместо ProcessMessages sleep(0) для начала.
(82)Я так и со слипом пробовал бесполезно! Попробуй у себя проверить мой код.
Выдает ошибку и вылетает 1с именно когда запускается поток ReadThread(83) SerG_121, видимо, у Вас исключение вылетает. попробуйте в try/except и выводить лог, может, прояснится
(83) SerG_121, Ты создаешь объект в 1с. Выполняешь его метод ОткрытьПорт. В методе ОткрытьПорт создается поток, который использует объект. Но объект после выполнения ОткрытьПорт автоматически убивается, но в потоке к нему есть обращение в Execute. Обращение к несуществующему объекту. Наверное по этому и глючит.
Собрал ВК в Lazarus.
Нашел небольшой глюк: если передать в функцию ФункцияПривет2 пустые строки, то платформа "валится"(89) TamDE, что-то не так в Вашем королевстве.
1. эта функция отвечает за возвращаемые значения, а не за передаваемые
2. L не может быть равно 0
3. у меня падения на пустых строках нетВ Linux таки не работает.
Платформа грузит .so, вызывает несколько функций и валится по SIGSEGV.
Вот что успевает вызвать:
[quote]
GetClassNames
GetClassObject
_setMemManager
_GetInfo
[/quote]
После этого падение. Пока причину понять не смог, может быть будут идеи?(91) Отладчик ловит исключение, и в качестве адреса показывает нулевые адреса. Бред полный :)
Ещё немного поразбирался - судя по всему причина в том, что под Linux 1С компилируется с использованием GCC, а у него виртуальная таблица методов в памяти имеет другую структуру.
Получается что "грязный" хак, с помощью которого вообще работает эта библиотека не срабатывает, т.к. TV8ProcRec не соответствует IComponentBase.Пока что удалось добиться таки вызова RegisterExtensionAs добавлением парочки пустых полей с типом Pointer, но теперь другая проблема - V8MM.AllocMemory() возвращает false.
(95) Magister, немного наблюдений:
в Win 1с вызывает функции в таком порядке:
Initialization
GetClassObject()
_Init()
_setMemManager()
_SetLocale()
_GetInfo()
_RegisterExtensionAs()
.
_Done()
DestroyObject()
Finalizationв Lin:
Initialization
GetClassObject()
_setMemManager()
_GetInfo()
далее - падение до захода в _RegisterExtensionAs()почему-то в линуксе обходится стороной _Init()
(92) Magister, похоже, проблема с менеджером памяти. только у меня при попытке вызова AllocMemory() - сразу крах. пытаюсь в _setMemManager() вызвать AllocMemory() - в винде успешно, память выделяется, в лин - сразу крах.
что-то с описанием интерфейса, может? соглашение о вызове, думаю, тут ни при чём
1CNativeLib - библиотека Delphi для создания внешних компонент (ВК) 1С по технологии Native API. Библиотека легка в использовании и позволяет заниматься непосредственно функционалом ВК, не отвлекаясь на соблюдение инструкций, предоставленных фирмой 1С.
Для того, чтобы создать ВК с помощью 1CNativeLib, достаточно создать проект DLL, написать класс с реализацией функционала вашей ВК и зарегистрировать этот класс при загрузке dll. Минимальный проект DLL с реализацией класса с одним методом выглядит так:
function Hello(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: integer): boolean;
function TMyClass.Hello(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: integer): boolean;
V8SetWString(RetValue,'Привет из Delphi!'); //устанавливаем результат функции
result := True; //Устанавливаем флаг, что функция завершилась успешно
with ClassRegList.RegisterClass(TMyClass, 'MySuperExtention', 'TMyClass') do
AddFunc('Hello', 'Привет', @TMyClass.Hello, 0); //регистрируем функцию
Всё необходимое содержится в одном модуле v8napi. pas. В прилагаемом архиве сам модуль, пример, более подробное описание и шаблон для нового проекта.
Специальные предложения
А может кто подскажет, можно ли в функцию ВК, написанную по NativeAPI, передавать массив или может структуру? И как это делать? В HasRetVal определил метод, как функцию, в GetNParams задал количество параметров данного метода - 1. Метод называется "Подключить". Если передаю скалярный параметр - все нормально (Компонента.Подключить(1)), а если пытаюсь передать массив или структуру (Компонента.Подключить(Массив)) - выдает ошибку в 1С - неверный аргумент.
Извините что не в тему, но мне тяжеловато работать с Делфями :cry:
Есть ли такое же только на С++? (Borland Builder или Visual C++)Возможно ли использование на FPC+Lazarus?
И еще - было бы неплохо и для v77 аналогичный ВК-класс сделать.Возможно ли использование ?
И еще - было бы неплохо и для v77 аналогичный ВК-класс сделать.
Для FPC+Lazarus надо допиливать. Сходу не заработало, но заработает.
Для v77 можно сделать, но вроде как уже и так хватает.есть возможность как то передавать не простые данные в ВК, а ссылки на элементы справочников или документов и уже внутри ВК с этими элементами работать?
если можно примерчик небольшой(9) Я так понимаю что не предусмотрен возврат и ссылок на таблицу значений или на какую другую коллекцию значений?
(13) Можно передавать только простые типы данных и вернуть из ВК двоичные данные. Вроде всё пока. Остальное 1С блокирует.
Скажите, пожалуйста, возможно ли с использованием NativeApi организовать поток (Delphi), который будет независимо выполнять определенные действия, и генерить в нужных ситуациях внешнее событие в 1С 8. В моем случае нужно опрашивать весы подключенные к com порту с периодичностью хотя бы раз в секунду и если они подключены при изменении веса отсылать данные в 1С. Обработчик ожидания не устраивает, так как 1С работает однопоточно и очень сильно висит при опросе com порта.
есть вопрос. Заключается он в том, что в ВК на технологии СОМ обработка ошибок во ВК производилась функцией RaiseLastOSError и все работает ОК, а вот теперь вроде сделал на Native API, и при вызове данной функции ВК, 1Ска закрывается (вылетает). какие методы есть решения? не подскажете.
(23) mur611,
V8.AddError(wcode: word; const source: PWideChar;
const descr: PWideChar;
scode: integer): boolean;см. документацию от 1С
есть вопрос, как вернуть массив? входные параметры функции - число, строка, а вот вернуть функция должна массив или olevariant, каа быть?
(25) igor_kav, только генерировать строку с внутренним представлением любой коллекции (массив, структура, список значений, и т.д.), а в 1С уже преобразуешь с помощью ЗначениеИзСтрокиВнутр(). К сожалению, я не смог найти ни одного внятного описания структуры внутреннего представления ТаблицыЗначений, а по всем остальным коллекциям формат довольно простой.
Сам на основе данного шаблона делал компоненту для внутреннего использования, с возвратом из функции массива. Если нужно, напиши, кину пример кода.Вот как раз и пример со структурой, у массива формат еще проще:
Кхм, понятия не имею. Честно говоря, ни разу за всю практику не сталкивался с необходимостью использования многомерных массивов. Но, если размышлять логически, то сам формат представления для массива таков:
Логично предположить, что если описание тпа подставить Массив, и а в значение - внутреннюю строку вложенного массива, то должно получиться то, что нужно.
Но надо проверять, конечно. Попозже гляну.
И действительно, для вложенных массивов достаточно в описание значения вместо строки передать строку , сформированную аналогично.Пару функций удалось сделать и использовать в 1С, но написал третью функцию в dll. при попытке использования в 1с именно этой третьей функции, 1с вылетает с ошибкой "Программа 1Сv8 не работает Возникшая проблема привела к прекращению работы программы. бла-бла". Самое интересное, что для тестирования создал проект VLC на delphi, поместил в него код функции. В VLC-проекте ФУНКЦИЯ РАБОТАЕТ!
Какие есть варианты решения?
поставил исключение в процедуре _CallAsFunc и получил ошибку:
Внешняя компонента : Invalid pointer operation.
Ошибка! : Ошибка при вызове метода контекста (ПолучитьМоиДанные): Ошибка внешней компонентыПрочитал, что СКОРЕЕ ВСЕГО УТЕЧКА ПАМЯТИ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ STRING, но как решить ума не приложу.
Кто сталкивался, ПОМОГИТЕ!
(41) от утечки памяти такого не бывает. такое бывает когда используешь указатель, который ни на что не указывает.
Но только в DLL, в EXE все нормально работает. В чем же все-таки причина?
(45) спасибо! :) ошибку нашел! все, как всегда, было банально просто. RIO не освобождал.
Спасибо за проделанную работу, очень нужную вещь ВК NativeAPI на Delphi создали.Можно ли передать функции параметр типа ТаблицаЗначений или XDTO пакет и как его потом в delphi разобрать?
(54) клиента 64 же не существует.
компилировалось Delphi XE2 и Delphi XE3.
в каталоге 1С есть .dt-шник, это база, где в общий макет залиты dll-ки с манифестом в зипе, dll-ки откомпилены delphi xe3, в любом случае все исходники там же
и есть обработка, которая запускает подключение компоненты на сервере
в любом случае, если есть возможность, попробуйте сами.
(58) vladon, попробуй такой вариант. у меня вроде работает. на сервере не проверял(нету у меня). проверял тестовой программой, которая загружает dll и читает список методов и свойств ВК. старая твоя ВК не грузилась, теперь стала грузиться. в архиве вариант модуля v8napi.pas. отпишись заработало или нет.
(63) не сочтите за наглость, но, так сказать, во избежание возможных недоразумений, можно при следующем обновлении в программных модулях указать тип лицензии на исходный код? например, Apache 2.0 (наиболее предпочтительная и либеральная), X11, или Modified BSD (неограниченное использование). или двойную лицензию GPL v2 и GPL v3 (на выбор пользователя).
хотим тут один небольшой проектик замутить на базе модуля для FreePascal под лицензией GPL v2, в целях экономии времени на рутину хотим использовать Ваш модуль ;-)
Мегаценная вещь, спасибо автору большое! Но возник вопрос, мне очень нужно сделать так, чтобы во время работы какой либо одной функции вызванной по nativeapi из 1С, произошла передача данных (к примеру установка свойства формы или генерация внешенего события с передачей данных в 1С). Например:
//процедура вызываемая из 1С
function TMyClass.SleepFunc(RetValue: PV8Variant; Params: PV8ParamArray; const ParamCount: integer; var v8:TV8AddInDefBase): boolean;
var
ms: Integer;
begin
ms := V8AsInt(@Params[1]); // к примеру 100.000
//тут хочу вызвать исключение в 1С и передать в него строку "Привет я пошел спать!" или как-то иначе
sleep(ms);
//допустим тут еще раз хочу вызвать исключение
//или установить свойство заголовка на форме или переменной модуля 1С. "Привет я проснулся!"
result := True; //завершается вызванная функция
end;
После некоторых исследований, было установлено, что к примеру если вызвать во время работы функции sleep (или любой другой) функцию, например, вызова внешнего события, то оно генерируется не в то время, где я вызываю ExternalEvent, а только по выходу из основной функции. То есть у меня никак не получается передавать в 1С, например строку промежуточного результата работы функции во время ее работы. Все уходит в 1С только по выходу из нее. Как решить подобную задачу?в модуле для FPC не нашёл функцию V8SetPWideChar ( возврат в 1С строки, представленной в FPC типом PWideChar )
дописал. может, кому, пригодится:
в модуле для FPC ошибка в function _GetParamDefValue, вызывающая падение в случае, если параметры по умолчанию не заданы, а 1с видит, что методу передано меньше параметров и пытается запросить параметр по умолчанию
правильный вариант кода:
что-то не ясен момент: в описании технологии Native API сказано, что BLOB (Двоичные данные) могут только возвращаться из компоненты в 1С, про передачу BLOB из 1С в компоненту ничего не сказано. при попытке передать ДвоичныеДанные в параметре метода 1С ругается на неверный параметр (до компоненты даже дело не доходит).
однако в Вашем модуле есть функция по получению BLOB V8AsBlob(). У Вас получилось передать ДвоичныеДанные в компоненту? не поделитесь рецептом?(69) andrewks, я не помню, что пробовал. ну если не дает, то значит нельзя. А V8AsBlob() наверное на всякий случай сделал.
Раз уж добавили поддержку Lazarus, может попробуем и под Linux скомпилить?
Вот тут есть готовая виртуальная машина с установленным Lazarus , попробовал в нем скомпилить выложенную демку, но она не подключается в контексте сервера 1С под x64 Ubuntu. Есть мысли? Спасибо!(74) У меня нет к сожалению ни одной ВК под linux, поэтому трудно сказать, дал бы кто попробовать.
(75) andrewks, ну и что, главное что стоит настроенный Lazarus и компилит, в т.ч. и приложенный тут пример ВК(76) UncleVader, я к тому, что если у Вас есть доступ к серваку с убунтой х64, то, может, стоит скомпилить прямо на нём? у меня на ноуте стоит убунта, но она там х32
(77) andrewks, Чтоб на нем скомпилить туда надо поставить Lazarus, а для меня это китайская грамота ((
Во вложении скомпиленная в упомянутой (73) системе, попробуйте может у Вас подключитсяНу ты в отладчике посмотри где глючит. А ProcessMessages тебе зачем? Поставь вместо ProcessMessages sleep(0) для начала.
(82)Я так и со слипом пробовал бесполезно! Попробуй у себя проверить мой код.
Выдает ошибку и вылетает 1с именно когда запускается поток ReadThread(83) SerG_121, видимо, у Вас исключение вылетает. попробуйте в try/except и выводить лог, может, прояснится
(83) SerG_121, Ты создаешь объект в 1с. Выполняешь его метод ОткрытьПорт. В методе ОткрытьПорт создается поток, который использует объект. Но объект после выполнения ОткрытьПорт автоматически убивается, но в потоке к нему есть обращение в Execute. Обращение к несуществующему объекту. Наверное по этому и глючит.
Собрал ВК в Lazarus.
Нашел небольшой глюк: если передать в функцию ФункцияПривет2 пустые строки, то платформа "валится"(89) TamDE, что-то не так в Вашем королевстве.
1. эта функция отвечает за возвращаемые значения, а не за передаваемые
2. L не может быть равно 0
3. у меня падения на пустых строках нетВ Linux таки не работает.
Платформа грузит .so, вызывает несколько функций и валится по SIGSEGV.
Вот что успевает вызвать:
[quote]
GetClassNames
GetClassObject
_setMemManager
_GetInfo
[/quote]
После этого падение. Пока причину понять не смог, может быть будут идеи?(91) Отладчик ловит исключение, и в качестве адреса показывает нулевые адреса. Бред полный :)
Ещё немного поразбирался - судя по всему причина в том, что под Linux 1С компилируется с использованием GCC, а у него виртуальная таблица методов в памяти имеет другую структуру.
Получается что "грязный" хак, с помощью которого вообще работает эта библиотека не срабатывает, т.к. TV8ProcRec не соответствует IComponentBase.Пока что удалось добиться таки вызова RegisterExtensionAs добавлением парочки пустых полей с типом Pointer, но теперь другая проблема - V8MM.AllocMemory() возвращает false.
(95) Magister, немного наблюдений:
в Win 1с вызывает функции в таком порядке:
Initialization
GetClassObject()
_Init()
_setMemManager()
_SetLocale()
_GetInfo()
_RegisterExtensionAs()
.
_Done()
DestroyObject()
Finalizationв Lin:
Initialization
GetClassObject()
_setMemManager()
_GetInfo()
далее - падение до захода в _RegisterExtensionAs()почему-то в линуксе обходится стороной _Init()
(92) Magister, похоже, проблема с менеджером памяти. только у меня при попытке вызова AllocMemory() - сразу крах. пытаюсь в _setMemManager() вызвать AllocMemory() - в винде успешно, память выделяется, в лин - сразу крах.
что-то с описанием интерфейса, может? соглашение о вызове, думаю, тут ни при чём
Читайте также:
- UpdatePropertyPage. Запрашивает свойства из объекта и отображает их на форме страницы свойств.