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

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

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

Восстановить пароль

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

Ответ
 
Опции темы Поиск в этой теме
Старый 02.01.2013, 15:49   #1
WhiskasTM
Подтвердите свой е-майл
 
Регистрация: 11.04.2012
Сообщений: 85
По умолчанию Динамическое создание компонентов из класса экспортирумый из dll : Cannot Assign TFont to TFont + Access Violation на выходе

С Новым Годом!

BPL не предлагать, ладно?

Суть, из dll грузится плагин который оформлен ввиде класса отдельным юнитом, он делает кнопку на форме главного приложения.

Интерфейс плагина(типа абстрактного класса)
Код:
unit uPluginInterface;

interface

type
  IPlugin = class
    procedure MakeButton;virtual;abstract;
  end;

implementation
end.
Допустим плагин, ввиде класса:
Код:
unit uWindows20;

interface

uses Vcl.Forms, Vcl.StdCtrls, uPluginInterface;

type
  TWindows20 = class(IPlugin)
  private
    Form:TForm;
    Btn:TButton;
  public
    procedure MakeButton;override;
    constructor Create(pForm:TForm);
  end;

implementation

constructor TWindows20.Create(pForm: TForm);
begin
 Form:=pForm;
end;

procedure TWindows20.MakeButton;
begin
 Btn:=TButton.Create(Form);
 with Btn do
  begin
  ParentFont:=false;
  Parent:=Form;
  Caption:='Launch Windows 20';
  end;
end;

end.
DLL с экспортом этого класса:
Код:
library Plugin;

uses
  Vcl.Forms,
  System.SysUtils,
  System.Classes,
  uPluginInterface in 'uPluginInterface.pas',
  uWindows20 in 'uWindows20.pas';

{$R *.res}

function __load(pForm:TForm):IPlugin;stdcall;
begin
  Result:=TWindows20.Create(pForm);
end;

exports
__load;

begin
end.
Приложение грузит плагин:
Код:
uses uPluginInterface;

.......

TLoad = function (pForm:TForm):IPlugin;stdcall;

var
  Form1: TForm1;
  Plugins:array of IPlugin;
  Load:TLoad;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
H:THandle;
begin
SetLength(Plugins,1);
H:=LoadLibrary(PWideChar('Plugin.dll'));
Load:=GetProcAddress(H,PWideChar('__load'));
Plugins[0]:=Load(Form1);
Plugins[0].MakeButton;
end;
Все работает (при условии, что при создании кнопки ParentFont стоит False, иначе будет Cannot Assign TFont to TFont).
Работает и ладно, но при закрытии формы выдается ошибка access violation. В call stack-е последним идет :00482b72 ListRemove+$A

Как починить?

EDIT:
Починил. Нужно чтоб сам плагин кнопку свою освобождал

Код:
TWindows20 = class
....
destructor Destroy;override;

....

implementation
....

destructor TWindows20.Destroy;
begin
Btn.Free;
end;
Плюс освобождать плагины в главном приложении:

Код:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
for i := 0 to High(Plugins) do Plugins[i].Free;
end;
Так всегда, мучался/учился дня 3, а стоило только сделать тему... ещё одна лишняя тема.

Последний раз редактировалось WhiskasTM; 02.01.2013 в 16:09.
WhiskasTM вне форума Ответить с цитированием
Старый 02.01.2013, 17:06   #2
spamer
Software Developer
Старожил
 
Аватар для spamer
 
Регистрация: 19.12.2008
Сообщений: 2,070
По умолчанию

ТС, посмотри вот сюда - урл, думаю будет полезно...
Будь проще и люди к тебе потянутся
spamer вне форума Ответить с цитированием
Старый 02.01.2013, 17:29   #3
WhiskasTM
Подтвердите свой е-майл
 
Регистрация: 11.04.2012
Сообщений: 85
По умолчанию

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

Кстати, тупую кнопку-то я сделал на главной форме, а вот держать события она не может, т.е. банально не выполняет их(события также в классе декларируются). Но зато когда сделать сначала панель, а затем на панели эту кнопку то все ОК. Че за грабли блин везде...
WhiskasTM вне форума Ответить с цитированием
Старый 02.01.2013, 18:35   #4
Кольша
Далеко не
Участник клуба
 
Аватар для Кольша
 
Регистрация: 11.08.2011
Сообщений: 1,512
По умолчанию

мне кажется или при создании кнопки надо еще передать Tfont основного приложения...
Кольша вне форума Ответить с цитированием
Старый 09.03.2013, 08:03   #5
WhiskasTM
Подтвердите свой е-майл
 
Регистрация: 11.04.2012
Сообщений: 85
По умолчанию

Все это бесполезно. А если работать ещё и со сторонними компонентами, то там такие ошибки выходят, что гугл выдает "нет результатов".

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

Код:
function SA_AddPanel(
const pOwner,pParent:TWinControl;
const pAlign:TAlign;
const pAnchors:TAnchors;
const pLeft,pTop,pWidth,pHeight:integer;
const bBorderOuter:TFrameStyleEx=fsNone;
const pTag:integer=0):TRzPanel;safecall; external 'Application.exe';
У меня таких десятка два теерь и вообще никаких проблем. А че, шикарно же =)
WhiskasTM вне форума Ответить с цитированием
Старый 18.04.2013, 13:09   #6
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,542
По умолчанию

точную причину назвать не смогу, но копать надо в сторону ShareMem.
DLL и EXE как абсолютно НЕЗАВИСИМЫЕ (на уровне Delphi не Windows) имеют ОТДЕЛЬНЫЕ менеджеры памяти (одинаковые но работающие независимо друг от друга). И каждый свой список типов объектов.
При работе с DLL безопасно(не имеет проблем) передавать можно только общесистемные типы(integer, point, Pchar,...) там где нечего делать менеджеру памяти. (не классы, и даже не string). Нandle передать можно.

создали удалили объекты =>сработал менеджер памяти DLL(выделили память) => выгрузили DLL => сработал менеджер памяти DLL(очистка) => использовали объект DLL =>AV
создали удалили объекты =>сработал менеджер памяти DLL(выделили память) => оставили DLL => сработал менеджер памяти DLL(очистка) => использовали объект DLL =>AV

shareMem данную проблему частично снимает.
Не зря ПЕРВОЙ же строчкой ВАС об этом предупреждают.
Цитата:
Код:
library Project1;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }
Такое верно для D7, что с новыми версиями не знаю.

D7 Help Writing dynamically loadable libraries
Цитата:
Note

If your application includes VisualCLX components, you must use packages instead of DLLs or shared objects. Only packages can manage the startup and shutdown of the Qt shared libraries.
Цитата:
A package is a specially compiled library used by applications, the IDE, or both. Packages allow you to rearrange where code resides without affecting the source code. This is sometimes referred to as application partitioning.
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 18.04.2013 в 13:19.
evg_m вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Создать шрифт из файла и сохранить его в виде TFont phomm Общие вопросы Delphi 4 22.12.2011 23:07
как переменную типа TFont перевести в тип integer? делфи_6 Общие вопросы Delphi 8 26.05.2010 06:02
[Как сохранить и прочитать TFont в реестр]. ZARO Общие вопросы Delphi 3 12.03.2010 22:41
Вопрос про TFont ? juan666777 Общие вопросы Delphi 6 29.05.2009 16:08