![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Прорисовка формы в DLL [D7, WinXP]
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, но этот метод есть не у всех компонентов.