• Программирование на основе Win32 API в Delphi
  • 1. Введение
  • 2. Существующие решения
  • 3. Принципы построения API-библиотеки
  • 4. Библиотека WinLite
  • 5. Пример программы на основе библиотеки WinLite
  • KOL
  • Состояние проекта KOL
  • API

    Программирование на основе Win32 API в Delphi

    1. Введение

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

    Абстракция от оборудования и низкоуровневых протоколов вводится в ядра операционных систем в виде библиотек 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;

    • субклассинг стандартных элементов управления;

    • буферизация вывода в окно для устранения мерцания;

    • создание дополнительного потока и передача сообщений между потоками;

    • установка таймера.

    KOL

    KOL — Key Objects Library – это библиотека объектов для программирования в среде Delphi. Предоставляется бесплатно, с исходными текстами.

    Поддерживаются версии Delph3, Delphi4, Delphi5. Библиотека KOL позволяет разрабатывать чрезвычайно компактные GUI-приложения (от 13,5К без сжатия — при условии использования предлагаемой замены системных модулей system, sysinit). Большая часть кода переведана на ассемблер.

    К библиотеке прилагается программа — генератор справки (xHelpGen), формирующая подробную документацию по библиотеке в html-формате. Справка формируется на основе комментариев в исходных текстах, так что разработчики всегда имеют доступ к самой свежей и полной документации.

    До сих пор программирование для KOL было полностью невизуальным, но с открытием проекта MCK (Mirror Classes Kit — набор зеркальных классов) появилась надежда на то, что очень скоро все прелести визуального программирования будут в полной мере доступны и для разработчиков, использующих KOL.

    Состояние проекта KOL

    • Базовый объект TObj функционально заменяет собой класс TObject из VCL. Он имеет похожий метод Free, который позволяет уничтожать объекты безопасно (игнорируя вызов для указателя nil), а так же пару методов RefInc и RefDec, позволяющих предотвратить удаление объекта из памяти между двумя соответствующими вызовами RefInc и RefDec.

     ◦ Очень полезный объект TList ("конструктор": NewList:PList). Подобно TList в VCL, позволяет хранить указатели на любые данные (или числа).

     ◦ TStrList. Конструктор: NewStrList: pstrlist — очень быстрый список строк (позволяет обрабатывать миллионы строк в секунду).

     ◦ Невизуальный объектный тип TTree для организации дерево-подобных структур данных в памяти.

     ◦ Объектный тип TGraphicTool реализует в себе GDI иснструменты — кисточку (NewBrush), шрифт (NewFont) и карандаш (NewPen), без введения трех различных потомков. Бóльшая часть кода включается в конечную программу только в случае, если в проекте имеются обращения к свойствам Font, Brush объектов TControl, или объекты типа TGraphicTool создаются явным образом.

     ◦ Объект TCanvas, очень похожий на TCanvas из VCL (но более компактный и эффективный). Для рисования на существующем DC, имеется конструктор: NewCanvas(DC): PCanvas

     ◦ TBitmap, также напоминает TBitmap из VCL. Конструкторы:

      ▪ NewBitmap(Width, Height): PBitmap.

      ▪ NewDIBBitmap(Width, Height, PixelFormat): PBitmap

     ◦ Объект TImageList (подобно аналогичному в VCL). Конструктор: NewImageList(AOwner: PControl): PImageList.

     ◦ Главный объект библиотеки KOL — это TControl. Он может выполнять роль любого визуального контрола взависимости от того, какой "конструктор" использован для его создания. Имеются следующие "конструкторы", точнее, глобальные функции конструирования (синтаксис намеренно видоизменен):

      ▪ NewApplet(Caption: String): PControl (примечание: в KOL необязателен. В случае единственной формы, для которой не требуется прятать кнопку приложения на панели задач, достаточно создать форму) .

      ▪ NewForm(AParent: PControl): PControl

      ▪ NewPanel(AParent; EdgeStyle:{ esRaised, esLowered, esNone }): PControl

      ▪ NewSplitter(AParent; MinSize1, MinSize2: Integer): PControl

      ▪ NewGroup(AParent; Caption): PControl

      ▪ NewLabel(AParent; Caption): PControl

      ▪ NewWordWrapLabel(AParent; Caption): PControl

      ▪ NewLabelEffect(AParent; Caption; ShadowDeep): PControl

      ▪ NewButton(AParent; Caption): PControl

      ▪ NewBitBtn(aParent, aCaption, aOptions: [ bboImageList, bboNoBorder, bboNoCaption, bboFixed ] , aLayout: { glyphLeft, glyphTop, glyphRight, glyphBottom, glyphOver } , GlyphBmp _or_ ImageList, GlyphCount __or__ ImgIdx _and_ GlyphCount _shl16): PControl

      ▪ NewCheckbox(AParent; Caption): PControl

      ▪ NewRadiobox(AParent; Caption): PControl

      ▪ NewEditbox(AParent; Options: Set of [ eoNoHScroll, eoNoVScroll, eoLowercase, eoMultiline , eoNoHideSel, eoOemConvert, eoPassword, eoReadonly, eoUpperCase, eoWantReturn, eoWantTab ]): PControl

      ▪ NewRichEdit(AParent, Options): PControl

      ▪ NewRichEdit1(AParent, Options): PControl

      ▪ NewListbox(AParent; Options: Set of [ loNoHideScroll, loNoExtendSel, loMultiColumn, loMultiSelect, loNoIntegralHeight, loNoSel, loSort, loTabstops ]): PControl

      ▪ NewCombobox(AParent; Options: Set of [ coReadOnly , coNoHScroll, coAlwaysVScroll, coLowerCase, coNoIntegralHeight, coOemConvert, coSort, coUpperCase ]): PControl

      ▪ NewPaintbox(AParent)

      ▪ NewGradientPanel(AParent; Color1, Color2): PControl

      ▪ NewGradientPanelEx(Color1, Color2, Style: ( gsHorizontal, gsVertical, gsRectangle, gsElliptic, gsRombic ), Layout: ( glTopLeft, glTop, glTopRight, glLeft, glCenter, glRight, glBottomLeft, glBottom, glBottomRight )): PControl

      ▪ NewProgressbar(AParent): PControl

      ▪ NewProgressbarEx(AParent; Options: set of [ pboVertical, pboSmooth ]): PControl

      ▪ NewListView(AParent, Style:{ lvsIcon, lvsSmallIcon, lsvList, lvsDetail, lvsDetailNoHeader}, Options: set of [ lvoIconLeft, lvoAutoArrange, lvoButton, lvoEditLabel, lvoNoLabelWrap, lvoNoScroll, lvoNoSortHeader, lvoHideSel, lvoMultiselect, lvoSortAscending,lvoSortDescending, lvoGridLines, lvoSubItemImages, lvoCheckBoxes, lvoTrackSelect, lvoHeaderDragDrop, lvoRowSelect, lvoOneClickActivate, lvoTwoClickActivate, lvoFlatsb, lvoRegional, lvoInfoTip, lvoUnderlineHot, lvoMultiWorkares ]; ImageListSmall, ImageListBig, ImageListState: PImageList): PControl

      ▪ NewTreeView(parent, options: set of [ tvoNoLines, tvoLinesRoot, tvoNoButtons, tvoEditLabels, tvoHideSel, tvoDragDrop, tvoNoTooltips, tvoCheckBoxes, tvoTrackSelect, tvoSingleExpand, tvoInfoTip, tvoFullRowSelect, tvoNoScroll, tvoNonEvenHeight ], ImgListNormal, ImgListState): PControl

      ▪ NewToolbar(parent, align: { c aLeft, caTop, caRight, caBottom }, options: set of [ tboTextRight, tboFlat, tboTransparent, tboWrapable ], Bitmap, Buttons: array of PChar; BtnImgIdxArray: array of Integer): PControl

      ▪ NewTabControl(parent, tabs: array of string, options: set of [ tcoButtons, tcoFixedWidth, tcoFocusTabs, tcoIconLeft, tcoLabelLeft, tcoMultiline, tcoMultiselect, tcoFitRows, tcoScrollOpposite, tcoBottom, tcoVertical, tcoFlat, tcoHotTrack ], ImgList, ImgIdx1st): PControl

     ◦ Динамически создаваемое меню — объект TMenu (главное меню или контекстное). Конструкторы:

      ▪ NewMenu(AParent; FirstCmd:Integer; Template: array of PChar; aOnItem: procedure( Sender; Item: integer) of object): PMenu

      ▪ NewMenuEx(AParent; FirstCmd:Integer; Template: array of PChar; aOnItems: array of procedure(Sender; Item: integer) of object): PMenu

     ◦ Невизуальный объект TIniFile. Конструктор: OpenIniFile(filename): PIniFile;

     ◦ Невизуальный объект TTimer. Конструктор: NewTimer(interval): PTimer

     ◦ Невизуальный объект TDirList. Конструкторы:

      ▪ NewDirList(path; 'filemask'; Attr): PDirList

      ▪ NewDirListEx(path; '[^]filemask1[;[^]filemask2]…'; Attr): PDirList

     ◦ Объект TOpenSaveDialog для вызова стандартного диалога выбора файлов на открытие/сохранение. Конструктор: NewOpenSaveDialog(title, strtdir: string; Options: [ OSCreatePrompt, OSExtensionDiffent, OSFileMustExist, OSHideReadonly, osnochangedir, osnoreferencelinks, osallowmultiselect, OSNoNetworkButton, OSNoReadonlyReturn, OSOverwritePrompt, OSPathMustExist, osreadonly ]): POpenSaveDialog

     ◦ Объект TOpenDirDialog для вызова стандартного диалога выбора директории (использует SHBrowseForFolder). Конструктор: NewOpenDirDialog(title, options: [ odfBrowseForComputer, odfBrowseForPrinter, odfDontGoBelowDomain, odfOnlyFileSystemAncestors, odfOnlySystemDirs ]): POpenDirDialog

    (Примечание: возможна установка начальной директории и OnSelChanged события).

     ◦ Объект TColorDialog для вызова стандартного диалога выбора цвета: NewColorDialog(FullOpenOption): PColorDialog

     ◦ Потоковые объекты типа TStream:

      ▪ NewMemoryStream: PStream

      ▪ NewReadFileStream(filename): PStream

      ▪ NewWriteFileStream(filename): PStream

      ▪ NewReadWriteFileStream(filename): PStream

     ◦ Невизуальный TImageList. Конструктор: NewImageList(aowner: pcontrol): pimagelist

     ◦ Невизуальный TTimer. Конструктор: NewTimer(interval): ptimer

     ◦ Невизуальный TThread. Конструкторы:

      ▪ NewThread: PThread

      ▪ NewThreadEx(Proc: TOnThreadExecute): PThread

     ◦ Невизуальный объект для мониторинга изменений в папках TDirChange:

      ▪ NewDirChangeNotifier(Path; Filter: set of [ fncFileName, fncDirName, fncAttributes, fncSize,

    fncLastWrite, fncLastAccess, fncCreation, fncSecurity ]; WatchSubtree; ChangeProc: TOnDirChange): PDirChange

     ◦ Невизуальный TMediaPlayer. NewMediaPlayer(filename, window): PMediaPlayer

    (Имеется ряд дополнительных функций для проигрывания звуковых wave-файлов из памяти, потока, файла или ресурса и контроля wave-выводом).

     ◦ Невизуальный (?) объект TTrayIcon. Конструктор: NewTrayIcon(Wnd:PControl; Icon: HIcon): PTrayIcon

    (Теперь с дополнительным свойством AutoRecreate, позволяющим возобновить иконки в трее в случае рестарта эксплорера).

     ◦ Функции JustOne(Wnd:PControl; Id:String): Boolean и JustOneNotify(Wnd; Id; OnAnotherInstance: procedure(cmdline: string) of object)

     ◦ Процедура SortData для быстрой сортировки любых массивов.

     ◦ Множество процедур и функций для работы с окнами, файлами, датой/временем, строками и преобразованиями форматов.

     ◦ Кроме того, реализованы дополнительно (здесь приведено даже близко далеко не все то, чем KOL мог бы гордиться):

      ▪ Поддержка табуляции с помощью клавиатуры — упрощенная (вызвать Tabulate для формы) и более сложная (вызвать TabulateEx).

      ▪ Набор свойств, упрощающих настройку границы формы (окна): HasCaption, HasBorder, CanResize, StayOnTop .

      ▪ Набор "сквозных" методов, упрощающих невизуальное проектирование формы: PlaceRight, PlaceDown, PlaceUnder, SetSize(w,h), Size(w, h), AlignLeft(fromcontrol), AlignTop (fromcontrol), ResizeParent, ResizeParentRight, ResizeParentBottom, CenterOnParent, Shift(x,y), SetAlign(куда) а так же свойство Margin.

      ▪ Поддержка вращающихся шрифтов — в LabelEffect, в TCanvas. Автоматически — по изменению свойства Font.Orientation

      ▪ Поддержка геометрического карандаша (pen) в TGraphicTool. А также свойство FontWeight для желаемого утолщения шрифтов средствами ОС.

      ▪ Поддержка двойной буферизации вывода (необходима в LabelEffect). Необходима установка для визуального объекта свойства DoubleBuffered в True (наследуется дочерними контролами)

      ▪ СвойствоTransparent (прозрачность, неявно использует DoubleBuffered).

      ▪ Свойство AlphaBlend позволяет сделать форму/контрол полупрозрачными (только Win2K).

      ▪ Свойство Align, позволяющее выравнивать контролы так же, как и в VCL. имеется дополнительный "сквозной" метод SetAlign, упрощающий начальную настройку контролов.

      ▪ Метод PreventResizeFlicks позволяет ликвидировать большинство мельканий изображения при изменении размеров формы и перемещении сплиттера — в случае применения выравнивания с помощью свойства Align . Особенно эффективно совместно с DoubleBuffered = True.

      ▪ Окно статуса (status bar), встраиваемое в форму (при использовании свойств StatusText[], SimpleStatusText, и т.п.).

      ▪ События OnMouseOver / OnMouseLeave.

      ▪ Возможность любых внешних расширений оконных процедур имеющихся контролов с помощью метода AttachProc (собственно, на нем построен весь K.O.L.)

     ◦ Добавлен набор зеркальных классов MCK (Mirror Classes Kit), который позволяет перейти к визуальному программированию с использованием библиотеки KOL.







     


    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх