Возможно ли такое создать в DLL?

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

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

AMD
постоялец
Сообщения: 189
Зарегистрирован: 23.01.2008 21:25:25
Откуда: Кишинев

Возможно ли такое создать в DLL?

Сообщение AMD »

Возможно ли такое создать в DLL?

Например из программы вызываю dll file

Из dll вызываю функцию с параметром [путь к файлу на диске]

В dll находидится функция которая рисует диалоговое окно со всеми нужными компонентами извлекает нужные даные на экране из данного файла (к примеру нужную строку текста) и дальше функция передает эту строку главной программе.

Зачем это?
Ну например чтобы тоже самое не писать несколько раз в разных программах - а так написал один раз а используешь сколько надо для разных прог.

А если точнее подумываю например написать нужные программы а вызывать их из OO basic - таким образом программа работает самостоятельно а OO basic передает только результат функции
Аватара пользователя
Slavikk
постоялец
Сообщения: 208
Зарегистрирован: 15.01.2007 21:34:52
Откуда: Из лесов...
Контактная информация:

Сообщение Slavikk »

Программа и dll имеют разные разделы памяти, разные rtl и т.д. Засунуть LCL окно в dll не получится, а процедуры без проблем - аналогично как и в delphi. Никто не мешает создавать окно на API системы, во время работы программы.

Окно из Delphi dll - можно загрузить без проблем.
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

Программа и dll имеют разные разделы памяти, разные rtl и т.д. Засунуть LCL окно в dll не получится, а процедуры без проблем - аналогично как и в delphi. Никто не мешает создавать окно на API системы, во время работы программы.

Я бы не был столь категоричен.

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

library project1;

 {$mode objfpc}{$H+}

 uses
   {$IFDEF UNIX}{$IFDEF UseCThreads}
   cthreads,
   {$ENDIF}{$ENDIF}
   Interfaces, // this includes the LCL widgetset
   Forms
   { you can add units after this }, unit1;

 procedure XShowForm; stdcall;
 begin
   Application.CreateForm(TForm1,Form1);
   Form1.ShowModal;
 end;

 function XGetForm:TFormClass;
 begin
   Application.CreateForm(TForm1,Form1);
   Result:=TFormClass(Form1);
 end;

 exports XShowForm,
         XGetForm;

 begin
 end.

Юнит пустой. Тестировал саму возможность.

А вот код вызова.

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

procedure TForm1.Button1Click(Sender: TObject);
type TPro=procedure; stdcall;
var hlib:TLibHandle;
    proc:TPro;
begin
hlib:=LoadLibrary('/home/b4rr4/Devel/DC/test/aaas/lib.so');
if hlib<>0 then
proc:=TPro(GetProcAddress(hlib,'XShowForm'));
if proc<>nil then proc;
end;

procedure TForm1.Button2Click(Sender: TObject);
 type TPro=function():TFormClass; stdcall;
 var hlib:TLibHandle;
     proc:TPro;
     x:TFormClass;
begin
hlib:=LoadLibrary('/home/b4rr4/Devel/DC/test/aaas/lib.so');
if hlib<>0 then
proc:=TPro(GetProcAddress(hlib,'XGetForm'));
if proc<>nil then x:=proc();

TForm1(x).Show;
end;

initialization
  {$I unit1.lrs}

end.

Тут два метода вызова - первый сам показывает окно, второй передает указатель на окно. Как насчет утечек памяти я не проверял.
Аватара пользователя
Slavikk
постоялец
Сообщения: 208
Зарегистрирован: 15.01.2007 21:34:52
Откуда: Из лесов...
Контактная информация:

Сообщение Slavikk »

Пардон, признаю свою ошибку. Но всё же в Windows, ShowModal - работает некорректно (только Show).

Я конкретно имел ввиду если в dll засунуть форму с панелью и пытаться контролы с этой панели отображать на панели в своей программе. У меня это не получилось.
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

Ты прав. Только что проверил. Переместить контролы действительно не получается. :/
Думаю, только используя интерфейсное апи, можно это сделать.
AMD
постоялец
Сообщения: 189
Зарегистрирован: 23.01.2008 21:25:25
Откуда: Кишинев

