1CNativeLib - бесплатная библиотека Delphi для создания внешних компонент (ВК) 1С по технологии Native API.
Новая версия.
16.12.2015 Исправлена ошибка: поиск свойств и методов ВК выполнялся с учетом регистра букв.
06.10.2015 Исправлена ошибка: сообщение "некорректная работа компоненты с памятью"
Просто структура класса не такая получается. Компилятор другой - вот и всё, баста.
Думаю, правильным путем было бы создание "обертки" на C++, которая бы уже общалась с FreePascal. Иначе гиблое это дело, как мне кажется...
Сейчас вот добился вызова методов:
[quote]GetClassNames
GetClassObject
_Init
_setMemManager
_RegisterExtensionAs[/quote]
Вот откуда тут _RegisterExtensionAs? Ведь, судя по логике, должен быть _SetLocale.
Вывод - в том месте, где у нас находится _RegisterExtensionAs, должен находится _SetLocale.
Это, в принципе, объясняет и падение на RegisterExtensionAs - т.к. SetLocale по параметрам отличается.
upd. Да, так и есть. Подставил туда _SetLocale - получил параметром строку своей локали. Т.е. я всё правильно понял.
(99) В принципе можно и так. Просто "обертка" - это "идеологически" правильный путь :)
(100) не поможет, как и написал andrewks Дело именно в структуре класса в памяти. GCC создает другую структуру, не совместимую с MSVC. И написанное мной выше подтверждает это.
меня больше другой вопрос заинтересовал - зачем понадобилось извращаться через пакед рекорды TV8ObjectRec, TV8ProcRec, и почему не работает через интерфейс/класс, как это сделано в родном примере на С++
(100) Александр, поскольку линукса у Вас нет, и тема "поднятия" модуля на этой платформе Вам, видимо, не очень интересна, Вы не будете против, если я создам публикацию с форком модуля, посвящённым решению этой проблемы?
в родном примере объявляются три интерфейса:
IInitDoneBase, ILanguageExtenderBase, LocaleBase
далее - класс IComponentBase, объединяющий в себе все три этих интерфейса
и конечный юзерский класс уже просто объявляется как наследник IComponentBase
и именно конечный класс потом используется для создания объекта в GetClassObject и помещается в IComponentBase** pInterface
никаких структур, никакого хардкора.
осталось только понять, как это записать на FPC, чтобы родная схема взлетела. в лоб у меня пока не получилось - интерфейсы объявил, класс, объект создаю, возвращаю его 1С, затем - сразу падение. ни один метод не вызывается вопрос отпал, освежил теорию. только извращения через рекорды, или делать отдельную интрефейсную прокси-библиотеку, что, в общем-то, тоже будет извратом
(109) Ну почему все так не любят читать документацию?
Почитайте описание NativeAPI от 1С, там всё написано.
Передавать можно только простые типы. Объекты - нет.
Респект автору но у меня из демо примера не работает на веб... на тонком все работает на веб пишет "Тип не определен"... что я не правильно делаю.. заранее спасибо
При компиляции проекта, который указан в публикации, на lazarus, вылетает ошибка на коде регистрации функции
AddFunc('Hello', 'Привет', @TMyClass.Hello, 0);
miniVK.lpr(24,49) Error: Incompatible type for arg no. 3: Got "<address of function(PV8Variant,PV8ParamArray,const LongInt):Boolean of object;Register>", expected "PV8CallAsFunc"
Пробовал на win 7 32бит и 64бит, также пробовал с компонентой от andrewks, та же ошибка.
Может кто-нибудь помочь?
\demo.dll","DemoLib",AddInType.Native);
ИмяМакета = "ОбщийМакет.ТестВК";
Если НЕ ПодключитьВнешнююКомпоненту(ИмяМакета,"DemoLib",AddInType.Native) Тогда
НачатьУстановкуВнешнейКомпоненты(Новый ОписаниеОповещения("ЗагрузкаВК",
&НаКлиенте
Процедура ЗагрузкаВК(Парам) экспорт
Если ПодключитьВнешнююКомпоненту(ИмяМакета,"DemoLib",AddInType.Native) Тогда
СоздатьОбъектВК();
КонецЕсли;
КонецПроцедуры
Александр, спасибо за разработку! Просто мегаполезная вешь!
Написал на её основе свою ВК, все замечательно работает и на клиенте, и на сервере.
Сейчас столкнулся вот с какой проблемой: До этого момента сервер 1С Предприятия стоял 32-разрядный на Windows Server 2008 x64, после установки x64 сервера 1C не удается подключить компоненту.
Ошибка происходит только в методах, выполняемых &НаСервере. При попытке вызвать функцию
1С-ка подвисает на несколько секунд, а затем выдает ошибку сетевого доступа.
При этом может выкинуть из программы некоторых пользователей, вне зависимости от того с какой базой они работают.
Если подключать компоненту, скомпилированную под x86, то функция просто возвращает Ложь и работа продолжается. Пробовал подключать компоненту как из файла, так и из общего макета с манифестом - результат всегда один.
При подключении с клиента, функции ВК вызываются как обычно:
_Init
_setMemManager
_SetLocale
_GetInfo
_RegisterExtensionAs
А на сервере эта же последовательность вызывается аж 11 раз, после чего все падает.
Может есть какие мысли по этому поводу? Как можно решить возникшую проблему?
(119) Пробовал, правда делал это впопыхах. RAD Studio дико ругалась на тот v8napi, арифметика с указателями ей не нравилась, быстренько поправил, скомпилировал, но в итоге и на клиенте и на сервере ПодключитьВнешнююКомпоненту возвращает Ложь. Может сам чего намудрил, конечно. Лазарусом воспользоваться не смог, т.к. там нет некоторых модулей для моей компоненты.
Пробовал, кстати, скомпилировать простой sample из вашего архива. В результате тоже рвется соединение при попытке подключить компоненту.
Юзаю demo.dll на Вин7х64. Движок 8.3.5.1383 - Управляемые формы, 1С запущена от имени Одмина. Компонента подключается нормально (возвращает истину), создается объект норм, видно пару его реквизитов. А вот когда идет обращение к первой функции из примера работы с компонентой из 1С: сама 1С вылетает по ошибке. У меня есть свои компоненты написанные по .СОМ - работают норм.. чо не так?
Создал свой длл из шаблона - вроде норм. Работает на стороне сервера в тонком клиенте, что мне и требовалось. Вопрос снят
Здравствуйте. Каким образом мне скачать эту библиотеку? Я разработчик, но инфостарт требует от меня денег за получение ссылки на закачку бесплатной компоненты.
Может мне кто-то помочь и дать ссылку на эту компоненту?
Возникает при посылке внешним приложением сообщения, сформированного в специальном формате. Внешнее событие сначала обрабатывается всеми открытыми формами, имеющими процедуру-обработчик этого события, а затем может быть обработано в процедуре-обработчике модуля управляемого приложения (модуля обычного приложения).
Примечание:
Обработка следующего события возможна только после завершения обработки текущего события.
x32 пробовал только файловый вариант ИБ, (сервер приложений не тестил), в файловой ИБ x32 вызываю процедуру "ПодключитьВнешнююКомпоненту()", возвращает истину, выгружаю базу на сервер приложений x64 - там возвращает ложь:
(132) Прошу прощения, сам баран (не иначе) скомпилировал проект под Win32 и еще хочу, чтобы он под Win64 поехал. Все работает, спасибо. Извините за беспокойство. :) И еще раз спасибо Вам за бесценную вещь в виде v8napi!!!
Не хватает реализации метода SetPlatformCapabilities
Похоже, что без него запустить компоненту можно только в клиенте 1С.
Под IE или FireFox постоянно кричит, что клиент не поддерживается.
Функция должна вернуть доступные возможности, а её нет.
Можете доделать ?
Вообще слов нет! Просто бомба. Спасибо тебе автор за это произведение искусства! А главное, что ты продолжаешь поддержку своего детища, другие годами не обновляют свои шаблоны внешних компонент. И главное, что разработка на Delphi - в наше время все меньше людей которые пишут на Delphi. Даже на ИТС примеров на Delphi уже не делают :( Очень печально, хотя новый Delphi вновь набирает обороты. Продолжай развивать данную разработку.
Добрый день!
Написал вот свой класс драйвера для ФР по правилам "1С: Совместимо" на Delphi с использованием модуля v8napi.pas. Подключаюсь толстым клиентом к локальной ИБ.
При попытке установить драйвер в 1С 8.3 (Управление торговлей 11.2), из файла указываю путь к zip-архиву с драйвером. Manifest.xml и Info.xml бодро подхватываются и видно информацию о драйвере. Дальше вот наблюдаю такую картину: при подключении драйвера пишет в самой нижней строке красным шрифтом: Не установлен на текущем компьютере. Не определен тип: AddIn.ICSFPNative.ICSFP_V2. При нажатии кнопки "Функции - > Установить драйвер" выдаёт сообщение "Внешняя компонента уже подключена".
Может кто подскажет куда копать? Может у меня старый модуль n8api (2011 год)?
(138) DAN397, в этих "1С: Совместимо" я разбираться не буду, но как минимум одна ошибка у тебя есть: в файле MANIFEST.XML убери component c x86_64, ибо у тебя dll только i386, а если будешь делать dll x86_64, то называй её по другому (например ICSFPNative64.dll).
А так, смотри где сам накосячил. v8napi.pas здесь не причем.
Затем в функции, которую вызываю из 1С, создаю экземпляр этого класса и запускаю:
function VSMusic.PlayMusic(RetValue: PV8Variant; Params: PV8ParamArray; const ParamCount: integer; var v8:TV8AddInDefBase): boolean;
begin
AMusThread := TMusThread.Create(true);
AMusThread.FreeOnTerminate := true;
AMusThread.Priority := tpNormal;
AMusThread.Notes := V8AsAString(@Params[1]);
AMusThread.Speaker := V8AsBool(@Params[2]);
AMusThread.Execute;
Result:=true;
end;
Показать
Но интерфейс 1С всё равно подвисает до тех пор пока не закончится выполнение этого доп потока. Не подскажите что я делаю не так или в 1С вообще нельзя сделать доп поток? У меня платформа 8.3.7.2008. К слову, я сделал приложение на делфи, которое делает то же самое и там поток нормально работает, ничего не виснет.
Большое спасибо! Никогда бы не догадался попробовать Resume вместо Execute. Я всегда думал что Execute запускает поток, а Resume используется только после Suspend. И в Delphi то ведь работает через Execute, это что-то 1Ской обусловлено?
(145)
Я помню когда учился потоки использовать читал статью чью-то и там было написано что запуск потока через Exucute. Сейчас тоже погуглил всё поновой, видимо я просто всегда ошибался. Еще раз большое спасибо!
v77, подскажите, что влияет на
06.10.2015 Исправлена ошибка: сообщение "некорректная работа компоненты с памятью"
На основе Вашей работы 2 года назад сделал библиотеку для работы с специфичным устройством, теперь на 8.3.7 вываливается вышеописанная ошибка. Писал всё на RAD Studio XE. Довольно сложно ваш файл к ней адаптировать.
function _GetPropName(Obj: PV8ObjectRec; lPropNum, lPropAlias: integer)
: PWideChar; stdcall;
begin
if lPropAlias = 0 then
result := Obj.RelObj1.V8AllocWideString(Obj.RelObj1.ClassReg.PropList[lPropNum].PropName)
else
result := Obj.RelObj1.V8AllocWideString(Obj.RelObj1.ClassReg.PropList[lPropNum].PropNameLoc);
end;
function _GetMethodName(Obj: PV8ObjectRec; const lMethodNum,
lMethodAlias: integer): PWideChar; stdcall;
begin
if lMethodAlias = 0 then
begin
result := Obj.RelObj1.V8AllocWideString(Obj.RelObj1.ClassReg.MethList[lMethodNum].MethName);
end
else
begin
result := Obj.RelObj1.V8AllocWideString(Obj.RelObj1.ClassReg.MethList[lMethodNum].MethNameLoc);
end;
end;
Не могу понять , есть процедура ExtEvent которая генерирует внешнее событие, если я ее вызываю из 1С, то все хорошо событие генерируется и обрабатывается 1С , если я вызываю ExtEvent из самой компоненты, то компонента вылетает с ошибкой и закрывает платформу.
procedure IFSFDRV.ExtEvent();
begin
v8.ExternalEvent(pWideChar('aaa'), pWideChar('bbb'), pWideChar('ccc'));
end;
(157) нормально ответить я так понимаю выше вашего достоинства ? Вылетает именно на v8.ExternalEvent('a','b','c'); , все что до этой строки в методе объекта все выполняется.
(159) unit Main; Ну вот Допустим пример , Из 1с метод ExtEvent вызывается нормально, отрабатывает генерирует внешнее событие , его подхватывает 1с и обрабатывает и все хорошо. Но как только я пытаюсь вызвать метод ExtEvent из самой внешней компоненты таким способом: MyIFSF.ExtEvent(); отрабатывает showmessage('СОБЫТИЕ !!!!'); а дальше краш.
constructor TMyClass.Create;
begin
T := nil;
Counter := 0;
TestV := '';
end;
destructor TMyClass.Destroy;
begin
FreeT;
inherited Destroy;
end;
procedure TMyClass.FreeT;
begin
if T <> nil then
begin
T.Terminate;
T.WaitFor;
FreeAndNil(T);
end;
end;
function TMyClass.Start(Params: PV8ParamArray;
const ParamCount: integer): boolean;
begin
Counter := 0;
if T = nil then
begin
T := TMyThread.Create(True);
T.P := self;
T.Resume;
end;
result := True;
end;
function TMyClass.Stop(Params: PV8ParamArray;
const ParamCount: integer): boolean;
begin
FreeT;
result := True;
end;
{ TMyThread }
procedure TMyThread.Execute;
var
S : WideString;
begin
while not Terminated do
begin
inc(P.Counter);
S := IntToStr(P.Counter) + ' привет из Delphi';
P.V8.ExternalEvent('моя вк', 'привет', @S[1]);
sleep(2000);
end;
end;
begin
//Регистрация класса
with ClassRegList.RegisterClass(TMyClass, 'Пример', 'TMyClass') do
begin
AddProc('Start', 'Старт', @TMyClass.Start);
AddProc('Stop', 'Стоп', @TMyClass.Stop);
end;
помучился прилично с модулем v8napi ... кажется там есть неприятная ошибка ... при вызове методов компоненты им передается не запись на PV8ObjectRec (то есть ссылка на объекты компоненты) а ссылка на сам интерфейс. Например в метод SetLocale передается I3 записи PV8ObjectRec
а вообще автору n8napi низкий поклон (я вспомнил что знаю delphi и не много изучил C++ при проверке исходников на ИТС)
Здравствуйте! А не подскажете как надо преобразовать методы внешней компоненты для работы в веб клиенте? Я сделал простейшую компоненту, которая просто выводит текст в строку сообщений 1С, в тонком клиенте работает хорошо, в веб я её преобразовал с помощью примеров и документации 1С (https://its.1c.ru/db/metod8dev/content/3221/hdoc) , сделал расширение для Chrome, подключается она нормально, но при попытке вызвать метод компоненты, выдается ошибка - Использование синхронных методов на клиенте запрещено. Не могу понять что нужно сделать, чтобы браузер считал метод асинхронным. Метод добавлен в класс через AddProc.
Использование внешних компонент в асинхронном режиме имеет ряд особенностей:
1. Подключение внешней компоненты выполняется с помощью асинхронного метода НачатьПодключениеВнешнейКомпоненты().
2. Для обращения к свойствам внешней компоненты следует использовать асинхронные методы НачатьУстановку<ИмяСвойства>() и НачатьПолучение<ИмяСвойства>().
3. Вместо обращения к методу компоненты следует использовать асинхронные методы НачатьВызов<ИмяМетода>().
Методы Начать…() автоматически добавляются платформой к существующим свойствам и методам внешней компоненты. Саму внешнюю компоненту не требуется отдельно перерабатывать для поддержки работы в асинхронном режиме.
Для метода НачатьВызов…() первым параметров следует указывать описание оповещения, а остальные параметры соответствуют набору параметров оригинального метода внешней компоненты.
При использовании веб-браузеров Google Chrome и Mozilla Firefox поддерживается только асинхронное подключение и использование внешних компонент, в том время как для других веб-браузеров допустимо использование как синхронного, так и асинхронного способа работы. Это определяется свойством конфигурации Режим использования синхронных вызовов расширений платформы и внешних компонент
(172) Думаю проще всего преобразовать ДД в Base64 строку и передать как строку, а в компоненте обратно преобразовать. В 1С - Base64Строка(<Значение>), в Delphi - DecodeBase64(<String>)
(173) Да ну, не проще. В pstrVal же однобайтовые AnsiChar, приводи к TBytes и ограничь этот массив по V.VarEnum.vtRecString.strLen.
Попробовал записать в файл, все гуд)) и всего 2 строчки кода!
(176) Разобрался, спасибо.
Проблема была не в DecodeString.
Проблема оказалась в инициализации Потока и его позиционированием.
DecodeString кстати тоже потоками кодирует строку успешно.
Кто может помочь - может в личке.
Поставил XE8.
Где-то нелады со строками.
Получаю строку, декодирую функцией выше.
Сохраняю в файл, но файл ни один просмотрщик не принимает.
Если пытаться декодировать через DecodeString или DecodeBase64(вариант родной делфи), то выдаёт No mapping for the Unicode character exists in the target multi-byte code page."
Добрый день.
Не подскажете - как на форме на кнопке реализовать вызов ExternalEvent ?
в модуле проекта как водится
with ClassRegList.RegisterClass(TMyClass, 'ComponentName', 'TMyClass') do
begin
//AddFunc( 'Name', 'Имя', @АдресФункции, КвоПараметров);
//AddProc( 'Name', 'Имя', @АдресФункции, КвоПараметров);
--
Потом открываю форму, что-то делаю, а после закрытия читаю в 1С результаты.
--
Хочется сделать нормально - посылать результаты прямо в 1С.
(181)
добавил при старте - записываю в переменную у себя на форме - ссылку на входной класс
function TMyClass.Start(RetValue: PV8Variant; Params: PV8ParamArray; const ParamCount: integer; var v8: V8AddInDefBase): boolean;
var i : integer;
begin
Form1 := TForm1.Create(Application);
frmCapture.PForm1 := @Form1;
Form1.myV8 := @v8;
---
переменная объявлена в форме
myV8 : TV8AddInDefBase;
---
ну и сам вызов на форме
myV8.ExternalEvent('aaa', 'bbb', 'ccc' );
---
собственно ошибку не вызывает, но и в 1С ничего не приходит.
(182) хм - пока дошёл домой - подумал.
Заменил
Form1.myV8 := @v8;
на
Form1.myV8 := Self.V8;
---
теперь посылает, но как в примере выше - только после выхода.
Если оно в потоке работает - ща буду думать, как приспособить поток для вызова оповещения по требованию.
(183) а поток оказался не нужен - просто 1С ждёт ответа - запустилась ли компонента.
А при открытии формы модально в момент старта компоненты - ответа то нет.
Убрал модальное открытие формы - теперь могу из формы посылать события - красотища.
Вопрос к автору. Скачал архив из этой раздачи, а в нём как оказалось шаблон компоненты от 2012 года, хотя в описании написано, что в архиве тот же файл модуля. Нельзя ли изменить описание файлов с учётом даты их обновлений? И как мне теперь быть в этой ситуации? Очень не хотелось бы тратить ещё одну стармани для того чтоб повторно качать то, что должно было быть в архиве...
У меня есть модуль от декабря 15 года. Это самая последняя версия библиотеки?
Пытался использовать этот модуль для разработки интеграционной библиотеки для драйвера оборудования, реализованного в виде стандартного сервера автоматизации (т.е. написать прослойку). Вроде все делаю по документации, но при попытке вызвать методы DLL 1С молча вылетает. Компилирую при помощи Delphi 10.1. Вот пример кода:
function TKKTDrv.GetVersion(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: Integer; var v8: TV8AddInDefBase): Boolean;
begin
try
WriteLog('GetVersion...');
V8SetWString(RetValue, DriverVersion);
Result := True;
WriteLog('Result = ' + DriverVersion);
except
on e: Exception do
begin
V8SetWString(RetValue, ''); // результат функции
Result := ErrorHandler(Word(c_unknown), e);
end;
end;
end;
function TKKTDrv.Open(RetValue: PV8Variant; Params: PV8ParamArray;
const ParamCount: Integer; var v8: TV8AddInDefBase): Boolean;
var
s: WideString;
ecode: Integer;
begin
ecode := c_unknown;
try
WriteLog('Open...');
if ParamCount <> 1 then
begin
ecode := c_param_wrong_num;
raise Exception.Create(LocStr(c_param_wrong_cnt_en, c_param_wrong_cnt_ru));
end;
s := '0123456789'; // ID устройства
fDeviceId := s;
V8SetWString(@Params[1], s);
V8SetBool(RetValue, True); // результат функции
Result := True;
WriteLog('Result = 0');
except
on e: Exception do
begin
V8SetBool(RetValue, False); // результат функции
Result := ErrorHandler(Word(ecode), e);
end;
end;
end;
function TKKTDrv.ErrorHandler(const ResCode: Word; E: Exception): Boolean;
begin
fLastErrCode := ResCode;
fLastErrDesc := e.Message;
WriteLog(Format('Result = %d (%s)', [fLastErrCode, fLastErrDesc]));
V8SetBool(RetValue, False); // результат функции
Result := False;
V8.AddError(ResCode, PWideChar(LocStr(c_ext_comp_en, c_ext_comp_ru)), PWideChar(fLastErrDesc), E_FAIL);
end;
// ...
begin
with ClassRegList.RegisterClass(TKKTDrv, 'TKKTDrv', 'TKKTDrv') do
begin
AddFunc('GetVersion', 'ПолучитьНомерВерсии', @TKKTDrv.GetVersion, 0);
AddFunc('Open', 'Подключить', @TKKTDrv.Open, 1);
// ...
end;
(188) Столкнулся с похожей ситуацией. Подключал компоненту в Розница 2.2. Если я правильно понимаю, 1С опять не выложил половину из новых требований и в момент опроса прослойки идет вызов не процедуры ПолучитьНомерВерсии а процедуры НачатьВызовПолучитьНомерВерсии, описание которого пока нигде не нашел. Если нашли решение - поделитесь пожалуйста
Друзья, можете скинуть в личку последний релиз - v8napi.pas от 16.12.2015? Потратил последние деньги на версию с ошибкой "Некорректная работа компоненты с памятью".
194.
user657734_YGREEN
06.05.19 22:50 Сейчас в теме
Компонента на компьютере где писалась (Lazarus) нормально подключается. А при переносе не подключается...
ПодключитьВнешнююКомпоненту возвращает Ложь...
Может кто сталкивался с похожей проблемой?