Создание программ на чистом WIN32API в DELPHI.
Если вы поклонник Delphi и задача понижения абстракции программирования до уровня системного API стала перед вами впервые, то данная статья поможет сделать первый уверенный шаг в постижении тонкостей этого ремесла. Содержательный пример поможет быстро подойти к сути вопроса. А справочная информация, публикуемая в статье, неизменно пригодиться в будущем.

Одной из наиболее интересных особенностей Delphi является предоставление, наряду с высокоуровневыми функциями VCL, простого доступа к функциям Windows API. Программист в любой момент волен (в зависимости от стоящей перед ним задачи) выбрать для ее решения простые в использовании компоненты либо реализовать алгоритм, требующий компактности и быстродействия при помощи прямых вызовов API. Более того, как правило, можно без прекращения использования компонентов и визуального программирования добавить несколько штрихов при помощи API и добиться предельной точности решения задачи и максимального быстродействия.

Само название операционной системы Windows говорит о том, что основным ее элементом является окно. Для успешного программирования разработчик должен иметь четкое представление о том, что подразумевается в Windows под этим понятием.

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

Поведение и внешний вид окна определяются его классом. Класс - это внутренняя структура Windows, описывающая шаблон, на основании которого операционная система создает окна.

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

Описание стилей основных элементов управления диалоговых окон приведены в таблицах:

Основные стили окон Windows.
WS_BORDERСоздание окна с рамкой.
WS_CAPTION Добавление заголовка к окну с рамкой.
WS_CHILDСоздание дочернего окна. Не используется с окнами стиля WS_POPUP.
WS_CHILDWINDOWСоздание дочернего окна стиля WS_CHILD.
WS_CLIPCHILDREN Используется при создании родительского окна; запрещает рисование родительского окна в области, занятой любым дочерним окном.
WS_CLIPSIBLINGS Используется только со стилем WS_CHILD. Окна данного стиля исключают области, занятые другими дочерними окнами, из клиентской области дочернего окна при получении данным окном сообщения о перерисовке. В противном случае можно было бы рисовать в клиентской области другого дочернего окна.
WS_DISABLEDСоздание изначально неактивного окна.
WS_DLGFRAME Создание окна с двойной рамкой без заголовка.
WS_EX_ACCEPTFILESУказывает, что создаваемое окно принимает файлы методом ""drag-and-drop".
WS_EX_DLGMODALFRAME Создание окна с двойной рамкой, в котором может находиться дополнительный заголовок. Этот стиль может использоваться только для значения dwEx- Style.
WS_EX_NOPARENTNOTIFY Указывает, что созданное дочернее окно не будет посылать родительскому окну сообщение WM_PARENTNOTIFY при создании или разрушении дочернего окна.
WS_EX_TOPMOSTУказывает, что созданное окно должно располагаться поверх всех окон, не имеющих такого стиля, и оставаться выше остальных даже в неактивном состоянии.
WS_EX_TRANSPARENTУказывает, что созданное окно должно быть про- зрачным. Все окна, расположенные под данным окном, не заслоняются им.
WS_GROUP Используется только в диалоговых окнах. Этот стиль окна указывается для первого элемента управления в группе элементов управления. Пользователь может перемещаться от одного элемента управле- ния к другому с помощью клавиш-стрелок.
WS_HSCROLLСоздание окна с горизонтальной полосой прокрутки.
WS_MAXIMIZEСоздание окна максимального размера.
WS_MAXIMIZEBOX Создание окна, которое имеет кнопку максимизации.
WS_MINIMIZEСоздание окна минимального размера.
WS_MINIMIZEBOX Создание окна, которое имеет кнопку минимизации.
WS_OVERLAPPEDСоздание перекрывающегося окна.
WS_OVERLAPPEDWINDOWДля создания перекрывающегося окна используются стили WS_OVERLAPPED, WS_THICKFRAME и WS_SYSMENU.
WS_POPUP Создание временного окна. Не используется с окнами стиля WS_CHILD.
WS_POPUPWINDOWДля создания временного окна используются стили WS_BORDER, WS_POPUP и WS_SYSMENU.
WS_SYSMENUСоздание окна, которое располагает кнопкой вызова системного меню. При использовании этого стиля для дочернего окна вместо стандартной кнопки вызова системного меню создается кнопка, позволяющая закрыть окно. Стиль WS_SYSMENU используется только для окон, имеющих заголовок.
WS_TABSTOPИспользуется только в диалоговых окнах. Указывает на произвольное количество элементов управления, между которыми пользователь может перемещаться с помощью клавиши ТаЬ. С помощью последовательных нажатий ТаЬ можно перемещаться между элементами управления со стилем WS_TABSTOP.
WS_THICKFRAMEСоздание окна с толстой рамкой. Рамка используется для изменения размеров окна.
WS_VISIBLEСоздание окна, видимого сразу после создания. Используется для перекрывающихся и временных окон.
WS_VSCROLLСоздание окна с вертикальной полосой прокрутки.

