Странности при явной загрузке DLL

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

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

Странности при явной загрузке DLL

Сообщение AlphaBlend » 10.02.2018 21:12:54

Всем привет!
Читаю книгу "Библия Delphi" Фленова. Главу - "Явная загрузка DLL". вопрос этот может быть поднимался когда-то, поэтому заранее
извиняюсь, если повторюсь.

Есть код явной загрузки DLL и вызова функции из нее.


Код: Выделить всё

  { CODE 1 }
 

   //явный вызов  библиотеки...

   //создать тип для  функции
 
   type
     
      Tfunction = function(Param:Pchar):Pchar; stdcall;

   ....

   // в  какой-то процедуре( пусть OnClick по кнопке) вызвать DLL и поискать в  ней  функцию


  procedure Button.Click(Sender: Tobject);
   var
   Func:TFunction;     // переменная  для полученной  из DLL функции
   DLLHandle: THandle; //Хандл библиотеки
   begin
     //попытаться  загрузить библиотеку в  память
     DLLHandle:=LoadLibrary('dll_2.dll');
     // проверить , загрузилась ли DLL
    if DLLHandle <> 0 then
      begin
      //библиотека  нашлась и загрузилась в память.
      //поискать в  ней  функцию. Если она  найдется, то указать ее  адрес переменной Func
      @Func:=GetProcAddress(DLLHandle,'GetString');
      //если указатель на Func не nil - функция  нашлась в  библиотеке  и
      //все  должно было присвоиться
      if @Func <> nil then
         begin
             //Что-то сделать с функцией
             showmessage(Func('Печенька!'));            
             //Уничтожить библиотеку
                 FreeLibrary(DLLHandle);
         end;                    
      end
       else
      begin
      // какой-то код , который будет работать,
      // если DLL  не  загрузилась. Например, Записать ошибку  в  журнал логов...
      end;
   end;




Сама DLL написана в Borland Delphi 2.0. Вот ее код:

Код: Выделить всё
   { CODE 2 }
      library dll_2;

      uses
        SysUtils,
        Classes;
        //в DLL нельзя ( не рекомендуется ) использовать тип STRING , а  надо тип PCHAR
        function GetString(Param:Pchar):Pchar export stdcall;
           begin
                result:=Param;
           end;

        exports
           GetString index 10 name 'GetString';
        begin
      end.
   


Теперь сформулирую суть проблемы:

{ CODE 1 } Написан в Borland Delphi 7. Компилируется и выполняется прекрасно. Никаких ошибок , предупреждений,
никаких Access Violation нету. Программа работает.

Набрав точно такой же код (скопипастив из Delphi) явного вызова этой DLL в Lazarus, получаю ошибку на этой строке:
Код: Выделить всё
      @Func:=GetProcAddress(DLLHandle,'GetString');
   

Текст сообщения об ошибке:
["intersect.pas(53,8) Error: Can't assign values to an address"]
Вот, собственно, и вопрос - Как правильно и безопасно делать явный вызов DLL в Lazarus ?

Если статически загружать, то работает:

Код: Выделить всё
   function GetString(Param: PChar):Pchar; stdcall; external 'dll_2.dll' index 10;
   


Но такой способ вызова для моей задачи не подходит.

Была попытка сделать так:
Код: Выделить всё

   type

      Tfunction = function(Param:Pchar):Pchar stdcall;

   ...
   
   procedure Button.Click(Sender: TObject);
   var
      PFunc:^TFunction;
      Func:TFunction
      DLLhandle:THandle;      
   begin
   //Попытаться  загрузить библиотеку      
   DLLHandle:=LoadLibrary('dll_2.dll');
   //Библиотека  загружена удачно?
   if DLLHandle <> 0 then
      begin
         //GetProcAddress возвращает  указатель!   
         Pfunc:=GetProcAddress('GetString');
         //указатель ссылается  куда-то ?
         if PFunc <> nil then
      begin
        //присвоить содержимое адреса, на который  ссылается указатель
        //переменной Func   
        Func:=PFunc^;
        //выполнить
        showmessage(Func('Печенька!'));       
      end;      
      //уничтожить библиотеку                                 
      FreeLibrary(DLLHandle);
      end;
   end;
         

   


