Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как достать фрейм из bpl ? [D2, D3, D4, D5, D6, D7, Win95/98, WinME, NT4, Win2k, WinXP]


BFG9k ©   (2005-10-07 16:02:00) 

Создаю пакет, включаю в него unit с фреймом.

Помпилирую пакет ,получаю bpl.

В другом проекте загружаю bpl  с помощью LoadPackage. Можно ли достать фрейм из bpl и кинуть на форму этого проекта ?


REA   (2005-10-12 15:55:00) [1]

Вариант 1:
Переменная M где-то портится.

Вариант 2:
Обработчики фрейма могут быть в BPL. При попытке вызова обработчика при выгруженной BPL - AV.

Вот это ничего не даст, т.к. во Free и так проверяется Assigned.
if Assigned(Frame1) then
    Frame1.Free;


BFG9k   (2005-10-12 14:56:00) [2]

Но AV возникает как раз в том случае, если я НЕ убиваю фрейм в finalization (даже если я нигде его не убиваю). Вот я и думаю, к чему бы это.


REA   (2005-10-12 10:57:00) [3]

Owner у Frame форма, она его и убъет.
Frame1.Free уже может работать по невалидной ссылке.


BFG9k   (2005-10-11 17:19:00) [4]

Да, видимо у меня невалидная ссылка.

Делаю следующим образом:


procedure TForm1.FormCreate(Sender: TObject);
var Flags:integer;
begin
  M:=LoadPackage('Packages\Package1.bpl');

  @FrameConstructor:=GetProcAddress(M,'CreateFrame');

  if Assigned(FrameConstructor) then
      Frame1:=FrameConstructor(Self,Self);//Первое - Owner , второе - Parent
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Frame1.Free;//можно не освобождать - результат тот же
  UnloadPackage(M);//возникает Access Violation
end;


  Так вот, AV не возникает, если в пакете сделать следующее :


implementation

var Frame1:TFrame1;

{$R *.dfm}

function CreateFrame(AOwner:TComponent;AParent:TWinControl):TFrame;
begin
  Frame1:=TFrame1.Create(AOwner);
  Frame1.Parent:=AParent;
  Result:=Frame1;
end;

exports
  CreateFrame name 'CreateFrame';
initialization
  Frame1:=nil;
finalization
  if Assigned(Frame1) then
     Frame1.Free; // в этом случае выгрузка происходит корректно
end.


Frame1 в пакете и программе - разные указатели, но на одну и ту же структуру (просто имена совпадают).


Reindeer Moss Eater   (2005-10-11 16:09:00) [5]

Если делать это в главной программе,

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


BFG9k   (2005-10-11 15:04:00) [6]

Если делать это в главной программе, то при вызове UnloadPackage имеем Access Violation. Ладно, сделаю индексацию динамическим массивом, это не долго.


Reindeer Moss Eater   (2005-10-11 14:37:00) [7]

Можно ли как-либо уничтожать экземпляр фрейма, имея только ссылку на него ?

<ссылка на него>.Free


BFG9k   (2005-10-11 14:19:00) [8]

Точно!

И последний вопрос: как лучше уничтожать созданные экземпляры фрейма ? При вызове Unload Package возникает Access Violation, если фрейм не уничтожить. Просто написать в основной программе Frame1.Free - не проходит. С одним экземпляром проблем нет - уничтожать его в DLL. Для нескольких экземпляров необходимо уже вести их индексацию в DLL. Можно ли как-либо уничтожать экземпляр фрейма, имея только ссылку на него ?


REA   (2005-10-11 13:30:00) [9]

Скомпилировать все с включенными run-time packages.


BFG9k   (2005-10-11 13:28:00) [10]

Спасибо. Никогда не подозревал, что раздел Exports может существовать прямо в модуле фрейма.

Однако не все так хорошо, как могло бы показаться. Попытался создать фрейм с одной кнопкой. Фрейм создался. В начале вылезла ошибка : Cannot assign TFont to TFont. При уничтожении фрейма - Access Violation.

Нашел статью о загрузке обьектов из DLL : http://www.delphimaster.ru/articles/book/Chap09.pdf

Смущает пункт 3 требований к DLL :

"Экспортируемый объект должен быть определен как в DLL , так и в вызывающем приложении с помощью методов, определенных в том же порядке."

2 раза определять объект?! Смысл применения DLL в таком случае пропадает.

Обнадеживает следующая фраза :

"Используемый подход применяется в весьма специфических ситуациях, и , как правило, такого же эффекта можно достичь путем применения пакетов и интерфейсов".

Применение энтерфейсов при взаимодействии Delphi с Delphi не обосновано. Я применяю пакеты, к сожалению в статье не сказано, как их применять :(


Reindeer Moss Eater   (2005-10-10 17:05:00) [11]

LoadPackage
EnumModules
Затем ищи с пом. GetProcAddress в модулях процедуру с предопределенным тобой именем: '@' + <Имя_Модуля> + '@' + <Имя_процедуры> + '$qqrv'
Она тебе и создаст нужный фрейм.


BFG9k   (2005-10-10 16:40:00) [12]

Нашел неплохую статью на эту тему : http://www.delphimaster.ru/articles/bdform/index.html

Правда все как-то через анус реализованно (хакерскими методами, я имею в виду).


BFG9k   (2005-10-10 16:24:00) [13]

Попробовал оба варианта.

1) Не нашел как экспортировать функцию из пакета. Можно ли вообще это сделать (в contains указываются только модули)? Попробовал сделать то же самое с DLL. Получилось вернуть Handle создаваемой формы, но не фрейма. Как только происходит обращение к Parent - исключение EInvalidOperation. При попытке вернуть экземпляр формы/фрейма - то же самое.
Привожу код DLL :

function CreateFrame(AParent:THandle):THandle;
begin
  Form1:=TForm1.CreateParented(AParent);
  Result:=Form1.Handle;
end;

procedure DestroyFrame;
begin
  Form1.Free;
end;

Exports
  CreateFrame name 'CreateFrame',
  DestroyFrame name 'DestroyFrame',
begin
end.


С фреймом то же самое не проходит - вылетает на CreateParented. Подозреваю, что TForm/TFrame вернуть невозможно в принципе :(

2) Делаю RegisterClass в разделе initialization модуля с фреймом. Секция выполняется - проверял. Загружаю пакет - FindClass ничего не находит.


REA   (2005-10-07 17:56:00) [14]

Можно поступить следующими способами:
1) Экспортировать функцию - конструктор фрейма, возвращающую фрейм (базовый класс)
2) Зарегистрировать в bpl класс при помщи RegisterClass, найти его в программе и создать на основе метакласса объект.


Наверх

Титульная страница Поиск, карта сайта Написать письмо