Дополнительные стили окон.
WS_EX_ACCEPTFILESУказывается, что создаваемое окно принимает файлы методом ""drag-and-drop".
WS_EX_DLGMODALFRAMEСоздается окно с двойной рамкой. Оно может также создаваться с заголовком, если в параметре dwStyle используется флаг стиля WS_CAPTION.
WS_EX_NOPARENTNOTIFYСоздается дочернее окно, при этом родительскому окну при создании или уничтожении дочернего окна не посылается сообщение WM_PARENTNOTIFY.
WS_EX_TOPMOSTСоздается окно, которое располагается поверх всех окон, не имеющих такого стиля. Оно будет оставаться выше остальных даже в неактивном состоянии. Для добавления и снятия этого атрибута может использоваться функция SetWindowPos().
WS_EX_TRANSPARENTСозданное окно будет прозрачным. Все окна, расположенные под данным окном, не заслоняются им. Сообщения WM_PAINT получаются окном после обновления остальных окон.
WS_EX_CLIENTEDGEКомпонент выглядит трехмерным

Стили органа управления Static.
SS_BLACKFRAMEОпределяет прямоугольник с черной рамкой.
SS_BLACKRECTОпределяет залитый черным цветом прямоугольник.
SS_CENTERВыравнивает заданный текст по центру заданного прямоугольника. Выполняется форматирование всего текста. Если текст не помещается на одну строку, то он автоматически переносится на следующую и выравнивается по центру.
SS_GRAYFRAMEОпределяет прямоугольник с серой рамкой.
SS_GRAYRECTОпределяет залитый серым цветом прямоугольник.
SS_ICOMАвтоматически масштабирует и выводит пиктограмму в диалоговом окне.
SS_LEFTДействует аналогично SS_CENTER, за исключением того, что текст выравнивается по левому краю. Автоматически выполняется перенос слов на следующую строку и выравнивание текста на следующей строке по левому краю.
SS_LEFTNOWORDWRAPОтключает обработку слов.
SS_NOPREFIXИзменяет обычную интерпретацию амперсанда (&). Как правило, Windows интерпретирует амперсанд в тексте элемента управления как символ-префикс горячей клавиши; он приводит к подчеркиванию следующего символа. Если не нужно чтобы статический элемент управления содержал подчеркнутый текст, то можно использовать стиль SSJMOPREFIX в комбинации (при помощи побитового логического ИЛИ) с другими стилями.
SS_RIGHTДействует аналогично SS_CENTER, за исключением того, что текст выравнивается по правому краю. Автоматически выполняется перенос слов на следующую строку и выравнивание текста на следующей строке по правому краю.
SS_SIMPLEОпределяет прямоугольник, в котором выводится одна строка выровненного по левому краю текста.
SS_USERITEMОпределяет заданный пользователем элемент.
SS_WHITEFRAME Определяет прямоугольник с белой рамкой.
SS_WHITERECTОпределяет залитый белым цветом прямоугольник.

