Написание программ на чистом WinAPI
Материал из DRKB
Написание программ на чистом WinAPI[править | править код]
Попробуем написать с Вами программу, которая не будет пользоваться VCL, а будет использовать вызовы функций Windows API.
Приложения такого типа нужны, когда размер исполняемого файла является критичным. Например, в инсталяторах, деинсталяторах, самораспаковывающихся архивах и т.п. В крайнем случае, для того чтобы посмотреть какую работу выполняет за нас VCL, и что из себя представляет Windows-программа.
На самом деле все очень просто... Для этого нам необходимо:
1. Зарегистрировать класс окна для окна главной формы.
function InitApplication: Boolean;
var
wcx: TWndClass;
begin
// Заполняем структуру TWndClass
// перерисовываем, если размер изменяется
wcx.style := CS_HREDRAW or CS_VREDRAW;
// адрес оконной процедуры
wcx.lpfnWndProc := @MainWndProc;
wcx.cbClsExtra := 0;
wcx.cbWndExtra := 0;
// handle to instance
wcx.hInstance := hInstance;
// загружаем стандандартную иконку
wcx.hIcon := LoadIcon(0, IDI_APPLICATION);
// загружаем стандартный курсор
wcx.hCursor := LoadCursor(0, IDC_ARROW);
// делаем светло-cерый фон
wcx.hbrBackground := COLOR_WINDOW;
// пока нет главного меню
wcx.lpszMenuName := nil;
// имя класса окна
wcx.lpszClassName := PChar(WinName);
// Регистрируем наш класс окна.
Result := RegisterClass(wcx) <> 0;
end;
2. Написать подпрограмму обработки оконных сообщений.
function MainWndProc(Window: HWnd; AMessage, WParam,
LParam: Longint): Longint; stdcall; export;
begin
// подпрограмма обработки сообщений
case AMessage of
WM_DESTROY: begin
PostQuitMessage(0);
Exit;
end;
else
Result := DefWindowProc(Window, AMessage, WParam, LParam);
end;
end;
3. Создать главное окно приложения.
function InitInstance: HWND;
begin
// Создаем главное окно.
Result := CreateWindow(
PChar(WinName), // имя класса окна
'Small program', // заголовок
WS_OVERLAPPEDWINDOW, // стандартный стиль окна
// стандартные горизонтальное, вертикальное положение, ширина и высота
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
0, // нет родительского окна
0, // нет меню
hInstance, // handle to application instance
nil); // no window-creation data
end;
4. Написать тело программы.
var
hwndMain: HWND;
AMessage: msg;
begin
if (not InitApplication) then
begin
MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok);
Exit;
end;
hwndMain := InitInstance;
if (hwndMain = 0) then
begin
MessageBox(0, 'Ошибка создания окна', nil, mb_Ok);
Exit;
end
else
begin
// Показываем окно и посылаем сообщение WM_PAINT оконной процедуре
ShowWindow(hwndMain, CmdShow);
UpdateWindow(hwndMain);
end;
while (GetMessage(AMessage, 0, 0, 0)) do
begin
// Запускаем цикл обработки сообщений
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
Halt(AMessage.wParam);
end.
5. Запустить программу на исполнение. ;)
Наша программа пока только может немногое - отображать форму, и закрываться после нажатия на кнопку закрытия формы... Но посмотрите на размер исполняемого файла - он больше чем на порядок меньше созданного с использованием VCL.
Полный текст програмы:
program SmallPrg;
uses Windows, Messages;
const
WinName = 'MainWClass';
function MainWndProc(Window: HWnd; AMessage, WParam,
LParam: Longint): Longint; stdcall; export;
begin
// подпрограмма обработки сообщений
case AMessage of
WM_DESTROY: begin
PostQuitMessage(0);
Exit;
end;
else
Result := DefWindowProc(Window, AMessage, WParam, LParam);
end;
end;
function InitApplication: Boolean;
var
wcx: TWndClass;
begin
// Заполняем структуру TWndClass
// перерисовываем, если размер изменяется
wcx.style := CS_HREDRAW or CS_VREDRAW;
// адрес оконной процедуры
wcx.lpfnWndProc := @MainWndProc;
wcx.cbClsExtra := 0;
wcx.cbWndExtra := 0;
// handle to instance
wcx.hInstance := hInstance;
// загружаем стандандартную иконку
wcx.hIcon := LoadIcon(0, IDI_APPLICATION);
// загружаем стандартный курсор
wcx.hCursor := LoadCursor(0, IDC_ARROW);
// делаем светло-cерый фон
wcx.hbrBackground := COLOR_WINDOW;
// пока нет главного меню
wcx.lpszMenuName := nil;
// имя класса окна
wcx.lpszClassName := PChar(WinName);
// Регистрируем наш класс окна.
Result := RegisterClass(wcx) <> 0;
end;
function InitInstance: HWND;
begin
// Создаем главное окно.
Result := CreateWindow(
PChar(WinName), // имя класса окна
'Small program', // заголовок
WS_OVERLAPPEDWINDOW, // стандартный стиль окна
// стандартные горизонтальное, вертикальное положение, ширина и высота
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
0, // нет родительского окна
0, // нет меню
hInstance, // handle to application instance
nil); // no window-creation data
end;
var
hwndMain: HWND;
AMessage: msg;
begin
if (not InitApplication) then
begin
MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok);
Exit;
end;
hwndMain := InitInstance;
if (hwndMain = 0) then
begin
MessageBox(0, 'Ошибка создания окна', nil, mb_Ok);
Exit;
end
else
begin
// Показываем окно и посылаем сообщение WM_PAINT оконной процедуре
ShowWindow(hwndMain, CmdShow);
UpdateWindow(hwndMain);
end;
while (GetMessage(AMessage, 0, 0, 0)) do
begin
// Запускаем цикл обработки сообщений
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
Halt(AMessage.wParam);
end.
Последний раз мы рассмотрели пару ф-й и их особенности(FindWindow, GetNextWindow и GetWindowText), однако несмотря на это были вопросы именно на эту тему - вывод : торопитесь ребята. Старайтесь по максимуму использовать, то что у Вас уже есть.
Итак вдогонку к 12-у выпуску хочется отметить, что при поиске окон, как отмечалось, нужен класс и имя, так вот - если Вы ищите DOS-окно, то его класс всегда = 'tty'.
Сегодня рассмотрим некоторые вспомогательные функции, которые немного облегчают и нашу жизнь, и программу в целом.
Получить каталог Windows( вдруг при установке Вы назвали его Unix :) ).
var s1 : array[0..254] of Char; ... GetWindowsDirectory(s1,255);
В s1 получим искомый путь.
Один момент - не надо описывать s1 просто как PChar, иначе при выполнении получите неприятное сообщение.
Аналогично можно найти и системный каталог. Это тоже важно, поскольку, например для Win9x это 'Windows\System', а для NT 'System32'.
GetSystemDirectory(s1, 255);
255 - это длинна строки. Отдельно подчеркну, что очень рекомендую вместо этого числа ставить переменную Max_Path, содержащую в себе максимальную длину пути в Вашей операционной системе.
Еще очень интересная функция. Она позволяет запретить или разрешить все действия с окном пользователю.
EnableWindow(H: Hwnd, t: Boolean);
Где h-дескриптор окна, если сказать Application.Handle, то свое окно. t=False - запретить действия, True - разрешить.
Ну и все с Api - функциями на этом.
ID: 02013