Сообщение AMD »

Slavikk писал(а):Пардон, признаю свою ошибку. Но всё же в Windows, ShowModal - работает некорректно (только Show).

Я конкретно имел ввиду если в dll засунуть форму с панелью и пытаться контролы с этой панели отображать на панели в своей программе. У меня это не получилось.

А если отображать всю панель с контролами?
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

Не получится. Стандартными средствами - либо всю форму, либо ничего.
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

Вот такой простенький код (для GTK) позволяет перемещать на форму контролы из подключаемой библиотеки.
Все компоненты расположены на панели, которую и перемещаем.
Предполагаю что виндозная windows.SetParent(...), сработает также.
Примечание: gtk не любит TLabel-ы, просто не отображает их.

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

library lclplug;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms,gtk,gdk,glib,Unit1;

function ListLoad(ParentWin:thandle;FileToLoad:pchar;ShowFlags:integer):thandle; stdcall;
begin
  Application.CreateForm(TForm1, Form1);
  gtk_widget_reparent(PGtkWidget(Form1.Panel1.Handle),PGtkWidget(ParentWin));
end;

exports ListLoad;

begin

end.
AMD
постоялец
Сообщения: 189
Зарегистрирован: 23.01.2008 21:25:25
Откуда: Кишинев

Сообщение AMD »

B4rr4cuda писал(а):Вот такой простенький код (для GTK) позволяет перемещать на форму контролы из подключаемой библиотеки.
Все компоненты расположены на панели, которую и перемещаем.
Предполагаю что виндозная windows.SetParent(...), сработает также.


Так... - инетересно... можешь по подробней обьяснить как все это работает а то не очень понял - обесняй только под линукс - так как ты тестировал
Аватара пользователя
FedeX
постоялец
Сообщения: 422
Зарегистрирован: 27.03.2006 09:25:34
Откуда: украина, житомир

Сообщение FedeX »

AMD
А зачем именно LCL окно. Это же так не экономно - и к длл и к проге которая его использовать будут линковаться полностью код ЛЦЛ. В итоге и длл и прога будут занимать по метру (а то и больше) места на диске.
Гораздо проще (и по мойму логичней), запихнуть в длл только парсинг файла (который ты там анализируеш) и передавать все данные в какой-нить структуре главной программе. ...Или создавать это окно в длл, но на Win или GTK API не так уж это и сложно, а выглядит солиднее. :wink:
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

AMD
Ладно по пунктам:
1. Проект -> Создать проект -> Приложение
2. Кидаем на форму панель, а на неё все нужные компоненты, пишем код, тестируем - все как обычно.
3. Проект -> Просмотреть исходный код проекта
Вместо

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

program project1;
пишем

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

library NameOfProject;

4. В uses добавляем юниты: gtk, gdk, glib
5. Пишем процедурку или функцию создающую форму и перемещающую панель с контролами на панель вызывающего приложения. Получаем что-то типа:

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

library NameOfProject;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms,gtk,gdk,glib,Unit1;
procedure Load(ParentWin:thandle); stdcall;
begin
  Application.CreateForm(TForm1, Form1);
gtk_widget_reparent(PGtkWidget(Form1.Panel1.Handle),PGtkWidget(ParentWin));
end;

exports Load;

begin
end.

6. Пишем вызывающую программу:

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

uses ... , dynlibs,gtk,glib,gdk;
...
 type TPro=procedure (ParentWin:thandle); stdcall;
 var Proc:TPro;
       Hlib:TLibHandle;
       lst:PGList;

...
Hlib:=LoadLibrary('путь к библиотеке');
   if Hlib<>0 then
     begin
       proc:=TPro(GetProcAddress(HLib,'Load'));
       if proc <> nil then
         begin
         {тк lcl панель - это по сути gtk_container и GBox расположенный на нем, то скрываем чайлд компонент и отображаем на его месте свою панель}
       lst:=gtk_container_children(GTK_CONTAINER(PGtkwidget(pnlParent.Handle)));
           if lst<>nil then
              gtk_widget_hide(PGtkWidget(lst^.data));
               
          proc(PnlParent.Handle);
         end;
      end;
....

Вот и все.