Стили органа управления Scrollbar.
SBS_BOTTOMALIGNИспользуется совместно со стилем SBS_HORZС использованием принятой по умолчанию высоты полосы прокрутки SBSJ30TTOMALIGN выравнивает полосу прокрутки по нижнему краю прямоугольника, определенного х, у, nWidth и nHeight
SBS_HORZОпределяет горизонтальную полосу прокрутки. Высота, ширина и положение полосы прокрутки определяются функцией CreateWindowQ, если не заказан стиль SBSJ30TTOMALIGN или SBS_TOPLIGN.
SBS_LEFTALIGNИспользуется совместно со стилем SBS_VERT. С использованием принятой по умолчанию высоты полосы прокрутки SBSJ-EFTALIGN совмещает левый край полосы прокрутки с левым краем прямоугольника, определяемого х, у, nWidth и nHeight.
SBS_RIGHTALIGNИспользуется совместно со стилем SBS_VERT. С использованием принятой по умолчанию высоты полосы прокрутки SBSJ^IGHTALIGN совмещает правый край полосы прокрутки с правым краем прямоугольника, определяемого х, у, nWidth и nHeight.
SBS_SIZEBOXОпределяет блок изменения размера. Высота, ширина и положение определяются функцией CreateWindowQ, если не заказан стиль SBS_SIZEBOXBOTTOMRIGHTALIGN или SBS_SIZEBOXTOPLEFTALIGN.
SBS_SIZEBOXBOTTOMRIGHTALIGNИспользуется совместно со стилем SB_SIZEBOX, С использованием принятой по умолчанию высоты полосы прокрутки SBS_RIGHTALIGN выравнивает полосу прокрутки по правому нижнему краю прямоугольника, определяемого х, у, nWidth и nHeight.
SBS_SIZEBOXTOPLEFTALIGNИспользуется совместно со стилем SBS_SIZEBOX. С использованием принятой по умолчанию высоты полосы прокрутки SBS_SIZEBOXTOPLEFTALIGN выравнивает полосу прокрутки по левому верхнему краю прямоугольника, определяемого х, у, nWidth и nHeight.
SBS_TOPALIGNС использованием принятой по умолчанию высоты полосы прокрутки SBS_TOPAL1GN выравнивает полосу прокрутки по верхнему краю прямоугольника, определяемого х, у, nWidth и nHeight.
SBS_VERTОпределяет вертикальную полосу прокрутки. Высота, ширина и положение полосы прокрутки определяются функцией CreateWin-dow(), если не заказан стиль SBS_RIGHTALIGN или SBS_LEFTALIGN.

Стили органа управления Listbox.
LBS_DISABLENOSCROLLЕсли в списке не содержится достаточного количества элементов, то вывод вертикальной полосы прокрутки блокируется.
LBS_EXTENDEDSEL Допускается выбор нескольких элементов списка при помощи клавиши <Shift> и "мыши" или при помощи специальных клавиш.
LBS_HASSTRINGSСлужит для обслуживания памяти и указателей на строки, появляющиеся в нестандартном списке. Стиль LBS_HASSTRINGS позволяет приложению использовать сообщение LB_GETTEXT для получения конкретной строки.
LBS_MULTICOLUMNЗадает список из нескольких колонок, между которыми возможна горизонтальная прокрутка.
LBS_MUPLTIPLESELВ списке этого стиля допускается выбор произвольного количества строк, выбранная строка меняется всякий раз, когда пользователь делает обычный или двойной щелчок на строке.
LBS_NOINTEGRALHEIGHTПри создании списка его размер определяется равным размеру, который задан приложением.
LBS_NOREDRAWЕсли задан такой стиль, то при внесении изменений изображение элемента управления класса LISTBOX не изменится
LBS_NOTIFYЕсли пользователь сделает обычный или двойной щелчок на строке списка этого стиля, то родительское окно получит сообщение.
LBS_OWNERDRAWFIXEDЗа перерисовку содержимого списка этого стиля отвечает окно-владелец; все элементы списка имеют одинаковую высоту.
LBS_OWNERDRAWVARIABLEЗа перерисовку содержимого списка этого стиля отвечает окно-владелец; в отличие от стиля LBS_OWNERDRAWFIXED, элементы списка могут быть разной высоты.
LBS_SORTСтроки в элементе управления класса LISTBOX сортируются в алфавитном порядке.
LBS_STANDARDСтроки в элементе управления класса LISTBOX сортируются в алфавитном порядке, когда пользователь делает обычный или двойной щелчок на строке, родительскому окну посылается сообщение. Элемент управления класса LISTBOX обладает вертикальной полосой прокрутки и рамками.
LBS_USETABSTOPSСписку позволяется распознавать и отображать все символы табуляции при выводе строк. По умолчанию одной позиции табуляции соответствуют 32 единицы масштабирования. С помощью функции GetDialogBaseUnitsO приложение может получить величину текущей базовой единицы масштабирования в пикселах. Одна единица диалога по горизонтали равняется одной четвертой текущей базовой единицы масштабирования. Базовые единицы масштабирования вычисляются на основании высоты и ширины текущего системного шрифта.
LBS_WANTKEYBOARDINPUTЕсли пользователь нажимает клавишу и список этого стиля обладает фокусом ввода, то владелец списка получает сообщения WM_VKEYTOITEM и WM_CHARTOITEM.

Стили органа управления Edit.
ES_AUTOHSCROLLАвтоматически перемещает текст вправо на 10 символов, когда пользователь начинает вводить данные в конце строки ввода. При нажатии пользователем клавиши <Enter> текст автоматически выводится с начала строки.
ES_AUTOVSCROLLАвтоматически перемещает текст вниз на одну страницу, когда пользователь нажимает клавишу <Enter> на последней строке.
ES_CENTERСлужит для выравнивания текста по центру.
ES_LEFTСлужит для выравнивания текста по левому краю.
ES_OWERCASEПри вводе все символы преобразуются в нижний регистр.
ES_MULTILINEОбеспечивает элемент управления - многострочный редактор. При использовании со стилем ES_AUTOVSCROLL в ответ на нажатие клавиши <Enter> осуществляется вертикальная прокрутка текста. Если стиль ES_AUTOVSCROLL не был указан, то при нажатии клавиши <Enter> подается звуковой сигнал; дополнительные строки не выводятся. То же самое относится к использованию стиля ES_AUTOHSCROLL. Если указан этот стиль, то пользователь может не переходить на следующую строку, а сдвигать текст влево. При переходе элемента управления в неактивное состояние текст не остается на той же строке в окне, а создается новая строка. Элементы управления стиля ES_MULTILINE могут включать полосы прокрутки.
ES_NOHIDESELПерекрывает выполняемую по умолчанию операцию, запрещая прятать выделенный фрагмент, когда элемент управления теряет фокус ввода.
ES_OEMCONVERTТекст, вводимый в элементе управления класса EDIT, преобразуется из кодовой таблицы Windows в кодовую таблицу OEM и наоборот.
ES_PASSWORDКаждый введенный символ выводится как звездочка (*).
ES_READONLYПользователю не разрешается вводить или редактировать текст.
ES_UPPERCASE Все вводимые символы преобразуются в верхний регистр.
ES_RIGHTСлужит для выравнивания текста по правому краю
ES_WANTRETURNПри нажатии пользователем клавиши <Enter> вставляется символ возврата каретки.

Стили органа управления Combobox.
CBS_AUTOHSCROLLКогда пользователь вводит символ в конце строки, автоматически осуществляется прокрутка текста в элементе управления класса EDIT.
CBS_DISABLENOSCROLLЕсли в списке не содержится достаточное количество элементов, то вывод вертикальной полосы прокрутки блокируется.
CBS_DROPDOWNСписок не будет выводиться до тех пор, пока пользователь не выберет пиктограмму около поля ввода.
CBS_DROPDOWNLISTЗаменяет элемент управления класса EDIT статическим элементом текста, в котором выводится выбранная строка в списке.
CBS_HASSTRINGSПозволяет возвратить текст конкретного элемента с помощью GETTEXT.
CBS_NOINTEGRALHEIGHTУказывает, что высота текста несущественна.
CBS_OEMCONVERTУказывает на преобразование OEM.
CBS_OWNERDRAWFIXEDЗа перерисовку содержимого списка этого стиля отвечает окно-владелец; все элементы списка имеют одинаковую высоту.
CBS_OWNERDRAWVARIABLEЗа перерисовку содержимого списка этого стиля отвечает окно-владелец; в отличие от стиля LBS_OWNERDRAWFIXED, элементы списка могут быть разной высоты.
CBS_SIMPLEСписок выводится постоянно. Выбранный в данный момент элемент списка выводится в элементе управления EDIT.
CBS_SHORTПроизводится автоматическая сортировка строк списка при их вводе. Этот стиль не применим к нестандартным комбинированным спискам.

Стили органа управления Button.
BS_AUTOCHECKВОХСовпадает со стилем BS_CHECKBOX за исключением того, что при выборе кнопка автоматически меняет свое состояние.
BS_AUTORADIOBUTTONСовпадает со стилем BS_RADIOBUTTON за исключением того, что при нажатии кнопки приложению автоматически посылается сообщение BN_CLICKED, снимая отметку с любого другого переключателя в группе.
BS_AUTOSSTATE Совпадает со стилем BS_3STATE за исключением того, что при нажатии кнопка автоматически меняет свое состояние.
BS_CHECKBOXОпределяет маленькую прямоугольную кнопку, которую можно выбрать (переключатель). Если кнопка данного стиля выбрана, то она изображается жирно. Любой текст, связанный с кнопкой, выводится с правой стороны.
BS_DEFPUSHBUTTONОпределяет маленькую кнопку в форме эллипса с толстой рамкой. Обычно используется для указания принятого по умолчанию ответа пользователя. Связанный с кнопкой текст выводится непосредственно на кнопке.
BS_GROUPBOXОпределяет прямоугольную область, охватывающую группу кнопок. Текст выводится в левом верхнем углу прямоугольника.
BS_LEFTEXTПриводит к выводу текста с левой стороны переключателя. Может использоваться со стилем элемента управления BS_3STATE.
BS_OWNERDRAWОпределяет кнопку с нестандартным алгоритмом отри- совки. О нажатии кнопки уведомляется ее родительское окно. Данное уведомление включает вывод, инвертиро вание и запрет кнопки.
BS_PUSHBUTTONОпределяет маленькую кнопку в форме эллипса, содержащую указанный текст. При нажатии кнопки родительскому окну посылается соответствующее сообщение.
BS_RADIOBUTTONОпределяет маленькую круглую кнопку с рамкой. Если кнопка выбрана щелчком, то рамка становится жирной. Родительское окно также уведомляется о нажатии кнопки при помощи соответствующего сообщения. Следующий щелчок на кнопке приведет к отмене выбора и передаче родительскому окну другого сообщения, указывающего на изменение состояния кнопки.
BS_3STATEСоответствует BS_CHECKBOX, но кнопка может быть не только выбрана, но и сделана недоступной для нажатия. Выведенная серым цветом кнопка указывает, что переключатель в данный момент недоступен.
BS_USERBUTTON Определяет "кнопку пользователя". Родительское окно уведомляется о нажатии на кнопку.

Главная проблема, возникающая при написании Win32API приложений - это неудобство ручного создания всех окон приложения. Требуется вызывать функцию CreateWindow для каждого (в том числе и дочернего) окна программы, а затем еще и менять атрибуты (такие как шрифт, цвет и т.д.) в большинстве из них. Лучшим выходом из этой ситуации является использование ресурсов диалоговых окон (dialog box resources) для создания всех окон приложения.

Преимущество такого способа создания диалоговых окон заключается в том, что Windows берет на себя обеспечение интерфейса диалоговых окон, к которому привык пользователь - кнопки по умолчанию (срабатывающие, когда пользователь нажмет <Enter> или <Esc>); возможность переключения между дочерними элементами управления при помощи клавиши <Tab> и т.п.

Для создания ресурсов лучше всего использовать обычный блокнот Windows и какой-либо редактор ресурсов (Resource Hacker, например). С начало в блокноте набирается код главного окна, например такой:

MAIN_WINDOW DIALOGEX 32768, 0, 258, 130
STYLE DS_MODALFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU
CAPTION "Главное окно"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
FONT 8, "MS SANS SERIF"
{
CONTROL "Закрыть", 1, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 193, 107, 55, 14
}

MAINICON ICON "C:\Icons\captionicon.ico"

В состав ресурсов окна мы также добавили значек программы (файл captionicon.ico). Заметьте, что главное окно названо MAIN_WINDOW, а значок - MAINICON. Данные идентификаторы будут нужны для обработки: вызова диалогового окна из ресурсов и отображения значка в шапке программы. Ключевое слово ICON сигнализирует, что в проект добавляется именно значок. Перед словом ICON ставится идентификатор (MAINICON), по которому этот значок будет затем "опознан" программой. В качестве идентификатора могут применяться либо целочисленные константы, либо строковые константы.

Вы сохраняете данный код как текстовый файл, меняете разрешение с *.txt на *.rc и компилируете его с помощью Borland Resource Compiler (файл BRCC32.EXE), который входит в поставку с DELPHI (в данном примере использован компилятор Delphi 3):

C:\Program Files\Borland\Delphi 3\BIN\Brcc32.exe example.rc

И получаете после компиляции файл example.res, который будет содержать в себе главное окно программы с кнопкой "Закрыть" (идентификатор "1") и значек. Теперь осталось подсоединить ресурсный файл в коде программы, прописав {$R example.res}, и использовать по назначению.

Чтобы не возиться с набиранием кода диалогового окна, проще всего взять его из чужой программы, написанной на API (например, WinZIP, WinRAR) и отредактировать в редакторе ресурсов. Существуют программы для создания диалоговых окон, но как показала практика, они не удобны и способны лишь на построение простейших окон, код которых можно с легкостью набрать в блокноте.

Код API-приложения будет выглядеть сложнее кода программы, написанной с помощью VCL. Объясняется это тем, что в данном случае все обработчики элементов управления нужно создавать вручную. Достаточно посмотреть на код программы, которая вызывает из ресурсов созданное нами ранее диалоговое окно и обрабатывает кнопку "Закрыть":

program example_program;

uses
 Windows, Messages;

//Функция, обрабатывающая все команды от элементов управления окна
function DlgProc(hWin, uMsg, wParam, lParam: Integer): Integer; stdcall;
begin
 Result := 0;
  case uMsg of
   WM_INITDIALOG:
    begin
     //Помещаем в шапку программы значок MAINICON
     SendMessage(hWin, WM_SETICON, ICON_BIG, LoadIcon(hInstance, 'MAINICON'));
    end;
   WM_COMMAND:
    begin
     case LoWord(wParam) of
      //При нажатии на кнопку с идентификатором 1 закрываем программу
      1: EndDialog(hWin, 0);
    end;
  end;
   //При нажатии на кнопку "Х" в шапке программы закрываем приложение
   WM_DESTROY, WM_CLOSE: PostQuitMessage(0);
 end;
end;

begin
 //Подключаем файл ресурсов
 {$R example.res}
 //При запуске программы открываем диалоговое окно MAIN_WINDOW
 DialogBox(hInstance, 'MAIN_WINDOW', 0, @DlgProc);

end.

Если вы все сделали правильно, то при запуске программы увидите диалоговое окно с кнопкой "Закрыть". В программу можно поместить любые ресурсы: приложения, шрифты, изображения, текстовые файл и т.п. Но это уже тема отдельной статьи...

Copyright © 2002-2008 by Vladimir Drigalkin aka LENIN INC. All Rights Reserved.