Смекни!
smekni.com

Федеральное государственное образовательное учреждение Высшего профессионального образования «Южный федеральный университет» Авакян Леон Александрович «использование win api функций в среде делфи» (уч (стр. 3 из 6)

Var WndClass: TWndClass;

FillChar(WndClass, SizeOf(WndClass), 0); //заполняем структуру нулямиwith WndClass do beginhInstance := SysInit.hInstance; //Обязательный параметр, идентификатор приложенияlpszClassName := sClassName; //имя классаlpfnWndProc := @WindowProc; // ссылка на оконную функциюhbrBackground := GetStockObject(LTGRAY_BRUSH); // способ заливки клиентской области

end;

Заполнение нулями необходимо для того, чтобы мусор, который, возможно, остался в памяти, не повлиял на параметры, значения которых явно не прописывается (стиль окна, иконка, курсор…).

После того, как создан класс, создаем на его основе окно. Это делается с помощью функции CreateWindow().

После того, как окно создано, его можно показать, например, с помощью функции ShowWindow(). Следует отметить, что эту функцию можно применить только к родительскому окну, т.е. если приложение содержит главное окно и дочерние компоненты, то аргументом этой функции является дескриптор главного окна.

Прием сообщений осуществляется с помощью нескольких функций: GetMessage(); TranslateMessage(); DispatchMessage(); DefWindowProc();
Для того, чтобы организовать цикл получения сообщений, нужно в первую очередь написать функцию окна, т.е. функцию, которая будет совершать какие-либо действия в ответ на сообщение (адрес этой функции указывается в структуре WNDCLASS: IpfnWndProc:=@WindowProc). Необходимо правильно описать функцию:

На языке С++:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

На языке Object Pascal:
function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer; stdcall; export;

где HWND - дескриптор окна, который был получен после выполнения функции CreateWindow(), uMsg - код сообщения (16 бит) (может использоваться, например, следующим образом: if uMsg=WM_CLOSE then …),WPARAM, LPARAM - параметры, которые передаются вместе с сообщением (16 бит).

Цикл обработки сообщений имеет следующий вид:

while GetMessage(Msg, 0, 0, 0) do begin

TranslateMessage(Msg);

DispatchMessage(Msg);

end;

Функция GetMessage() выбирает первое сообщение из очереди сообщений, предназначенных для данного приложения, функция TranslateMessage() переводит виртуальный код сообщения в строку символов, функция DispatchMessage() отправляет сообщение на обработку оконной функцией, заданной при регистрации класса окна.

Оконная функция может иметь следующий вид:

function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer; stdcall; export;begin Result := 0; case uMsg of WM_DESTROY: … WM_PAINT: … … end else Result := DefWindowProc(hWnd, uMsg, wParam, lParam); end;

Внутри блока case располагается код, ответственный за особую реакцию приложения на некоторые сообщения (закрытие окна, его перерисовка). Функция DefWindowProc вызывает стандартную оконную функцию, которая обрабатывает все остальные сообщения, не указанные в блоке.

Пример создания простейшего окна приведен ниже. Обратите внимание, что весь код располагается в файле project1.dpr, как и в случае консольного приложения (но без директивы $APPTYPE CONSOLE).

program project1;uses Windows, Messages; const sClassName = 'MyWindow'; // Имя класса окнаvar hWnd: THandle; // идентификатор окна (дескриптор) WndClass: TWndClass; //структура WndClass Msg: TMsg; //структура для принятия сообщений function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer; {функция окна} stdcall; export;begin Result := 0; case uMsg of WM_DESTROY: //если uMsg равна WM_DESTROY(код закрытия окна) то закрываемся begin halt(0); end; end; Result := DefWindowProc(hWnd, uMsg, wParam, lParam); // обработать остальные сообщенияend; begin FillChar(WndClass, SizeOf(WndClass), 0); //заполняем структуру нулями with WndClass do begin hInstance := SysInit.hInstance; lpszClassName := sClassName; //имя класса lpfnWndProc := @WindowProc; //ссылка на оконную функцию hbrBackground := GetStockObject(LTGRAY_BRUSH); end; RegisterClass(WndClass); //регистрируем класс hWnd := CreateWindow(sClassName, '', WS_OVERLAPPEDWINDOW, 200, 200, 300, 300, 0, 0, hInstance, NIL); //создаем окно if hWnd = 0 then begin //если произошла ошибка, то выходим MessageBox(0, 'Initialisation failed', NIL, ID_OK); Exit; end; ShowWindow(hWnd, SW_normal); //показываем окно while GetMessage(Msg, HWnd, 0, 0) do begin //получаем сообщение TranslateMessage(Msg); DispatchMessage(Msg); end; Halt(Msg.wParam);end.

В результате работы такой программы должно появиться обычное окно, которое можно закрыть стандартным образом.

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

2.2. Создание кнопок (button) средствами WinAPI

Создание кнопки производится с помощью уже использованной нами для создания окна функцией CreateWindow. В качестве класса окна нужно использовать определенный в системе класс кнопки BUTTON. Основные доступные классы, предоставляемые операционной системой, следующие: LISTBOX, COMBOBOX, MEMO, MAINMENU, EDIT, SCROLLBAR, BUTTON, LISTVIEW, STATIC, TREEVIEW, HEADER, TOOLBAR, STATUSBAR, TRACKBAR, UPDOWN, PROGRESS, TABCONTROL, RICHEDIT, POPUPMENU, CHECKBOX, LABEL, GAUGE.

Изменим оконную функцию, описанную в предыдущем разделе, следующим образом:

function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer; stdcall; export;{функция окна}begin Result := 0; case uMsg of WM_DESTROY: //если uMsg равна WM_DESTROY(код закрытия окна), то закрываемся begin halt(0); end; WM_CREATE: begin // создание кнопки hButton := CreateWindowEx (0, 'BUTTON', // определенный класс кнопки '&Нажмите здесь', // надпись на кнопке ws_Child or ws_Visible or bs_PushButton, // стили для кнопки 10, 10, // координаты левого верхнего угла 200, 80, // размер hWnd, // handle родителя id_Button, // идентификатор кнопки (задается программистом) hInstance, nil); end; WM_COMMAND: // проверяем, от какой кнопки пришло сообщение if LoWord (wParam) = id_Button then // если это событие - click if HiWord (wParam) = bn_Clicked then // код обработки нажатия кнопки MessageBox (hWnd, 'Вы нажали на кнопку', '', MB_OK); end; Result := DefWindowProc(hWnd, uMsg, wParam, lParam); end;

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

Обработка сообщений, передаваемых элементам управления, реализована с помощью сообщения WM_COMMAND, приходящего родительскому окну. В этом случае, первые 2 байта wParam хранят идентификатор элемента, остальные 2 – код уведомления/события. Таким образом, для того, чтобы обработать нажатие на кнопку, нужно принять сообщение WM_COMMAND и проанализировать параметр оконной функции wParam.

2.3. Создание однострокового редактора (Edit) средствами WinAPI

Создание строкового редактора осуществляется аналогично кнопке с помощью процедуры CreateWindow, но с использованием класса EDIT:

hEdit := CreateWindow ('EDIT', // стандартный класс 'Hello', // текст WS_CHILD or WS_VISIBLE or WS_TABSTOP or WS_BORDER, // стиль 10, 10, // положение 150, 24, // размер hWnd, // родительское окно id_Edit, // идентификатор данного контрола hInstance, // как обычно - экземпляр программы nil) ;Чтобы созданный элемент был дочерним по отношению к главному окну – необходимо указать флаг WS_CHILD в стиле элемента. Также, для каждого элемента применимы как стандартные WS_ флаги стилей, так и свои собственные (ES_, BS_, SS_ и т.д.) которые зачастую являются специфичными только для этого типа элементов.

Для получения доступа к текстовой строке Edit’а, воспользуемся функциями GetWindowText и SetWindowText. Первая функция копирует строку в указанный буфер. В нашем случае этой строкой является содержимое edit’а. Вторая функция позволяет установить текст (если это возможно).

Дополним предыдущий пример с использованием этих функций так, чтобы при нажатии на кнопку появлялось окно с текстом edit’а. Оконная функция будет иметь следующий вид:

function WindowProc(hWnd: THandle; uMsg, wParam, lParam: Integer): Integer; stdcall; export;{функция окна}var p^: Pointer; // буфер для считывания строкиbegin Result := 0; case uMsg of WM_DESTROY: halt(0); WM_CREATE: begin // create button hButton := CreateWindowEx (0,'BUTTON','&Click here', ws_Child or ws_Visible or bs_PushButton, 10, 100, 200, 80, hWnd, id_Button, hInstance, nil); // create edit hEdit := CreateWindow ('EDIT', 'Hello', WS_CHILD or WS_VISIBLE or WS_TABSTOP or WS_BORDER, 10, 10, 250, 24, hWnd, id_Edit, hInstance, nil) ; SetWindowText( hEdit, 'некоторый текст'); // меняем текст end; WM_COMMAND: if LoWord (wParam) = id_Button then if HiWord (wParam) = bn_Clicked then // обработка нажатия кнопки begin GetMem(p, 255*SizeOf(Char)); // подготовка буфера GetWindowText(hEdit, p, 255*SizeOf(Char)); // считывание текста в буфер MessageBox (hWnd, PChar(p), 'текст в Edit', MB_OK); FreeMem(p); // освобождение буфера end; end; Result := DefWindowProc(hWnd, uMsg, wParam, lParam); end;

Результат работы представлен на рисунке:

2.3. Создание многострокового редактора (Memo) средствами WinAPI

Создание многострокового редактора производится на основе уже рассмотренного элемента EDIT путем использования стиля ES_MULTILINE следующим образом:

hMemo := CreateWindow('EDIT', 'Memo1', WS_VISIBLE or WS_CHILD or WS_DLGFRAME or WS_VSCROLL or ES_MULTILINE or ES_AUTOVSCROLL, // cтили для edit-элемента5, 180, 250, 70, hWnd, 0, hInstance, nil);

Модифицируем код предыдущего пункта так, чтобы текст edit’а сохранялся в Memo1 после нажатия на кнопку. Для этого изменим код обработчика нажатия на кнопку следующим образом:

var p: PChar;… WM_COMMAND: if LoWord (wParam) = id_Button then if HiWord (wParam) = bn_Clicked then // обработка нажатия кнопки begin GetMem(p, 32*1024); // подготовка буфера // получим текст из Memo GetWindowText(hMemo, p, 32*1024); // добавление символа конца строки Move(#13#10, PChar(Integer(p) + Length(p))^, 2); // добавление текста из Edit GetWindowText(hEdit, PChar(Integer(p + Length(p))), 32*1024); // устанавливаем новый текcт в Memo SetWindowText(hMemo, p); // прокрутка memo до самого конца while (LOWORD(SendMessage(hMemo, EM_SCROLL, SB_PAGEDOWN,0))<> 0) do; FreeMem(p); // освобождение буфера end; Результат работы представлен на рисунке:

2.4. Меню на WinAPI

Работа с меню тоже достаточно проста и логична. Как и каждый элемент управления, меню имеет свой дескриптор (HMENU). Он позволяет обращаться и изменять свойства пункта или группы пунктов.