Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.09.2017, 10:59   #1
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
Счастье Динамические формы из библиотек

Я наконец то сделал это! и вот решил поделиться со всеми заинтересованными!
Во-первых создаем основной проект MDI главная форма которая имеет CategoryPanelGroup и 1 CategoryPanel. выглядит так
1.jpg

дальше делаем обработчик кнопок

Код:
procedure TMainForm.FormInDLLClick(Sender: TObject);
var
  DLLRoutine: procedure;
  DLLHandle: THandle;
begin
  DLLHandle := loadlibrary(pwidechar('mods\' + tbutton(Sender).Name));
  DLLRoutine := GetProcAddress(DLLHandle, 'Create_Form');
  if Assigned(DLLRoutine) then
    DLLRoutine
  else
    MessageDlg('Файл не найден или не подходит.',
      mtInformation, [mbOK], 0);
end;
далее обработчики всех кнопок будут выполнять эту процедуру, затем при создании формы нам нужно создать массив со списком имеющихся у нас библиотек с формами в папке "mods", для этого есть процедура

Код:
procedure TMainForm.Find;
var
  SearchRec: TSearchRec;
  FileName, cDir: String;
  n: LongInt;
begin
  n := 1;
  cDir := ExtractFilePath(ParamStr(0)) + '\mods';
  FileName := '*.dll';
  ChDir(cDir);
  if FindFirst(FileName, faArchive, SearchRec) = 0 then
    repeat
      if (SearchRec.Attr and faAnyFile) = SearchRec.Attr then
      begin
        SetLength(massiv, Length(massiv) + 1);
        massiv[n - 1] := SearchRec.Name;
        inc(n);
      end;
    until FindNext(SearchRec) <> 0;
end;
в ней massiv - глобальная переменная типа Array of String.

после чего в FormCreate создаем сами кнопки

Код:
procedure TMainForm.FormCreate(Sender: TObject);
var
  b: tbutton;
  i: Integer;
begin
  Find;
  for i := 0 to Length(massiv) - 1 do
  begin
    b := tbutton.Create(self);
    b.Parent := CategoryPanel1;
    b.Align := alTop;
    delete(massiv[i], massiv[i].Length - 3, 4);
    b.Name := massiv[i];
    b.Caption := b.Name;
    b.OnClick := FormInDLLClick;
  end;
end;
где и назначаем обработчик события нажатия.

Caption кнопок планирую брать из константы библиотеки, но еще не тестил.

теперь переходим к библиотеке, и собственно вот ее код

Код:
library formInDLL;

uses
  Winapi.Windows,
  System.SysUtils,
  System.Classes,
  Vcl.Graphics,
  Vcl.Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

procedure Create_Form(); export;
begin
  TForm1.Create(Application);
end;

exports
Create_Form;

begin
end.
теперь в проекте с библиотекой создаем новую форму, MDIChild
с единственной процедурой

Код:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;
и последний шаг в проекте главного окна и каждой библиотеки нужно поставить галочку

2.JPG
затем в библиотеке можно настраивать форму и писать в ней ее код, что бы появилась кнопка, собранную библиотеке нужно положить в папку mods к основному приложению!
Спасибо за внимание!
PTyTb32 вне форума Ответить с цитированием
Старый 07.09.2017, 13:36   #2
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Гладко стелишь фраерок... Но:
Раз ты runtime packages юзаешь - делал бы дочерние формы в bpl тоже
Даже если рантайм, я рантаймлю только большие пакеты такие как rtl и vcl, остальные из runtime packages выкидываю т.е. они вкомпилируются в exe и не надо таскать кучу bplек а только rtl и vcl.
Либо без runtime packages тогда нужно в dll передать Application.Handle чтоб и в приложении и в dll они были одинаковые
ну и для dll обычно используют форму вызова stdcall.

Код:
procedure Create_Form(AppHandle:THandle); stdcall; export;  
begin  
  Application.Handle:=AppHandle;  
  with TForm1.Create(Application) do Show;  
end;
кроме того нет ни одного FreeLibrary, т.е. однажды загруженную библиотеку не выгрузишь до закрытия...
я бы сделал подсчет ссылок и делал бы FreeLibrary по достижению нуля
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 07.09.2017 в 14:01.
Slym вне форума Ответить с цитированием
Старый 07.09.2017, 13:54   #3
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
По умолчанию

Цитата:
Сообщение от Slym Посмотреть сообщение
делал бы дочерние формы в bpl тоже
стоп. то есть я мог добавлять не dll, а bpl и было бы проще? runtime packages - вообще не знаю что это, но с ней все работает, на каком то форуме посоветовали. и в чем разница bpl или dll добавлять?

Цитата:
Сообщение от Slym Посмотреть сообщение
FreeLibrary
вообще не юзаю.. надо исправить)

Последний раз редактировалось PTyTb32; 07.09.2017 в 14:03.
PTyTb32 вне форума Ответить с цитированием
Старый 07.09.2017, 14:46   #4
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
По умолчанию

Цитата:
Сообщение от Slym Посмотреть сообщение
Либо без runtime packages тогда нужно в dll передать Application.Handle
Код:
procedure TMainForm.FormInDLLClick(Sender: TObject);
var
  DLLRoutine: procedure; stdcall;
  DLLHandle: THandle;
begin
  DLLHandle := loadlibrary(pwidechar('mods\' + tbutton(Sender).Name));
  DLLRoutine := GetProcAddress(DLLHandle, 'Create_Form(AppHandle:THandle)');
  if Assigned(DLLRoutine) then
    DLLRoutine(self.Handle)
  else
    MessageDlg('Файл не найден или не подходит.',
      mtInformation, [mbOK], 0);

end;
ошибка
[dcc32 Error] Main.pas(62): E2034 Too many actual parameters
PTyTb32 вне форума Ответить с цитированием
Старый 07.09.2017, 18:46   #5
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Код:
procedure TMainForm.FormInDLLClick(Sender: TObject);
var
  DLLHandle: THandle;
  DLLRoutine: procedure(AppHandle:THandle); stdcall;
begin
  DLLHandle := loadlibrary(pwidechar('mods\' + tbutton(Sender).Name));
  DLLRoutine := GetProcAddress(DLLHandle, 'Create_Form');
  if Assigned(DLLRoutine) then
    DLLRoutine(Application.Handle)
  else
    MessageDlg('Файл не найден или не подходит.',
      mtInformation, [mbOK], 0);
end;
про формы в bpl завтра....

и вообще - слоев абстракции маловато
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 07.09.2017 в 18:51.
Slym вне форума Ответить с цитированием
Старый 08.09.2017, 03:09   #6
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,859
По умолчанию

Цитата:
Сообщение от PTyTb32 Посмотреть сообщение
стоп. то есть я мог добавлять не dll, а bpl и было бы
Мог и было бы.
Но ты бы озвучил свою задачу.
P.S. А по поводу
Цитата:
Сообщение от Slym Посмотреть сообщение
передать Application.Handle
тут Slym ошибся. Передавать нужно не Application.Handle, а ссылку на сам объект Application.
Ну и. Если тебя действительно интересует тема "плагинов в Дельфи", то почитай для начала Создаём систему плагинов, часть 1
А потом и далее.
northener вне форума Ответить с цитированием
Старый 08.09.2017, 06:11   #7
Filka
Форумчанин
 
Регистрация: 29.10.2015
Сообщений: 272
По умолчанию

Цитата:
Сообщение от northener Посмотреть сообщение
тут Slym ошибся. Передавать нужно не Application.Handle, а ссылку на сам объект Application.
То есть Стив Тейксейра и Ксавье Пачеко пишут ерунду?
Filka на форуме Ответить с цитированием
Старый 08.09.2017, 08:34   #8
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Применяемо для компиляции без runtime packages:
В общем то для убирания задвоения в панеле задач достаточно Application.Handle, для более тесной интеграции можно и Application передать...
НО! Тогда необходимо следить чтоб имена классов окон были строго уникальны!
если в приложении TForm1 и в dll тоже - то ошибка.
И перед смертью dll подменять Application на родное значение.

Для runtime packages:
Application зашит в vcl.bpl и уже общий для exe и dll и танцы с бубном не нужны

PS1: а ссылочка http://www.gunsmoker.ru/2008/12/1.html правильная... почитай, но я там не совсем согласен (сложновато) и не до конца (с моей точки зрения) раскрыта выгрузка плагинов.


PS2: и с резюмирую основную проблему это - корректная выгрузка плагина
а именно недопущение выгрузки плагина до закрытия окон плагина, выгрузка плагина раньше закрытия приложения и своевременная подмена Application в плагине.

PS3: интерфейсы конечно хорошо, но я за COM...

PS4: спустя n часов оказывается нужно еще и Screen отдавать в приложение
т.к. MDIChildren пользует Screen для энумерации окон
Вложения
Тип файла: zip MDI App.zip (18.9 Кб, 31 просмотров)
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 08.09.2017 в 11:15.
Slym вне форума Ответить с цитированием
Старый 10.09.2017, 01:42   #9
northener
ПШП
Участник клуба
 
Регистрация: 15.07.2013
Сообщений: 1,859
По умолчанию

Цитата:
Сообщение от Filka Посмотреть сообщение
То есть Стив Тейксейра и Ксавье Пачеко пишут ерунду?
Нет, конечно. Только вы об чем собственно?
Я лишь о том костыле, который позволяет избавится от того, что Дельфи считает разными два по сути идентичных класса. Только из-за того, что они имеют разные адреса.

Последний раз редактировалось northener; 10.09.2017 в 01:54.
northener вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Динамические формы Orchestroman Общие вопросы Delphi 4 16.03.2012 23:53
Подключение библиотек mishalive Общие вопросы Delphi 5 23.08.2011 09:50
Передача переменных в форму, динамические формы nasprin Microsoft Office Excel 2 10.06.2011 14:34
Подключение библиотек MovsesIV Общие вопросы C/C++ 1 27.12.2010 21:25
Описание библиотек в Си papochka Общие вопросы C/C++ 1 28.10.2009 10:51