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

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

Прорисовка формы в DLL [D7, WinXP]


Страницы:   1 2

vers ©   (2005-07-29 14:27:00) 

DLL динамически подключается к приложению, в DLL переменной Application присваивается Application приложения, создаются 2 формы, в качестве ParentWindow форм указывается хэндл формы приложения. Проблема: не прорисовываются некоторые компоненты форм DLL, например, SpeedButton'ы, при проведении через них мышью. То есть кнопка становится выпуклой при наведении на нее мышью, а в обратное состояние не возвращается, при уходе мышью с нее. В случае со SpeedButton'ами проблему решил путем установки таймера c интервалом в 100 мс, в обработчике для всех кнопок вызываю UpdateTracking, но как быть с компонентами, у которых нет метода UpdateTracking? Вызов Update или посылка сообщения WM_PAINT не помогают.


Юрий Зотов   (2005-07-30 22:47:00) [21]

> Defunct ©   (30.07.05 22:37) [15]

> цикл выборки подмененного Application'а никуда не девается

Естественно. Он просто начинает работать с другим Self. Соответственно, и с другим Handle.

> Почему бы при такой подмене не убивать внутренние (dll)
> экземпляры Application и Screen?

Потому что их надо будет восстановить перед выгрузкой DLL, чтобы она правильно финализировалась.


Defunct   (2005-07-30 22:45:00) [22]

> Юрий Зотов ©   (30.07.05 22:23) [14]

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

...
Application := app;
Screen := scr;
...

ведь он, как минимум, чреват несовместимостью dll и хост приложения при компиляции оных в разных версиях Delphi.


Defunct   (2005-07-30 22:37:00) [23]

> Поэтому предположение о том, что "цикл выборки экземпляра Application в DLL продолжает работать со старым handle'ом" выглядит спорным.

Спорным, но вполне допустимым.

Мне почему-то кажется, что цикл выборки подмененного Application'а никуда не девается и как минимум при такой подмене мешает нам работать, мы же наблюдаем лишь следствие этого - неправильную прорисовку (как будто часть сообщений не обрабатывается). Почему бы при такой подмене не убивать внутренние (dll) экземпляры Application и Screen?


Юрий Зотов   (2005-07-30 22:23:00) [24]

> Defunct