2FedeX
Не экономно - это точно, зато удобно. Лично меня от чистого интерфейсного апи тошнит (что от винапи, что от gtk, надо ещё qt попробовать). А вот смесь, позволяющая вытворять трюки и добавляющая гибкости - самое оно. Если размер не критичен, а время поджимает - такие трюки помогают.
А писать на чистом апи, чтобы выглядеть солиднее... пффф, это, простите, детство.
Насчет этого:
Гораздо проще (и по мойму логичней), запихнуть в длл только парсинг файла (который ты там анализируеш) и передавать все данные в какой-нить структуре главной программе.
полностью согласен.
the_beginer
новенький
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Сообщение the_beginer »

FedeX писал(а):AMD
Гораздо проще (и по мойму логичней), запихнуть в длл только парсинг файла (который ты там анализируеш) и передавать все данные в какой-нить структуре главной программе. ...Или создавать это окно в длл, но на Win или GTK API не так уж это и сложно, а выглядит солиднее. :wink:


а можно пример в студию ?

интересна реализация
Аватара пользователя
minoshi
постоялец
Сообщения: 279
Зарегистрирован: 17.05.2008 21:23:38

Сообщение minoshi »

[quote="B4rr4cuda"]AMD
Ладно по пунктам:
1. Проект -> Создать проект -> Приложение
2. Кидаем на форму панель, а на неё все нужные компоненты, пишем код, тестируем - все как обычно.
3. Проект -> Просмотреть исходный код проекта
Вместо

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

program project1;
пишем

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

library NameOfProject;

4. В uses добавляем юниты: gtk, gdk, glib
5. Пишем процедурку или функцию создающую форму и перемещающую панель с контролами на панель вызывающего приложения. Получаем что-то типа:

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

library NameOfProject;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms,gtk,gdk,glib,Unit1;
procedure Load(ParentWin:thandle); stdcall;
begin
  Application.CreateForm(TForm1, Form1);
gtk_widget_reparent(PGtkWidget(Form1.Panel1.Handle),PGtkWidget(ParentWin));
end;

exports Load;

begin
end.

6. Пишем вызывающую программу:

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

uses ... , dynlibs,gtk,glib,gdk;
...
 type TPro=procedure (ParentWin:thandle); stdcall;
 var Proc:TPro;
       Hlib:TLibHandle;
       lst:PGList;

...
Hlib:=LoadLibrary('путь к библиотеке');
   if Hlib<>0 then
     begin
       proc:=TPro(GetProcAddress(HLib,'Load'));
       if proc <> nil then
         begin
         {тк lcl панель - это по сути gtk_container и GBox расположенный на нем, то скрываем чайлд компонент и отображаем на его месте свою панель}
       lst:=gtk_container_children(GTK_CONTAINER(PGtkwidget(pnlParent.Handle)));
           if lst<>nil then
              gtk_widget_hide(PGtkWidget(lst^.data));
               
          proc(PnlParent.Handle);
         end;
      end;
....

Вот и все.

а как убить эту панель?
Аватара пользователя
B4rr4cuda
энтузиаст
Сообщения: 693
Зарегистрирован: 28.12.2007 06:48:35

Сообщение B4rr4cuda »

minoshi писал(а):а как убить эту панель?

gtk_widget_hide(хэндл панели) -чтобы скрыть средствами gtk api.
gtk_widget_destroy(хэндл панели) -чтобы убить средствами gtk api
и Form1.Panel1.free -чтобы убить средствами самого лазаря :).
Неужели трудно было догадаться?
the_beginer
новенький
Сообщения: 30
Зарегистрирован: 29.05.2008 16:51:51

Сообщение the_beginer »

B4rr4cuda писал(а):
minoshi писал(а):а как убить эту панель?

gtk_widget_hide(хэндл панели) -чтобы скрыть средствами gtk api.
gtk_widget_destroy(хэндл панели) -чтобы убить средствами gtk api
и Form1.Panel1.free -чтобы убить средствами самого лазаря :).
Неужели трудно было догадаться?



теперь эту тему можно перенести в раздел FAQ. Это предложение админам, т.к. ресурсы в библиотеке - это может пригодиться каждому.
Ответить