");
// -->
Любую современную программу или программную технологию можно представить как
совокупность программных "слоев". Каждый из этих слоев производит свою собственную
работу, которая заключается в повышении уровня абстракции производимых операций.
Так, самый низший слой (слои) вводит понятия, которые позволяют абстрагироваться
от используемого оборудования; следующий слой (слои) позволяет программисту абстрагироваться
от сложной последовательности вызовов функций, вводя такое понятие как протокол
и т.д. Практически в любом современном программном продукте можно обнаружить и выделить
около десятка последовательных слоев абстракции.
Абстракция от оборудования и низкоуровневых протоколов вводится в ядра операционных
систем в виде библиотек API (Application Program Interface). Однако современные
тенденции приводят к необходимости абстрагирования и от самих операционных систем,
что позволяет переносить программы с одной операционной системы на другую путем
простой перекомпиляции (транслируемые программы, в основном, вообще не требуют никаких
действий по переносу).
Абстракцию, которая доступна программисту в виде библиотек API можно назвать
базовой. Это самый низкий уровень абстракции, который доступен для прикладного
программирования. На уровне ядра системы доступны и более низкие уровни абстракции,
однако для их использования необходимо разрабатывать специализированные программы
(драйвера, модули). Базовый уровень абстракции (API) предоставляет максимально широкие
возможности для прикладного программирования и является наиболее гибким. Однако,
программирование с использованием API является гораздо более трудоемким и приводит
к значительно большим объемам исходного кода программы, чем программирование с использованием
дополнительных библиотек.
Дополнительные библиотеки поставляются со многими средствами разработки с целью
уменьшения трудоемкости и сроков разработки программ, что в итоге приводит к повышению
их конкурентноспособности. Но применение дополнительных библиотек абстракций приводит
к резкому увеличению размеров откомпилированных программ, из-за того что в программу
включается код используемых библиотек, к тому же это включение зачастую бывает неэффективным
- в программу включаются неиспользуемые участки кода. Кроме того, чем больше уровень
абстракции библиотеки, тем сложнее ее код, и тем больше трудностей возникает при
решении сложных задач. Приходится учитывать множество взаимосвязей и взаимных влияний
отдельных элементов и процессов библиотеки друг на друга. Кроме того, структура
и функциональность любой библиотеки обычно рассчитывается на удовлетворение всех
потенциально возникающих задач, что приводит к ее громоздкости и неэффективности.
В Delphi используется очень мощная и сложная библиотека VCL (Visual Components
Library), которая помимо непосредственных абстракций вводит также и множество своих
функциональных классов. В этой библиотеке находятся компоненты для визуального отображения
информации, работы с базами данных, с системными объектами, компоненты для работы
с Internet-протоколами, классы для написания своих COM-объектов и многое другое.
Модули библиотеки подключаются к компиляции по мере необходимости, однако базовый
размер простейшего диалогового проекта с одной формой превышает 300кБ (со статически
скомпонованной библиотекой). И такой размер во многих случаях может оказаться слишком
большим, особенно если программа не требует большой функциональности в интерфейсе.
Для решения этой проблемы можно отказаться от использования библиотеки VCL, и
программировать, используя базовый набор функций Win32 API. Однако, если при разработке
линейных, недиалоговых, нерезидентных программ не возникает никаких трудностей,
то разработка программ, требующих активного взаимодействия с пользователем или системой,
становится трудоемкой. Структурное программирование, рекомендуемое в таких случаях,
оказывается неэффективным и трудоемким.
Данная статья посвящена проблеме создания и использования компактной объектно-ориентированной
библиотеки, которая бы облегчила построение небольших и эффективных программ на
основе Win32 API.
2. Существующие решения
Автору известны три объектно-ориентированные библиотеки, которые можно рассматривать
как альтернативу библиотеке 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.
3. Принципы построения 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
4. Библиотека WinLite
////////////////////////////////////////////////////////////////////////////////
// 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.
5. Пример программы на основе библиотеки WinLite
В прилагаемом примере, построенном на основе разработанной автором библиотеки
API-программирования WinLite, рассматриваются следующие проблемы:
- создание и показ окон;
- создание и показ диалогов;
- загрузка ресурсов;
- работа с трэем;
- активизация приложения по нажатию глобальной "горячей" клавиши;
- "прилипание" окна к границам рабочей области экрана;
- реализация графики OpenGL;
- субклассинг стандартных элементов управления;
- буферизация вывода в окно для устранения мерцания;
- создание дополнительного потока и передача сообщений между потоками;
- установка таймера.
Источник http://www.codenet.ru
|