В справке так и рекомендуется. Но, как показывает практика, дочерние окна в DLL (например) при таком способе не работают, а при замене всего Application (и Screen) - работают. Аналогично и с другими глобальными объектами (скажем, если не подменять Session, то в DLL потребуется переоткрытие DataSet'ов).

Handle - это, в общем-то, всего лишь свойство Application. Естественно, подменяя Application, мы подменяем весь объект вместе со всеми его свойствами. Поэтому предположение о том, что "цикл выборки экземпляра Application в DLL продолжает работать со старым handle'ом" выглядит спорным.


Defunct   (2005-07-30 21:55:00) [25]

> Eraser

Вот отрыл в рабочем проекте:

procedure UploadFileThroughISP( ACallingProcessHandle : DWord;
                                 FileName: ShortString );stdcall;
begin
  if ACallingProcessHandle <> 0 then
     Application.Handle := ACallingProcessHandle;

  with TISPProgrammerForm.Create( nil ) do
  begin
     fFileName := FileName;
     L_FName.Caption := ExtractFileName( FileName );
     ShowModal;
  end
end;


Defunct   (2005-07-30 21:49:00) [26]

Eraser ©   (30.07.05 21:46) [11]

Правильно, и он нужен не более чем для НЕ создаваниядополнительного окна на панели задач. Я же говорю, что не трогая Application в DLL формы будут прорисовываться так, как положено.


Eraser   (2005-07-30 21:46:00) [27]

Defunct ©   (30.07.05 21:43) [10]

Вряд ли... хэндл Application - это всего навсего дескриптор невидимого окна и не более того.


Defunct   (2005-07-30 21:43:00) [28]

Почему-то мне кажется что проблема не в экспорте. Даже не присваивая Application := app и не присваивая screen форма созданная в dll должна прекрасно работать. Может быть все дело в том, что вы присваиваете целый экземпляр Application, а не его Handle. При этом цикл выборки экземпляра Application в DLL продолжает работать со старым handle'ом.

Короче говоря насколько я помню, делал так:
1. Вообще не трогал Application.
2. Присваивал handle'у экземпляра Application в DLL - handle Application'а хост приложения.

Попробуйте так:

procedure createform(AppHandle : Dword);
begin
Application.Handle := AppHandle;
Form := TForm2.Create(Application);
Form.Show;
end;

....
Createform:=GetProcAddress(dllhandle,'createform');
CreateForm(Application.Handle);
....


Юрий Зотов   (2005-07-30 21:16:00) [29]

> isasa ©   (30.07.05 20:28) [7]

Вообще-то, Application и Screen - это глобальные объекты модуля Forms, а никакого не ВАП. И если этот модуль в DLL используется - значит, они в DLL присутствуют. Причем именно свои собственные, а не те же самые, что в загружающей программе.

> isasa ©   (30.07.05 20:46) [8]

Как быть, если требуется создавать и уничтожать форму много раз по ходу программы? Или если требуется произвольное количество экземпляров формы?


isasa   (2005-07-30 20:46:00) [30]

Если я правильно понимаю идею, беспокоит вопрос о создании
фори при подключении,и их уничтожении при выгрузке библиотеки?
Не лучше ли поступить естественным путем, используя

   DLL_PROCESS_ATTACH: locDLLForm := TDLLForm.Create(nil);
   DLL_PROCESS_DETACH: locDLLForm.Free;

а експортировать указатель функцией

function GetForm: TDLLForm;
begin
result:=locDLLForm;
end;


isasa   (2005-07-30 20:28:00) [31]

Не совсем понятна мысль

procedure createform(app:TApplication; scr:TScreen);
begin
Application:=app;
Screen:=scr;
Form := TForm2.Create(Application);
...

а так не достаточно
Form := TForm2.Create(app);

Application и Screen глобальные переменные для ВАП, в DLL переменной Application нет и по определению быть
не может т.к. у DLL нет своего адресного пространства.


Юрий Зотов   (2005-07-30 19:54:00) [32]

> vers ©   (30.07.05 18:40) [4]

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

А вообще, радикальное решение - в [3]. DLL - это все же библиотека функций, а не объектов и экспорт форм из нее - моветон (хотя и можно, но от проблем не гарантирует). Поэтому лучше использовать BPL вместо DLL, либо уж хотя бы компилировать и приложение, и DLL с run-time пакетами.


Leonid Troyanovsky   (2005-07-30 19:14:00) [33]


> > Leonid Troyanovsky ©
>
> А можно поподробней про package? А то я про такое вообще
> не слышал...


http://softwarer.ru/packages.html

Но, начинать надо с Delphi help.

--
Regards, LVT.


vers   (2005-07-30 18:40:00) [34]


> Юрий Зотов ©

Код:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;
 dllhandle:THandle;
 createform:procedure(app:TApplication; scr:TScreen);

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
dllhandle:=LoadLibrary('c:\temp\project2.dll');
createform:=GetProcAddress(dllhandle,'createform');
CreateForm(Application,Screen);
end;

end.

--------------------------------

library Project2;

uses
 SysUtils,
 Classes,
 Forms,
 Unit2 in 'Unit2.pas' {Form2};

var
 Form : TForm2;

{$R *.res}

procedure createform(app:TApplication; scr:TScreen);
begin
 Application:=app;
 Screen:=scr;
 Form := TForm2.Create(Application);
 Form.Show;
end;

exports
 createform;

begin
end.



> Leonid Troyanovsky ©

А можно поподробней про package? А то я про такое вообще не слышал...


Leonid Troyanovsky   (2005-07-30 17:56:00) [35]


> vers ©   (29.07.05 14:27)  
> DLL динамически подключается к приложению, в DLL переменной
> Application присваивается Application приложения, создаются
> 2 формы, в качестве ParentWindow форм указывается хэндл
> формы приложения. Проблема: не прорисовываются


Пользуй package instead dll and be happy.

--
Regards, LVT.


Юрий Зотов   (2005-07-30 17:47:00) [36]

> Переприсваивание объекта Application

Еще и Screen переприсвоить не помешает. А вообще - код бы...


vers   (2005-07-30 17:40:00) [37]

Поясню вопрос примером:
приложение:

procedure TForm1.Button1Click(Sender: TObject);
begin
dllhandle:=LoadLibrary('c:\temp\dllforms.dll');
createform:=GetProcAddress(dllhandle,'createform');
CreateForm;
end;


dll:

procedure createform;
var
 DLLForm : TDLLForm;
begin
 DLLForm := TDLLForm.Create(Application);
 DLLForm.Show;
//  DLLForm.Free;
end;


На форме DLLForm находится пара SpeedButton'ов и XPManifest. Если провести по кнопкам мышью, они становятся выпуклыми, а в обратное состояние не возвращаются.
Также заметил, что если вместо DLLForm.Show использовать DLLForm.ShowModal и соответственно раскомментарить DLLForm.Free, то эта проблема не возникает. Но нужно использовать немодальную форму.
Переприсваивание объекта Application и отправка сообщений WM_PAINT в DLLForm проблему не решают. Помогает только периодический вызов SpeedButton.UpdateTracking, но этот метод есть не у всех компонентов.


Страницы:   1 2

Наверх

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