ВКЛЮЧЕНИЕ В БИБЛИОТЕКУ ФОРМНесмотря на то, что DLL не имеет собственной формы, с ее помощью можно вызывать формы из связанных с библиотекой модулей. Для этого в библиотеке используется ссылка uses на связанные модули-формы и объявляются экспортируемые из DLL подпрограммы, в которых реализуется вызов соответствующих форм. В следующем примере иллюстрируется техника включения в DLL формы и использования ее в вызывающей программе. Текст DLL library DLLWithForm; Uses SysUtils, Classes, DLLFormU in 'DLLFormU.pas' {DLLForm}; {$R *.RES} Exports ShowModalForm, ShowForm, FreeForm; Begin End. Текст формы в DLL
unit DLLFormU; Interface Uses Windows, Messages, SysUtils,Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons; Type TDLLForm = class (TForm) BitBtnl: TBitBtn; BitBtn2: TBitBtn; procedure FormClose(Sender: TObject; var Action: TCloseAction); Private { Private declarations } CallForm: THandle; //Дескриптор вызывающей формы Public { Public declarations } End; // Объявление экспортируемых подпрограмм function ShowModalForm: Integer; procedure ShowForm(aHandle: THandle); procedure FreeForm; Var DLLForm: TDLLForm; Implementation {$R *.DFM} function ShowModalForm: Integer; // Модальный вызов Begin DllForm:= TDllForm.Create(Application); Result:= DLLForm.ShowModal; DLLForm.Free; End; procedure ShowForm(Appl, Form: THandle); // Немодальный вызов Begin Application.Handle:= Appl; // Замена объекта Application DllForm:= TDllForm.Create(Application); // Запоминаем дескриптор вызывающего окна для посылки // ему сообщения о закрытии CallForm:= Form; DLLForm.Show End; procedure FreeForm; // Уничтожение формы Begin DLLForm.Free end; procedure TDLLForm.FormClose(Sender: TObject; var Action: TCloseAction); Begin if CallFormoO then SendMessage(CallForm, wm_User, 0, 0) End; End. Текст вызывающей программы unit TestMainU; Interface Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; Type TTestMain = class (TForm) Buttoni: TButton; // Открыть в модальном режиме Button2: TButton; // Открыть в немодальном режиме Button3: TButton; // Закрыть окно Label I: TLabel; procedure ButtonlClick(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ButtonSClick(Sender: TObject); Private { Private declarations } public { Public declarations } procedure WMUser(var Msg: TMessage); message WM_USER; End; Var TestMain: TTestMain; Implementation {$R *.DFM} function ShowModalForm: Integer; External 'DLLWithForm'; procedure ShowForm(Appl, Form: THandle); External ' DLLWithForm'; procedure FreeForm; External 'DLLWithForm'; procedure TTestMain.ButtonlClick(Sender: TObject); // Модальный вызов Begin Button2.Enabled:= False; labell.Caption:= 'ModalResult = '+IntToStr(ShowModalForm); labell.Show; // Показываем результат вызова Button2.Enabled := True End; procedure TTestMain.Button2Click(Sender: TObject); // Немодальный вызов Begin Buttoni.Enabled:== False; Button2.Enabled:= False; Buttons.Enabled:= True; label 1.Hide; ShowForm(Application.Handle, Self.Handle); End; procedure TTestMain.Button3Click(Sender: TObject); // Закрыть форму Begin FreeForm; Button1.Enabled := True; Button2.Enabled:= True; Button3.Enabled:= False/end; procedure TTestMain.WMUser(var Msg: TMessage); // Сообщение из формы DLL о ее закрытии Begin Buttons.Click End; End. Модуль формы DLLForm, помещенной в DLL, ссылается на стандартный модуль Forms и таким образом получает свой глобальный объект Application, который ничего “не знает” о глобальном объекте вызывающей программы (см. гл. 21). В режиме модального вызова это не имеет особого значения, т. к. модальное окно блокирует работу вызывающей программы. В режиме немодального вызова следует синхронизовать действия объектов, в противном случае минимизация главного окна, например, не приведет к минимизации окна DLL. Синхронизация достигается тем, что дескриптор объекта Application DLL заменяется на соответствующий дескриптор вызывающей программы. При показе формы в немодальном режиме она может быть закрыта щелчком по собственной системной кнопке закрыть. В этом случае она должна каким-то образом известить вызывающую программу об этом событии. Для этого используется стандартный механизм посылки вызывающей форме Windows-сообщения. Сообщение должно иметь адрес, в роли которого используется дескриптор окна, получающего это сообщение. Вот почему вторым параметром обращения к функции ShowForm в DLL передается и в поле CallForm: запоминается дескриптор вызывающего окна. Обработчик события enclose формы проверяет это поле и, если оно определено, посылает вызывающему окну сообщение с индексом wm_user. В вызывающей программе предусмотрен обработчик этого сообщения, в котором реализуются необходимые действия.
Современные операционные системы Windows 32 обеспечивают не только многозадачность, т. е. возможность параллельной работы нескольких программ, но и многопоточность, когда в рамках одной программы организуется несколько параллельно выполняемых фрагментов (потоков), каждый из которых конкурирует с другими потоками за наиболее важный ресурс - время центрального процессора. В многопоточном режиме время ЦП выделяется для каждого процесса небольшими порциями (квантами), по истечении этого времени управление передается другому потоку и т. д. до тех пор, пока потоки не закончат свою работу. В любой работающей программе организуется как минимум один поток для команд программы. С помощью объектов класса TThread программа может создать дополнительные потоки для проведения некоторой фоновой работы (например, текстовый процессор Word создает дополнительные потоки для проверки правильности орфографии, разбивки на страницы, печати документа и т. п.). Для создания дополнительного потока в программах Delphi предназначен специальный модуль потока в репозитории он обозначен пиктограммой Thread Obiecll). При выборе этого модуля Delphi запрашивает имя класса, который будет дочерним для основополагающего класса TThread. Необходимость наследования связана с тем, что класс TThread содержит абстрактный метод Execute, который, собственно, и должен исполняться в рамках нового потока и который, следовательно, обязан перекрываться в потомках. После указания имени дочернего класса Delphi раскрывает дополнительный модуль с обширным комментарием и заготовкой для дочернего класса. Например (с соответствующим переводом): unit Unit1;
|