eManual - электронная документация
Программирование на основе Win32 API в Delphi
Оглавление
Введение
Существующие решения
Принципы построения API-библиотеки
Библиотека WinLite
Пример программы на основе библиотеки WinLite
Любую современную программу или программную технологию можно представить как совокупность программных
"слоев". Каждый из этих слоев производит свою собственную работу, которая заключается в повышении
уровня абстракции производимых операций. Так, самый низший слой (слои) вводит понятия, которые позволяют
абстрагироваться от используемого оборудования; следующий слой (слои) позволяет программисту
абстрагироваться от сложной последовательности вызовов функций, вводя такое понятие как
протокол и т.д. Практически в любом современном программном продукте можно обнаружить и выделить
около десятка последовательных слоев абстракции.
Абстракция от оборудования и низкоуровневых протоколов вводится в ядра операционных систем в виде
библиотек API (Application Program Interface).
Однако современные тенденции приводят к необходимости абстрагирования и от самих
операционных систем, что позволяет переносить программы с одной операционной системы на другую путем
простой перекомпиляции (транслируемые программы, в основном, вообще не требуют никаких действий по
переносу).
Абстракцию, которая доступна программисту в виде библиотек API можно назвать базовой.
Это самый низкий уровень абстракции, который доступен для прикладного программирования. На уровне ядра
системы доступны и более низкие уровни абстракции, однако для их использования необходимо разрабатывать
специализированные программы (драйвера, модули). Базовый уровень абстракции (API) предоставляет
максимально широкие возможности для прикладного программирования и является наиболее гибким. Однако,
программирование с использованием API является гораздо более трудоемким и приводит к значительно
большим объемам исходного кода программы, чем программирование с использованием дополнительных библиотек.
Дополнительные библиотеки поставляются со многими средствами разработки с целью уменьшения трудоемкости
и сроков разработки программ, что в итоге приводит к повышению их конкурентноспособности. Но применение
дополнительных библиотек абстракций приводит к резкому увеличению размеров откомпилированных программ,
из-за того что в программу включается код используемых библиотек, к тому же это включение зачастую
бывает неэффективным - в программу включаются неиспользуемые участки кода. Кроме того, чем больше уровень
абстракции библиотеки, тем сложнее ее код, и тем больше трудностей возникает при решении сложных задач.
Приходится учитывать множество взаимосвязей и взаимных влияний отдельных элементов и процессов библиотеки
друг на друга. Кроме того, структура и функциональность любой библиотеки обычно
рассчитывается на удовлетворение всех потенциально возникающих задач, что приводит
к ее громоздкости и неэффективности.
В Delphi используется очень мощная и сложная библиотека VCL (Visual Components Library), которая помимо
непосредственных абстракций вводит также и множество своих функциональных классов. В этой библиотеке
находятся компоненты для визуального отображения информации, работы с базами данных, с системными объектами,
компоненты для работы с Internet-протоколами, классы для написания своих COM-объектов и многое другое.
Модули библиотеки подключаются к компиляции по мере необходимости, однако базовый размер простейшего
диалогового проекта с одной формой превышает 300кБ (со статически скомпонованной библиотекой). И такой
размер во многих случаях может оказаться слишком большим, особенно если программа не требует большой
функциональности в интерфейсе.
Для решения этой проблемы можно отказаться от использования библиотеки VCL, и программировать,
используя базовый набор функций Win32 API. Однако, если при разработке линейных, недиалоговых,
нерезидентных программ не возникает никаких трудностей, то разработка программ, требующих активного
взаимодействия с пользователем или системой, становится трудоемкой. Структурное
программирование, рекомендуемое в таких случаях, оказывается неэффективным и трудоемким.
Данная статья посвящена проблеме создания и использования компактной объектно-ориентированной
библиотеки, которая бы облегчила построение небольших и эффективных программ на основе Win32 API.
Автору известны три объектно-ориентированные библиотеки, которые можно
рассматривать как альтернативу библиотеке VCL при написании компактных программ.
Это библиотеки классов XCL, ACL и KOL. Все библиотеки бесплатны и поставляются в исходных кодах.
Библиотека ACL | (API control library) |
Автор: | Александр Боковиков, Екатеринбург, Россия |
Страничка: | http://a-press.ur.ru/pc/bokovikov |
E-Mail: | abb@adx.ru |
Классы и модули: | TFont, TFonts, TControl, TWinControl, TStdControl, TLabel, TEdit, TListBox,
TButton, TCheckBox, TComboBox, TGroupBox, TProgressBar, TKeyboard |
Библиотека XCL | (Extreme class library) |
Автор: | Vladimir Kladov (Mr.Bonanzas) |
Страничка: | http://xcl.cjb.net |
E-Mail: | bonanzas@xcl.cjb.net |
Классы и модули: | XForm, XApplet, XCanvas, XPen, XBrush, XFont, ZDDB, ZHiBmp, ZDIBitmap,
ZBitmap, ZIcon, ZGifDecoder, ZGif, ZJpeg, XLabel, XButton, XBevel, XPanel, XSplitPanel, XStatus, XGrep,
XGroup, XCheckBox, XRadioBox, XPaint, XScroller, XScrollBox, XScrollBoxEx, XEdit, XNumEdit,
XCombo, XGrid, XListView, XMultiList, XNotebook, XTabs, XTabbedNotebook, XCalendar, XGauge, XGaugePercents,
XHysto, XHystoEx, XImageList, XImgButton, XTooltip, XCustomForm, XDsgnForm, XDsgnNonvisual,
CLabel, CPaint, CButton, CEdit, CMemo, CCheckBox, CRadioBox, CListBox, CComboBox,
ZList, ZMenu, ZPopup, ZMainMenu, ZPopupMenu, ZTimer, ZStrings, ZStringList,
ZIniFile, ZThread, ZQueue, ZFileChange, ZDirChange, ZOpenSaveDialog, ZOpenDirDialog,
ZTree, ZDirList, ZDirListEx, ZRegistry, ZStream, ZFileStream, ZMemoryStream,
XStrUtils, XDateUtils, XFileUtils, XWindowUtils, XPrintUtils,
XShellLinks, XJustOne, XJustOneNotify, XPascalUnit,
XSysIcons, XCanvasObjectsManager, XRotateFonts, XFocusPainter,
XFormsStdMouseEvents, XFormsStdKeyEvents, XFormAutoSizer, XAligner, XControlAutoPlacer,
XMfcAntiFlicker, XSplitSizer, XResizeAntiFlicker, XCaretShower, XEditMouseSelect, XEditClipboard,
XEditUndo, XListMouseSel, XListKeySel, XListEdit, ZNamedTags, XBtnRepeats, XBufLabels, XBackgrounds,
XWndDynHandlers |
Библиотека KOL | (Key object library) |
Автор: | Vladimir Kladov (Mr.Bonanzas) |
Страничка: | http://xcl.cjb.net |
E-Mail: | bonanzas@xcl.cjb.net |
Классы и модули: |
TObj, TList, TGraphicTool, TCanvas, TControl, TTimer, TTrayIcon, TStream, TStrList,
TDirList, TIniFile
|
Как видно из списка приведенных для каждой библиотеки классов, эти библиотеки предендуют скорее не
на помощь при написании программ с использованием Win32 API,
а пытаются создать более высокий уровень абстракции чем API, по крайней мере в графической части
(особенно это относится к XCL). Более того, иерархия и перечень объектов совпадают
с соответствующими структурами в библиотеке VCL, что скорее всего связано с желанием авторов обеспечить
логическую совместимость с VCL при построении программ на основе этих библиотек.
Данные библиотеки не обеспечивают минимального размера программы, за счет того что предоставляют более
высокий уровень абстракции. Они являются компромисом между программированием с использованием VCL
и программированием на чистом API.
Стандартным видом API-программирования является структурное программирование. Примеры такого
программирования на Win32 API есть практически в любой книжке по Borland Pascal, Borland C++,
Microsoft Visual C++ и другим системам разработки. Множество примеров API-программирования на С содержится
в поставке Microsoft Visual C++.
Структурное программирование с оконными функциями, процедурами обработки команд, не в состоянии
обеспечить быструю и эффективную разработку программ. В современной ситуации большинство программистов
привыкло к объектно-ориентированному методу, с возможностью инкапсуляции, наследования и переопределения
методов объектов. Такое программирование оказывается наиболее эффективным.
Кроме того, для построения эффективной API-библиотеки прежде всего нужно выяснить, какие задачи при работе
с Win32 API являются наиболее трудоемкими. Практика показывает, что наиболее неудобным и трудоемким
элементом является реализация основного диспетчера логики программы - оконной функции. Реализация
этой функции в качестве метода класса, а не простой глобальной функции, позволила бы улучшить структуру
кода и облегчить программирование путем инкапсулирования всех переменных внутри оконного класса.
Программирование может быть еще более облегчено, есть возпользоваться механизмом message-процедур
языка Object Pascal. Вызов этих процедур полностью лежит на компиляторе и корневом объекте TObject и
включает в себя методы Dispatch, DefaultHandler, а также все методы, объявленные с директивой message.
Такое решениее позволит полностью отказаться от громоздкого оператора case в оконной функции.
Учитывая все вышеперечисленное автором была создана компактная библиотека оконных классов WinLite.
Эта библиотека является минимальной, она не вводит более высоких уровней абстракции чем существуют
в Win32 API - она только облегчает работу, переводом программирования в объектно-ориентированное русло.
Размер библиотеки очень небольшой и вся она помещается в один модуль.
Библиотека реализует базовый класс TLiteFrame и построенные на основе него оконные классы:
TLiteWindow - класс окна, с возможностью subclass'инга;
TLiteDialog - класс немодального диалога;
TLiteDialogBox - класс модального диалога.
Библиотека может быть использована совместно с VCL. На первый взгляд, это возможность является
абсурдной и ненужной, так как об экономии размера в этом случае не может быть и речи.
Однако, иногда бывают моменты, когда реализация специфических оконных
элементов на основе объектов TWinControl или TCustomControl может быть затруднена или неэффективна
из-за их сложности и неочевидного поведения.
В этом случае, можно реализовать такой элемент на базе класса TLiteWindow - он
будет вести себя стандартным образом, как и полагается вести себя стандартному оконному элементу Win32.
Благодаря своей простой архитектуре библиотека может быть использована в многопоточной программе.
Конечно, вы не сможете вызывать методы классов одного потока из другого потока без соответствующей
синхронизации. Однако, вы можете беспрепятственно создавать оконные классы в различных потоках без блокировки
и синхронизации, а также посылать сообщения оконным классам в другом потоке.
Практический совет: при API-программировании программист должен сам следить за корректным
освобождением многочисленных ресурсов, которые занимает программа во время выполнения. Поэтому, для
облегчения этой задачи используйте какую-либо контролирующую утилиту, например MemProof или Numega
BoundsChecker. Корректное освобождение занятых ресурсов крайне необходимо !
Для редактирования шаблонов диалогов можно использовать любой редактор ресурсов, например Borland
Resource WorkShop, правда он несколько неудобен, а окончательный результат все равно приходится
корректировать вручную.
Вся документация необходимая для API-программирования содержится в поставляемых компанией
Microsoft компакт-дисках с документацией под общим названием MSDN (Microsoft Developer's
Network). Существует online-версия документации по адресу
http://msdn.microsoft.com. Урезанная версия MSDN,
содержащая основные файлы помощи, поставляется с Delphi.
Прежде чем вы решите работать над своим проектом в русле Win32 API, подумайте, а зачем
вам это нужно? В подавляющем числе случаев размер программы не имеет никакого значения.
Я не хочу сказать, что API-программирование сложнее чем VCL-программирование. Во многих случаях
легче изучить и написать 10 вызовов API с кучей аргументов и понимать, что происходит, чем написать
1 вызов простой, на первый взгляд, VCL-инструкции и потом долго исследовать дебри VCL в поисках
ответа. Просто API-программирование - это другая культура, к которой вы, возможно, не привыкли.
И первоначальная работа может вызвать у вас сильное разочарование. API-программирование требует
дотошности, кропотливости и внимательного изучения документации.
Те же, кто отважился программировать на API, наряду с библиотекой WinLite могут совместно использовать
невизуальные классы как из состава VCL (модули SysUtils, Classes), так и многие сторонние -
естественно, что размер вашей программы при этом увеличится.
Невизуальные классы библиотеки ACL - http://a-press.ur.ru/pc/bokovikov
Невизуальные классы библиотеки XCL - http://xcl.cjb.net
JEDI Code Library - http://www.delphi-jedi.com
Системные компоненты на Torry - http://www.torry.ru
Заслуживает внимание работа Владимира Кладова по изменению функциональности обязательного
модуля system.pas. Со времен первых версий Turbo Pascal этот модуль по умолчанию
компонуется в исполняемый код программы. Код модуля реализует многие принципы и решения
заложенные в синтаксис и логику языка Object Pascal, и изменение этого модуля позволяет
модифицировать реализацию этой логики. Такое решение является специфичным для языка Object
Pascal в отличие, например, от C/C++, где компилятор и абсолюдно все модули никак не связаны.
Изменение модуля system.pas, а именно его разбиение на блоки и сокращение редко используемых
участков кода позволило сократить постоянные (не переменные) издержки примерно на 8 кБ.
Конечно, для больших проектов, такое сокращение может быть и незаметным, однако интересен
сам принцип.
Модифицированный модуль system.pas - http://xcl.cjb.net
////////////////////////////////////////////////////////////////////////////////
// WinLite, библиотека классов и функций для работы с Win32 API
// (c) Николай Мазуркин, 1999-2000
// _____________________________________________________________________________
// Оконные классы
////////////////////////////////////////////////////////////////////////////////
unit WinLite;
interface
uses Windows, Messages;
Инициализационные структуры
Объявление структур, которые используются для формирования параметров вновь создаваемых окон
и диалогов соответственно.
////////////////////////////////////////////////////////////////////////////////
// Параметры для создания окна
////////////////////////////////////////////////////////////////////////////////
type
TWindowParams = record
Caption : PChar;
Style : DWord;
ExStyle : DWord;
X : Integer;
Y : Integer;
Width : Integer;
Height : Integer;
WndParent : THandle;
WndMenu : THandle;
Param : Pointer;
WindowClass : TWndClass;
end;
////////////////////////////////////////////////////////////////////////////////
// Параметры для создания диалога
////////////////////////////////////////////////////////////////////////////////
type
TDialogParams = record
Template : PChar;
WndParent : THandle;
end;
Декларация базового класса TLiteFrame
Базовый класс для окон и диалогов. Инкапсулирует в себе дескриптор окна и объявляет
общую оконную процедуру. Реализует механизм message-процедур.
////////////////////////////////////////////////////////////////////////////////
// TLiteFrame
// _____________________________________________________________________________
// Базовый класс для объектов TLiteWindow, TLiteDialog, TLiteDialogBox
////////////////////////////////////////////////////////////////////////////////
type
TLiteFrame = class(TObject)
private
FWndCallback: Pointer;
FWndHandle : THandle;
FWndParent : THandle;
function WindowCallback(hWnd: HWnd; Msg, WParam, LParam:Longint):Longint; stdcall;
protected
procedure WindowProcedure(var Msg: TMessage); virtual;
public
property WndHandle: THandle read FWndHandle;
property WndCallback: Pointer read FWndCallback;
public
constructor Create(AWndParent: THandle); virtual;
destructor Destroy; override;
end;
Декларация оконного класса TLiteWindow
Создание уникального класса окна и создание окна. Возможность субклассинга стороннего окна.
////////////////////////////////////////////////////////////////////////////////
// TLiteWindow
// _____________________________________________________________________________
// Оконный класс
////////////////////////////////////////////////////////////////////////////////
type
TLiteWindow = class(TLiteFrame)
private
FWndParams : TWindowParams;
FWndSubclass: Pointer;
protected
procedure CreateWindowParams(var WindowParams: TWindowParams); virtual;
public
procedure DefaultHandler(var Msg); override;
constructor Create(AWndParent: THandle); override;
constructor CreateSubclassed(AWnd: THandle); virtual;
destructor Destroy; override;
end;
Декларация диалогового класса TLiteDialog
Загрузка шаблона диалога и создание диалога.
////////////////////////////////////////////////////////////////////////////////
// TLiteDialog
// _____________________________________________________________________________
// Диалоговый класс
////////////////////////////////////////////////////////////////////////////////
type
TLiteDialog = class(TLiteFrame)
private
FDlgParams : TDialogParams;
protected
procedure CreateDialogParams(var DialogParams: TDialogParams); virtual;
public
procedure DefaultHandler(var Msg); override;
constructor Create(AWndParent: THandle); override;
destructor Destroy; override;
end;
Декларация модального диалогового класса TLiteDialogBox
Загрузка шаблона диалога и создание диалога. Модальный показ диалога.
////////////////////////////////////////////////////////////////////////////////
// TLiteDialogBox
// _____________________________________________________________________________
// Модальный диалоговый класс
////////////////////////////////////////////////////////////////////////////////
type
TLiteDialogBox = class(TLiteFrame)
private
FDlgParams : TDialogParams;
protected
procedure CreateDialogParams(var DialogParams: TDialogParams); virtual;
public
procedure DefaultHandler(var Msg); override;
public
function ShowModal: Integer;
end;
Реализация базового класса TLiteFrame
implementation
////////////////////////////////////////////////////////////////////////////////
// TLiteFrame
// _____________________________________________________________________________
// Инициализация / финализация
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Конструктор
////////////////////////////////////////////////////////////////////////////////
constructor TLiteFrame.Create(AWndParent: THandle);
begin
inherited Create;
// Запоминаем дескриптор родительского окна
FWndParent := AWndParent;
// Создаем место под блок обратного вызова
FWndCallback := VirtualAlloc(nil,12,MEM_RESERVE or MEM_COMMIT,PAGE_EXECUTE_READWRITE);
// Формируем блок обратного вызова
asm
mov EAX, Self
mov ECX, [EAX].TLiteFrame.FWndCallback
mov word ptr [ECX+0], $6858 // pop EAX
mov dword ptr [ECX+2], EAX // push _Self_
mov word ptr [ECX+6], $E950 // push EAX
mov EAX, OFFSET(TLiteFrame.WindowCallback)
sub EAX, ECX
sub EAX, 12
mov dword ptr [ECX+8], EAX // jmp TLiteFrame.WindowCallback
end;
end;
////////////////////////////////////////////////////////////////////////////////
// Деструктор
////////////////////////////////////////////////////////////////////////////////
destructor TLiteFrame.Destroy;
begin
// Уничтожаем структуру блока обратного вызова
VirtualFree(FWndCallback, 0, MEM_RELEASE);
// Уничтожение по умолчанию
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
// TLiteFrame
// _____________________________________________________________________________
// Функции обработки сообщений
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Функция обратного вызова для получения оконных сообщений
////////////////////////////////////////////////////////////////////////////////
function TLiteFrame.WindowCallback(hWnd: HWnd; Msg, WParam, LParam: Integer): Longint;
var
WindowMsg : TMessage;
begin
// Запоминаем дескриптор окна, если это первый вызов оконной процедуры
if FWndHandle = 0 then FWndHandle := hWnd;
// Формируем сообщение
WindowMsg.Msg := Msg;
WindowMsg.WParam := WParam;
WindowMsg.LParam := LParam;
// Обрабатываем его
WindowProcedure(WindowMsg);
// Возвращаем результат обратно системе
Result := WindowMsg.Result;
end;
////////////////////////////////////////////////////////////////////////////////
// Виртуальная функция для обработки оконных сообщений
////////////////////////////////////////////////////////////////////////////////
procedure TLiteFrame.WindowProcedure(var Msg: TMessage);
begin
// Распределяем сообщения по обработчикам
Dispatch(Msg);
end;
Реализация оконного класса TLiteWindow
////////////////////////////////////////////////////////////////////////////////
// TLiteWindow
// _____________________________________________________________________________
// Инициализация / финализация
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Конструктор
////////////////////////////////////////////////////////////////////////////////
constructor TLiteWindow.Create(AWndParent: THandle);
begin
inherited;
// Формируем параметры окна
CreateWindowParams(FWndParams);
// Регистрируем класс окна
RegisterClass(FWndParams.WindowClass);
// Создаем окно
with FWndParams do
CreateWindowEx(ExStyle, WindowClass.lpszClassName, Caption,
Style, X, Y, Width, Height,
WndParent, WndMenu, hInstance, Param
);
end;
////////////////////////////////////////////////////////////////////////////////
// Конструктор элемента с субклассингом
////////////////////////////////////////////////////////////////////////////////
constructor TLiteWindow.CreateSubclassed(AWnd: THandle);
begin
inherited Create(GetParent(AWnd));
// Сохраняем оконную функцию
FWndSubclass := Pointer(GetWindowLong(AWnd, GWL_WNDPROC));
// Сохраняем дескриптор окна
FWndHandle := AWnd;
// Устанавливаем свою оконную функцию
SetWindowLong(FWndHandle, GWL_WNDPROC, DWord(WndCallback));
end;
////////////////////////////////////////////////////////////////////////////////
// Деструктор
////////////////////////////////////////////////////////////////////////////////
destructor TLiteWindow.Destroy;
begin
// Наш объект - объект субклассиннга ?
if FWndSubclass = nil then
begin
// Уничтожаем класс окна
UnregisterClass(FWndParams.WindowClass.lpszClassName, hInstance);
// Уничтожаем окно
if IsWindow(FWndHandle) then DestroyWindow(FWndHandle);
end
else
// Восстанавливаем старую оконную функцию
SetWindowLong(FWndHandle, GWL_WNDPROC, DWord(FWndSubclass));
// Уничтожение по умолчанию
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
// Формирование параметров окна по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteWindow.CreateWindowParams(var WindowParams: TWindowParams);
var
WndClassName : string;
begin
// Формируем имя класса
Str(DWord(Self), WndClassName);
WndClassName := ClassName+':'+WndClassName;
// Заполняем информацию о классе окна
with FWndParams.WindowClass do
begin
style := CS_DBLCLKS;
lpfnWndProc := WndCallback;
cbClsExtra := 0;
cbWndExtra := 0;
lpszClassName := PChar(WndClassName);
hInstance := hInstance;
hIcon := LoadIcon(0, IDI_APPLICATION);
hCursor := LoadCursor(0, IDC_ARROW);
hbrBackground := COLOR_BTNFACE + 1;
lpszMenuName := '';
end;
// Заполняем информацию об окне
with FWndParams do
begin
WndParent := FWndParent;
Caption := 'Lite Window';
Style := WS_OVERLAPPEDWINDOW or WS_VISIBLE;
ExStyle := 0;
X := Integer(CW_USEDEFAULT);
Y := Integer(CW_USEDEFAULT);
Width := Integer(CW_USEDEFAULT);
Height := Integer(CW_USEDEFAULT);
WndMenu := 0;
Param := nil;
end;
end;
////////////////////////////////////////////////////////////////////////////////
// TLiteWindow
// _____________________________________________________________________________
// Функции обработки сообщений
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Обработчик сообщений по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteWindow.DefaultHandler(var Msg);
begin
// Наш объект - объект субклассиннга ?
if FWndSubclass = nil then
// Вызываем системную функцию обработки сообщений
with TMessage(Msg) do
Result := DefWindowProc(FWndHandle, Msg, WParam, LParam)
else
// Вызываем старую оконную функцию обработки сообщений
with TMessage(Msg) do
Result := CallWindowProc(FWndSubclass, FWndHandle, Msg, WParam, LParam);
end;
Реализация диалогового класса TLiteDialog
////////////////////////////////////////////////////////////////////////////////
// TLiteDialog
// _____________________________________________________________________________
// Инициализация / финализация
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Конструктор
////////////////////////////////////////////////////////////////////////////////
constructor TLiteDialog.Create(AWndParent: THandle);
begin
inherited;
// Формируем параметры диалога
CreateDialogParams(FDlgParams);
// Создаем диалог
with FDlgParams do
CreateDialogParam(hInstance, Template, WndParent, WndCallback, 0);
end;
////////////////////////////////////////////////////////////////////////////////
// Деструктор
////////////////////////////////////////////////////////////////////////////////
destructor TLiteDialog.Destroy;
begin
// Уничтожаем диалог
if IsWindow(FWndHandle) then DestroyWindow(FWndHandle);
// Уничтожение по умолчанию
inherited;
end;
////////////////////////////////////////////////////////////////////////////////
// Формирование параметров диалога по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteDialog.CreateDialogParams(var DialogParams: TDialogParams);
begin
DialogParams.WndParent := FWndParent;
DialogParams.Template := '';
end;
////////////////////////////////////////////////////////////////////////////////
// Обработка сообщений по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteDialog.DefaultHandler(var Msg);
begin
// Возвращаемые значения по умолчанию
with TMessage(Msg) do
if Msg = WM_INITDIALOG then Result := 1
else Result := 0;
end;
Реализация модального диалогового класса TLiteDialogBox
////////////////////////////////////////////////////////////////////////////////
// TLiteDialogBox
// _____________________________________________________________________________
// Инициализация / финализация
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Формирование параметров диалога по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteDialogBox.CreateDialogParams(var DialogParams: TDialogParams);
begin
DialogParams.WndParent := FWndParent;
DialogParams.Template := '';
end;
////////////////////////////////////////////////////////////////////////////////
// Активизация модального диалога
////////////////////////////////////////////////////////////////////////////////
function TLiteDialogBox.ShowModal: Integer;
begin
// Формируем параметры диалога
CreateDialogParams(FDlgParams);
// Показываем диалог
with FDlgParams do
Result := DialogBoxParam(hInstance, Template, WndParent, WndCallback, 0);
end;
////////////////////////////////////////////////////////////////////////////////
// Обработка сообщений по умолчанию
////////////////////////////////////////////////////////////////////////////////
procedure TLiteDialogBox.DefaultHandler(var Msg);
begin
// Возвращаемые значения по умолчанию
with TMessage(Msg) do
if Msg = WM_INITDIALOG then Result := 1
else Result := 0;
end;
end.
В прилагаемом примере, построенном на основе разработанной автором библиотеки API-программирования
WinLite, рассматриваются следующие проблемы:
создание и показ окон;
создание и показ диалогов;
загрузка ресурсов;
работа с трэем;
активизация приложения по нажатию глобальной "горячей" клавиши;
"прилипание" окна к границам рабочей области экрана;
реализация графики OpenGL;
субклассинг стандартных элементов управления;
буферизация вывода в окно для устранения мерцания;
создание дополнительного потока и передача сообщений между потоками;
установка таймера.
|