Компилируется без предупреждений, программа запускается. При событии OnClick авария - "Access Violation".
В Lazarus как-то по-другому реализован явный вызов? Спасибо ^_^
Аватара пользователя
AlphaBlend
постоялец
 
Сообщения: 207
Зарегистрирован: 22.05.2016 10:13:10

Re: Странности при явной загрузке DLL

Сообщение runewalsh » 10.02.2018 23:02:14

В дефолтном {$mode objfpc} @ перед Func не нужна, т. е. убери её или используй {$mode delphi}.
TFunction — это тот же указатель, что возвращает GetProcAddress, так что по сути никакие разыменования или взятия адреса не имеют места и синтаксис Delphi странноват, можно понять, почему от него отказались.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: Странности при явной загрузке DLL

Сообщение AlphaBlend » 10.02.2018 23:16:56

runewalsh писал(а): {$mode objfpc} @ перед Func не нужна, т. е. убери её или используй {$mode delphi}.
Неа, не работает все равно. В гуглах вообще какие-то одинаковые примеры, которые не объясняют этой ошибки. Если убрать "собачку" , то пишет несовпадение типов ( Pointer ) и (Procedure ). Уже подумываю этот проект полностью на Delphi перенести пока еще немного сделано :roll:
Аватара пользователя
AlphaBlend
постоялец
 
Сообщения: 207
Зарегистрирован: 22.05.2016 10:13:10

Re: Странности при явной загрузке DLL

Сообщение runewalsh » 11.02.2018 01:37:48

Ой, и правда. Тогда делай pointer(Func) := GetProcAddress(...) или Func := TFunction(GetProcAddress(...)).
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: Странности при явной загрузке DLL

Сообщение скалогрыз » 11.02.2018 06:46:49

runewalsh писал(а):Ой, и правда. Тогда делай pointer

Чоааа???
{$mode delphi} работает правильно.

например, сий код компилится и работает без проблем:
Код: Выделить всё
program project1;
{$ifdef fpc}{$mode delphi}{$H+}{$endif} // и чтобы на делфи собирался тоже

uses
  Windows, Classes;

type
  Tfunction = function(Param:Pchar):Pchar stdcall;

var
  Func:TFunction;
  DLLhandle:THandle;
begin
  //Попытаться  загрузить библиотеку
  DLLHandle:=LoadLibrary('dll_2.dll');
  //Библиотека  загружена удачно?
  if DLLHandle <> 0 then
  begin
    //GetProcAddress возвращает  указатель!
    @func:=GetProcAddress(DLLHandle, 'GetString');
    if @Func <> nil then
    begin
      //выполнить
      writeln(Func('Печенька!'));
    end;
    //уничтожить библиотеку
    FreeLibrary(DLLHandle);
  end;
end.

(проверено на Delphi 7 и FPC 3.0.0)

имхо (да и к делу не относится), именно благодаря поддержке $mode delphi и возможности написать {$ifdef fpc}{$mode delphi}{$endif}, FPC живее самой делфи.
Разработчики имеют возможность "быстро попробовать" свой код на FPC, особо не рискуя необходимостью вносить кучу правок для совместимости между компиляторами.

какой-нить GNU Pascal, успешно слился из-за синтаскической несовместимости с более известным вариантом языка! :)
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Странности при явной загрузке DLL

Сообщение runewalsh » 11.02.2018 19:04:01

Ну я по игнорированию моего совета о {$mode delphi} (который я, возможно, недостаточно чётко сформулировал) предположил, что автору нужен {$mode objfpc}. Там процедурные типы несовместимы с pointer без кастов почему-то.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Re: Странности при явной загрузке DLL

Сообщение Cheb » 10.03.2018 00:49:50

Там процедурные типы несовместимы с pointer без кастов почему-то.

Чтобы иметь возможность выстрелить себе в ногу - надо открытым текстом попросить об этом, иначе нельзя. Хороший принцип, мне нравится.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34


Вернуться в Lazarus

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru