Содержание материала

Введение

 

Любую современную программу или программную технологию можно представить как совокупность программных "слоев". Каждый из этих слоев производит свою собственную работу, которая заключается в повышении уровня абстракции производимых операций. Так, самый низший слой (слои) вводит понятия, которые позволяют абстрагироваться от используемого оборудования; следующий слой (слои) позволяет программисту абстрагироваться от сложной последовательности вызовов функций, вводя такое понятие как протокол и т.д. Практически в любом современном программном продукте можно обнаружить и выделить около десятка последовательных слоев абстракции.

 

Абстракция от оборудования и низкоуровневых протоколов вводится в ядра операционных систем в виде библиотек API (Application Program Interface). Однако современные тенденции приводят к необходимости абстрагирования и от самих операционных систем, что позволяет переносить программы с одной операционной системы на другую путем простой перекомпиляции (транслируемые программы, в основном, вообще не требуют никаких действий по переносу).

 

Абстракцию, которая доступна программисту в виде библиотек API можно назвать базовой. Это самый низкий уровень абстракции, который доступен для прикладного программирования. На уровне ядра системы доступны и более низкие уровни абстракции, однако для их использования необходимо разрабатывать специализированные программы (драйвера, модули). Базовый уровень абстракции (API) предоставляет максимально широкие возможности для прикладного программирования и является наиболее гибким. Однако, программирование с использованием API является гораздо более трудоемким и приводит к значительно большим объемам исходного кода программы, чем программирование с использованием дополнительных библиотек.

 

Дополнительные библиотеки поставляются со многими средствами разработки с целью уменьшения трудоемкости и сроков разработки программ, что в итоге приводит к повышению их конкурентноспособности. Но применение дополнительных библиотек абстракций приводит к резкому увеличению размеров откомпилированных программ, из-за того что в программу включается код используемых библиотек, к тому же это включение зачастую бывает неэффективным - в программу включаются неиспользуемые участки кода. Кроме того, чем больше уровень абстракции библиотеки, тем сложнее ее код, и тем больше трудностей возникает при решении сложных задач. Приходится учитывать множество взаимосвязей и взаимных влияний отдельных элементов и процессов библиотеки друг на друга. Кроме того, структура и функциональность любой библиотеки обычно рассчитывается на удовлетворение всех потенциально возникающих задач, что приводит к ее громоздкости и неэффективности.

 

В Delphi используется очень мощная и сложная библиотека VCL (Visual Components Library), которая помимо непосредственных абстракций вводит также и множество своих функциональных классов. В этой библиотеке находятся компоненты для визуального отображения информации, работы с базами данных, с системными объектами, компоненты для работы с Internet-протоколами, классы для написания своих COM-объектов и многое другое. Модули библиотеки подключаются к компиляции по мере необходимости, однако базовый размер простейшего диалогового проекта с одной формой превышает 300кБ (со статически скомпонованной библиотекой). И такой размер во многих случаях может оказаться слишком большим, особенно если программа не требует большой функциональности в интерфейсе.

 

Для решения этой проблемы можно отказаться от использования библиотеки VCL, и программировать, используя базовый набор функций Win32 API. Однако, если при разработке линейных, недиалоговых, нерезидентных программ не возникает никаких трудностей, то разработка программ, требующих активного взаимодействия с пользователем или системой, становится трудоемкой. Структурное программирование, рекомендуемое в таких случаях, оказывается неэффективным и трудоемким.

 

Данная статья посвящена проблеме создания и использования компактной объектно-ориентированной библиотеки, которая бы облегчила построение небольших и эффективных программ на основе Win32 API.

 


Автору известны две объектно-ориентированные библиотеки, которые можно рассматривать как альтернативу библиотеке VCL при написании компактных программ. Это библиотеки классов XCL и ACL. Обе библиотеки бесплатны и поставляются в исходных кодах.

 

Библиотека ACL        (API control library)        

Автор:        Александр Боковиков, Екатеринбург, Россия        

Классы:        TFont, TFonts, TControl, TWinControl, TStdControl, TLabel, TEdit, TListBox, TButton, TCheckBox, TComboBox, TGroupBox, TProgressBar, TKeyboard        

 

Библиотека XCL        (Extreme class library)        

Автор:        Vladimir Kladov (Mr.Bonanzas)        

   

Классы:        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.pas, XDateUtils.pas, XFileUtils.pas, XWindowUtils, XPrintUtils, XShellLinks.pas, XJustOne.pas, XJustOneNotify.pas, XPascalUnit.pas, XSysIcons.pas, XCanvasObjectsManager, XRotateFonts, XFocusPainter, XFormsStdMouseEvents, XFormsStdKeyEvents, XFormAutoSizer, XAligner, XControlAutoPlacer, XMfcAntiFlicker, XSplitSizer, XResizeAntiFlicker, XCaretShower, XEditMouseSelect, XEditClipboard, XEditUndo, XListMouseSel, XListKeySel, XListEdit, ZNamedTags, XBtnRepeats, XBufLabels, XBackgrounds, XWndDynHandlers        

Как видно из списка приведенных для каждой библиотеки классов, эти библиотеки предендуют скорее не на помощь при написании программ с использованием Win32 API, а пытаются создать более высокий уровень абстракции чем API, по крайней мере в графической части (особенно это относится к XCL). Более того, иерархия и перечень объектов совпадают с соответствующими структурами в библиотеке VCL, что скорее всего связано с желанием авторов обеспечить логическую совместимость с VCL при построении программ на основе этих библиотек.

Данные библиотеки не обеспечивают минимального размера программы, за счет того что предоставляют более высокий уровень абстракции. Они являются компромисом между программированием с использованием VCL и программированием на чистом API.

Можно выделить несколько недостатков присущих даже не столько указанным библиотекам, а сколько решениям и принципам на которых они основаны.

· Несмотря на сравнительно малый размер получаемых программ, размер программ написанных с использованием только Win32 API был бы меньше.
· Помимо изучения Win32 необходимо изучение структуры классов, предлагаемых в этих библиотеках.
· Библиотека XCL не поддерживает механизм message-процедур.
· Архитектура этих библиотек, по мнению автора, является весьма громоздкой. Структуры и классы данных библиотек аналогичны структурам VCL, что приводит к неэффективности программ (ведь мы стараемся написать компактную программу, не так ли ?).
· Использование библиотеки ACL невозможно совместно с библиотекой VCL.
· Запутанность и большой размер классов наряду с "самодокументированным" кодом (то есть отсутствием файлов помощи) затрудняют изучение библиотек.
· Библиотеки разрабатываются и поставляются в частном порядке на некоммерческой основе, поэтому при разработке большого проекта на основе этих библиотек существует потенциальный риск отказа от поддержки. При этом вся тяжесть по устранению ошибок и развитию кода библиотеки ляжет на вас (если вы не вращаетесь в Delphi-сообществе).

 


Стандартным видом 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. Корректное освобождение занятых ресурсов крайне необходимо !

К тому же, прежде чем вы решите работать над своим проектом в русле Win32 API, подумайте, а зачем вам это нужно? В подавляющем числе случаев размер программы не имеет никакого значения. Я не хочу сказать, что API-программирование сложнее чем VCL-программирование. Во многих случаях легче изучить и написать 10 вызовов API с кучей аргументов и понимать, что происходит, чем написать 1 вызов простой, на первый взгляд, VCL-инструкции и потом долго исследовать дебри VCL в поисках ответа. Просто API-программирование - это другая культура, к которой вы, возможно, не привыкли. И первоначальная работа может вызвать у вас сильное разочарование. API-программирование требует дотошности, кропотливости и внимательного изучения документации.

Те же, кто отважился программировать на API, наряду с библиотекой WinLite могут совместно использовать невизуальные классы как из состава VCL (модули SysUtils, Classes), так и многие сторонние - естественно, что размер вашей программы при этом увеличится.

 
 
 
 

Для редактирования шаблонов диалогов можно использовать любой редактор ресурсов, например Borland Resource WorkShop, правда он несколько неудобен, а окончательный


 

 

Code:

//         WinLite, библиотека классов и функций для работы с Win32 API

//                       (c) Николай Мазуркин,

// _____________________________________________________________________________

//                                Оконные классы

////////////////////////////////////////////////////////////////////////////////

 

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.

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить