Win API
Минимальная программа на Win API

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Данная статья начинает серию статей, посвященных программированию в Delphi на Win API. API (Application Program Interface) - это набор функций, которые находятся в стандартных библиотеках (DLL), располагающихся в системном каталоге Windows. Операционная система предоставляет эти функции для использования каждой программе.

Что дает нам использование API функций? В первую очередь минимальные размеры получившегося приложения. Это может оказаться важным при написании таких программ как инсталляторы, при создании пачтей или при работе с графикой. Программы маленьких размеров удобно распространять через интернет. Также стоит отметить, что программы, написанные на Win API, работают быстрее, чем их "собратья", написанные с использованием классов объектно-ориентированных языков.

Первое знакомство с Win API начнем с того, что создадим окно. Просто пустое окно, которое в дальнейшем будет служить нам шаблоном. Постепенно наращивая этот шаблон, мы будем создавать более сложные приложения.

Итак, приступим. Запускаем Delphi и создаем новый проект. Нам необходимо убрать из проекта форму, для этого делаем следующее. В меню Project выбираем Remove from Project..., в появившемся окне выделяем строку Unit1 и нажимаем кнопку OK. Delphi попросит подтвердить, хотим ли мы удалить Unit1 из проекта, ответьте утвердительно. Теперь необходимо открыть файл проекта. Снова лезем в меню Project и выбираем View Source. Последний шаг, нужно удалить несколько лишних строк. Приведите файл проекта к следующему виду.

program Project1;

begin

end.

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

program Project1;

uses
  Windows, Messages;

begin

end.

Для начала нам хватит этих двух модулей. А мы продолжаем, и переходим к объявлению переменных. Когда в Windows создаётся некоторый объект, ему присваивается уникальный 32-разрядный номер, который называется дескриптором. В дальнейшем при работе с этим объектом каждой функции передаётся этот дескриптор, поэтому нам необходимо его сохранить. Для этого нам понадобится переменная типа HWND. Также потребуется переменная типа TWndClassEx, ее мы используем для того, чтобы описать создаваемый нами объект. И еще одна переменная типа TMsg будет использоваться для обработки сообщений. Наш проект принимает следующий вид.

program Project1;

uses
  Windows, Messages;

var
  Wc: TWndClassEx;
  Wnd: HWND;
  Msg: TMsg;

begin

end.

Теперь опишем оконную процедуру.

function WindowProc( Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM ): LRESULT; stdcall;
begin
   case Msg of
      WM_DESTROY: begin
         PostQuitMessage( 0 );
         Result := 0;
         Exit;
      end;
      else
         Result := DefWindowProc( Wnd, Msg, wParam, lParam );
   end;
end;

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

Небольшое отступление. Действие процедуры PostQuitMessage аналогично сообщению WM_QUIT, и описанную выше процедуру можно было бы написать следующим образом.

function WindowProc( Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM ): LRESULT; stdcall;
begin
   case Msg of
      WM_DESTROY: begin
         PostMessage( Wnd, WM_QUIT, 0, 0 );
         Result := 0;
         Exit;
      end;
      else
         Result := DefWindowProc( Wnd, Msg, wParam, lParam );
   end;
end;

Подготовка окончена, и теперь нам пора создавать окно. Последовательность действий будет такая: описать класс создаваемого объекта, зарегистрировать этот класс в системе, создать и показать окно. Приступаем.

...

const
  WndClass = 'TWinApiWnd';
  WndCaption = 'Минимальная программа на Win API';

...

begin
   with Wc do
   begin
      cbSize := SizeOf( Wc );
      style := CS_HREDRAW or CS_VREDRAW;
      lpfnWndProc := @WindowProc;
      cbClsExtra := 0;
      cbWndExtra := 0;
      hInstance := hInstance;
      hIcon := LoadIcon( 0, IDI_APPLICATION );
      hCursor := LoadCursor( 0, IDC_ARROW );
      hbrBackground := COLOR_WINDOW;
      lpszMenuName := nil;
      lpszClassName := WndClass;
   end;
   RegisterClassEx( Wc );

   Wnd := CreateWindowEx( 0, WndClass, WndCaption, WS_OVERLAPPEDWINDOW,
                          10, 10, 300, 100, 0, 0, hInstance, nil );

   ShowWindow( Wnd, SW_SHOWNORMAL );

   while GetMessage( Msg, 0, 0, 0 ) do
   begin
      TranslateMessage( Msg );
      DispatchMessage( Msg );
   end;
   Halt( Msg.wParam );
end.

Теперь я дам краткое описание происходящего. Начнем с описания класс объекта. Флаги CS_HREDRAW и CS_VREDRAW говорят о том, что окно должно перерисовываться при изменении вертикального или горизонтального размера. lpfnWndProc присваиваем адрес созданной нами оконной процедуры. hInstance содержит описатель экземпляра приложения (адрес начала образа exe файла в адресном пространстве). С иконкой, курсором и цветом все понятно. lpszMenuName - указатель на главное меню, которого пока нет. И последнее, lpszClassName - имя класса создаваемого объекта.

Забегая немного вперед, обращаю ваше внимание на то, что второй параметр функции CreateWindowEx имеет тоже значение, что и поле lpszClassName описываемого объекта. Они должны быть одинаковыми, поэтому я использую константу, созданную ранее. Это не обязательно, просто мне так удобнее.

Используя RegisterClassEx регистрируем описанный класс в системе. Создаем окно. Первый параметр CreateWindowEx - расширенный стиль окна. Далее идут имя класса и заголовок окна. Затем описывается стиль окна. Если посмотреть описание флага WS_OVERLAPPEDWINDOW (оно приведено ниже), мы увидим, что это комбинация нескольких флагов. Другими словами, мы сами можем определять стиль окна, используя различные комбинации, например WS_OVERLAPPED or WS_SYSMENU or WS_MINIMIZEBOX. Советую вам поэкспериментировать с этим параметром. Следующие 4 параметра отвечают за позицию и размер окна. Затем идет дескриптор окна родителя, его у нас нет, так что ставим 0. Меню у нас пока тоже нет, так что дальше тоже ставим 0. Далее идут указатель на начало данных и указатель на структуру CREATESTRUCT. Создав окно, воспользуемся процедурой ShowWindow, чтобы его показать.

{$EXTERNALSYM WS_OVERLAPPEDWINDOW}
  WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or
    WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX);

Заканчивается все циклом обработки сообщений. Функция TranslateMessage транслирует сообщения виртуальных клавиш в символьные сообщения. Функция DispatchMessage посылает сообщения оконной процедуре. Цикл обработки сообщений может меняться в зависимости от ситуации, но эти 2 процедуры присутствуют всегда.

Наша минимальная программа готова. В следующий раз мы усовершенствуем ее, добавим меню и элементы управления, а пока это все. До скорой встречи и удачи в программировании.

.: Пример к данной статье :.


При использовании материала - ссылка на сайт обязательна