Отладка DLL

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

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

Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Отладка DLL

Сообщение Alex. S »

Здравствуйте.

Написал DLL библиотеку и программу (которая будет её использовать через статическую линковку) в Lazarus'е. Пытаюсь протестировать dll, добавив в параметрах запуска свою программу, которую я переместил в папку dll проекта. Однако, когда я запускаю dll проект, появляется окно программы, но при нажатии кнопки в окне, которая вызывает функцию из dll не происходит остановка программы, хотя breakpoint стоит в начале этой функции :(

Подскажите, почему такое может быть?
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Alex. S писал(а): Пытаюсь протестировать dll, добавив в параметрах запуска свою программу, которую я переместил в папку dll проекта.

Параметр называется "Главное приложение" ?
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

Sharfik, да.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

У меня работает такое, но использую динамическую линковку.
Попробуй динамически обратится, может в этом дело.
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

Пробовал динамически, тоже безуспешно.

Sharfik, не можете скинуть пустой dll-проект, который у Вас успешно проходит отладку?

P.S. Передаю в процедуру из dll массив как переменную, заполняю его в dll, в итоге: External "SIGSEGV".

Частичный код DLL:

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

...
TDWordArray = array of Cardinal;
...
procedure GetData(var Data: TDWordArray);
begin
//
SetLength(Data, 1);
//
Data[0]:=5;
end;


Код программы:

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

...
procedure GetData(Data: TDWordArray); external 'MyDLL.dll';
...
var
//
i, k: Cardinal;
//
Data: TDWordArray;
begin
//
GetData(Data);

//
k:=Length(Data);
//
if k > 0 then
  begin
  //
  Dec(k);

  //
  for i:=0 to k do
  //
  ShowMessage(IntToStr(Data[i]));
  end;
end.
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

Alex. S писал(а):Частичный код DLL: Код программы:

Попробуйте название: GetData, переименовать на GetDataTest.
Есть предположение, что у Вас получается рекурсия и валит программу.


.
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

vitaly_l, в реальности, вместо GetData используется другое название, это я использовал доя тестирования...

По поводу рекурсии, я её тут не вижу. Если вместо массива, передать простую переменную, и присвоить ей значение в процедуре GetData, то всё нормально работает...
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

Alex. S писал(а):По поводу рекурсии, я её тут не вижу.

А по моему это вечный цикл:

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

procedure GetData(Data: TDWordArray); external 'MyDLL.dll';
var
Data: TDWordArray;
begin
//
GetData(Data); <==== вот она, рекурсия. Процедура ссылается на саму себя.

// Всё! <== дальше - программа, никогда не перейдёт, т.к. вызовется GetData(Data); ,
// которая дойдёт до предыдущей строки GetData(Data); и снова вызовет GetData(Data);
и так до бесконечности, пока не закончится память, допустимое значение вариантов или бсода.



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


.
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

vitaly_l, это не рекурсия, это я так отформатировал код, не совсем понятно :)

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

procedure GetData(Data: TDWordArray); external 'MyDLL.dll';

Это импорт процедуру из dll в программе.

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

var
//
i, k: Cardinal;
//
Data: TDWordArray;
begin
//
GetData(Data);

//
k:=Length(Data);
//
if k > 0 then
  begin
  //
  Dec(k);

  //
  for i:=0 to k do
  //
  ShowMessage(IntToStr(Data[i]));
  end;
end.


А это уже код программы, который выполняется при её запуске.

Извините, что ввёл Вас в заблуждение.

Проверил, если заменить тип переменной Data с TDWordArray на Cardinal в программе и в dll, и просто присвоить значение этой переменной, в процедуру GetData, то программа выполняется без ошибок. А вот если, передавать уже массив, и обрабатывать его, будет ошибка :(
Аватара пользователя
vitaly_l
долгожитель
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41
Контактная информация:

Сообщение vitaly_l »

У Вас два раза вот это объявлено: Data: TDWordArray; обычно Лазарус на такое ругается, до компиляции.
там где VAR, делайте: var DataX: TDWordArray; Получится: GetData(DataX); (либо Data второй раз не объявляйте)



.
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

vitaly_l, это только в тестовом коде, я упростил код программы, так как он слишком громоздкий, переписав с него только тот участок, где происходит ошибка.

Сейчас вот ещё заметил, что если установить размер массива Data в программе, а в dll устанавливать только значения для массива, ошибки тоже не будет...
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Такой вариант работает.

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

library edt_cablelaying;

{$mode objfpc}{$H+}

uses
  windows, Classes, SysUtils, FileUtil, Interfaces,
  Forms, Controls, Graphics, Dialogs;

const
  PackageName               = 'Plugin';
  PackageAuthor             = 'My';
  PackageVersion            = '0.4';
  PackageLic                = 'Freeware';
  PackageMenuCaption        = 'Прокладка кабелей';
  PackageLibName            = 'edt_cablelaying.dll';

//var
  //ThisApp                  :TCustomAssiApp;

function PluginInit(AppClass: Pointer):Boolean; stdcall;
begin
    //проверки
    //ThisApp :=TCustomAssiApp((AppClass);
    Result    :=True;
end;

procedure PluginDeinit(AppClass: Pointer); stdcall;
begin

end;

procedure PluginProjectInit(AppClass: Pointer;AStr:WideString); stdcall;
begin

end;

procedure PluginProjectDeinit(AppClass: Pointer;AStr:WideString); stdcall;
begin
 
end;

function PluginType: WideString; stdcall;
begin
   //PT_EDITFORM        - Редактор с формой
   Result:=  PT_EDITFORM;
end;

function PluginName: WideString; stdcall;
begin
     Result:=  Utf8ToAnsi(PackageName);
end;

function PluginMenuCaption: WideString; stdcall;
begin
     Result:=  Utf8ToAnsi(PackageMenuCaption);
end;

function PluginAuthor: WideString; stdcall;
begin
     Result:=  Utf8ToAnsi(PackageAuthor);
end;

function PluginVersion: WideString; stdcall;
begin
     Result:=  PackageVersion;
end;

function PluginLicense: WideString; stdcall;
begin
     Result:= Utf8ToAnsi(PackageLicDescriptionStr);
end;

function PluginWindow: Pointer; stdcall;
begin
  Result := nil;
  if Assigned(ThisApp) then
  begin

  //Процедура вызывается если PluginType возвращает PT_EDITFORM, PT_EXPORTIMPORT
  end;
end;

exports
        PluginInit            name 'PluginInit',
        PluginDeinit          name 'PluginDeinit',
        PluginProjectInit     name 'ProjectInit',
        PluginProjectDeinit   name 'ProjectDeinit',
        PluginType            name 'PluginType',
        PluginName            name 'PluginName',
        PluginAuthor          name 'PluginAuthor',
        PluginVersion         name 'PluginVersion',
        PluginLicense         name 'PluginLicense',
        PluginWindow          name 'PluginWindow',
        PluginMenuCaption     name 'PluginMenuCaption';

{$R *.res}

begin
  Application.Initialize;
end.
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

Sharfik, спасибо, буду тестировать :)
А в программе у вас mode ObjFPC, или Delphi?

У меня, с динамической линковкой не получается собрать при mode ObjFPC, строка

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

@some_proc:=getProcAddress(DLLHandle, 'proc_name');


не хочет компилироваться.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Там mode ObjFPC

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

function TFLauncher.LoadPlugin(Filename: String): Boolean;
var
  PluginPath   :PChar;
  newPlugin    :TPluginItem;
  PluginCorrect:Boolean;
  DLLHandle    :THandle;
  sResult      :WideString;
  i            :Integer;
begin
  try
    PluginCorrect:=true;
    Result:=false;
    // загружаем dll динамически
    PluginPath:=pchar(UTF8ToSys(Filename));
    DLLHandle := loadLibrary (PluginPath);
    if DLLHandle > 32 then
    begin
      newPlugin :=TPluginItem.Create;
      newPlugin.LibHandle:=DLLHandle;

      newPlugin.PluginFileName       :=Filename;
      newPlugin.faRun                :=GetProcAddress( DLLHandle, 'PluginRun');
      newPlugin.faWindow             :=GetProcAddress( DLLHandle, 'PluginWindow');
     ///property faWindow            :Pointer read FPluginWindow
     ///                                                    write FPluginWindow;
      newPlugin.faVersion            :=GetProcAddress( DLLHandle, 'PluginVersion');
      //**

      if newPlugin.faVersion         =nil then PluginCorrect:=false;
      //**
      if newPlugin.faProjectInit     =nil then PluginCorrect:=false;

      if not PluginCorrect then
      begin
        ThisApp.SystemLog('', Format('Плагин %s не загружен. Необходимые ресурсы не найдены.',[ExpandFileNameUTF8(Filename)]));
        newPlugin.Free;
        freeLibrary(DLLHandle);
      end
      else begin
          ThisApp.PluginAdd(newPlugin);
          Result:=true;
      end;
    end
    else begin
      // DLL не найдена
      ThisApp.SystemLog('', Format('Плагин %s не загружен. Не удалось прочитать.',[ExpandFileNameUTF8(Filename)]));
    end;
   
  except
    freeLibrary(DLLHandle);
    if assigned(newPlugin) then newPlugin.Free;
  end;
end;
Alex. S
новенький
Сообщения: 39
Зарегистрирован: 22.08.2015 10:37:00

Сообщение Alex. S »

Sharfik, большое спасибо. Буду анализировать, почему у меня не получается :)
Ответить