Не получается вызвать функцию из DLL

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Не получается вызвать функцию из DLL

Сообщение AlexDanilov » 27.10.2017 03:07:30

Добрый день.

Есть библиотека подключения к фискальному регистратору unisystem мини-фп54.

Пробую подключиться к функции t400me. Через GetProcedureAddress возвращается nil, а через ActiveX вообще access viloation
Код: Выделить всё
unit kkm;

{$mode objfpc}{$H+}

interface

uses Classes, SysUtils, Dialogs, dynlibs, LConvEncoding, activexcontainer;

type
  TUniSystem = class(TObject)
    procedure Exec;
  end;

  TMyFunc = function(var Param1: WideString): String; stdcall;


implementation

procedure TUniSystem.Exec;
var
  kkmLib: TLibHandle;
  MyFunc: TMyFunc;
  P: Pointer;

  AC: TActiveXContainer;
  k: variant;
begin
  //  попытка подключения через ActiveX
  AC := TActiveXContainer.Create(nil);
  AC.OleClassName := 'It400';
  k := AC.ComServer;
  ShowMessage(k.t400me('open_port;1;9600')); //  тут вылетает access violation


// попытка загрузить dll и вызвать функцию через GetProcedureAddress
  kkmLib := LoadLibrary('ecrT400.' + SharedSuffix);
  if kkmLib = 0 then Exit;
  P := GetProcedureAddress(kkmLib, 'It400::t400me');
  if P = nil then ShowMessage('P = nil'); // P == nil :(
  MyFunc := TMyFunc(P);
  if MyFunc = nil then ShowMessage('func = nil');

end;

end.


Что я делаю не так?

В Интернете есть рабочий пример для 1С.
Код: Выделить всё
Соединение = Новый COMОбъект("ecrmini.t400");
Удачно = Соединение.t400me("open_port;"+Строка(Номер)+";115200;");
Если Не Удачно Тогда...


Во вложении я добавил скриншот программы, которая показала все экспортируемые функции.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
AlexDanilov
новенький
 
Сообщения: 17
Зарегистрирован: 24.10.2016 15:11:46
Откуда: Kiev

Re: Не получается вызвать функцию из DLL

Сообщение Лекс Айрин » 27.10.2017 09:08:32

а просто объявить ее как экспортируемую не пробовал? Как это делается в модуле windows.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Не получается вызвать функцию из DLL

Сообщение AlexDanilov » 27.10.2017 12:57:41

Лекс Айрин писал(а):а просто объявить ее как экспортируемую не пробовал? Как это делается в модуле windows.

Не понял, что вы имели в виду.

В модуле windows вижу только инструкции типа
Код: Выделить всё
{$i func.inc}
AlexDanilov
новенький
 
Сообщения: 17
Зарегистрирован: 24.10.2016 15:11:46
Откуда: Kiev

Re: Не получается вызвать функцию из DLL

Сообщение Cheb » 28.10.2017 10:09:50

Очевидно, попытка в лоб загрузить метод COM объекта, как функцию (в сишной нотации It400::t400me означает "метод t400me класса It400").

Я сам с ними не занимался, но есть сильное подозрение, что это работает совершенно не так.

Копать в сторону биндингов для этой либы для Паскаля или Си, и как выковыривать методы COM объектов и как вообще работать с COM объектами в Паскале.
Также, вижу, что в приведённом скриншоте НЕТ адресов для методов (которые с двоеточиями) - лишнее доказательство, что как ф-ии они НЕ грузятся.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Не получается вызвать функцию из DLL

Сообщение olegy123 » 28.10.2017 14:03:24

AlexDanilov писал(а):В Интернете есть рабочий пример для 1С.

Он должен подходить для Lazarus-а. Сущность Com обектов в этом..

Сначало нужно dll-ку зарегистрировать в реесте системы Windows как ole объект.
regsvr32 xxxxx.dll
https://en.wikipedia.org/wiki/Regsvr32
И только потом его можно вызывать по имени.. Тогда станет доступен всем и 1Ске и Excel/Word/Access, VB, VC++ и тебе.


Вот тут показывают как вызывают MSOffice и OpenOffice
http://wiki.lazarus.freepascal.org/Offi ... oft_Office

должно получится типа так
Код: Выделить всё
var         
  Server     : Variant;

try
    Server := CreateOleObject('ecrmini.t400');
  except
    WriteLn('Unable to start ecrmini.t400.');
    Exit;
  end;

после Server:=CreateOleObject('ecrmini.t400') добавляются к переменной Server все методы и поля.

потом как в примере для 1С вызывать методы один в один
Код: Выделить всё
Server := CreateOleObject('ecrmini.t400');
if not VarIsNull(Server) then
      connection:=Server.t400me('open_port;1;115200;');
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Не получается вызвать функцию из DLL

Сообщение AlexDanilov » 29.10.2017 01:09:09

olegy123, спасибо, все получилось.

А в чем разница между OLEjectObject, ComObject, ActiveX и способом LoadLibrary.

Когда какой способ лучше использовать?
AlexDanilov
новенький
 
Сообщения: 17
Зарегистрирован: 24.10.2016 15:11:46
Откуда: Kiev

Re: Не получается вызвать функцию из DLL

Сообщение Vadim » 29.10.2017 05:12:13

AlexDanilov
LoadLibrary() загружает некую библиотеку в память и берёт из неё функцию по её адресу. Фактически это получается аналог юнитов в Паскале. При работе с COM-объектами (любыми) загружается целая программа (чужая). Это может быть и не одна функция или даже библиотека, а целая связка. Кроме того COM-объект в обязательном порядке должен быть зарегистрирован в системе (реестре) по своему уникальному номеру. regsvr32 как раз этим и занимается. И программа работает с COM-объектами через реестр.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Не получается вызвать функцию из DLL

Сообщение olegy123 » 30.10.2017 13:25:28

AlexDanilov писал(а):А в чем разница между OLEjectObject, ComObject, ActiveX и способом LoadLibrary.

В том что это (OLE) скорее plug-in для системы windows. За основу был взят формат dll-ки. OLE методы без самой Windows не вызывать, иначе нужно эмулировать высокий слой который представляет Windows.
Интересно этот COM элемент можно сделать DCOM - и работать с ним по сети.

Server := CreateOleObject('\\имя компьютера в сети\ecrmini.t400');
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 30

Рейтинг@Mail.ru