В этом выпуске мы попробуем написать с Вами программу, которая не будет пользоваться 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 instancenil); // no window-creation dataend;
// 4. Написать тело программы.var
hwndMain: HWND;
AMessage: msg;
beginif (not InitApplication) thenbegin
MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok);
Exit;
end;
hwndMain := InitInstance;
if (hwndMain = 0) thenbegin
MessageBox(0, 'Ошибка создания окна', nil, mb_Ok);
Exit;
endelsebegin// Показываем окно и посылаем сообщение WM_PAINT оконной процедуре
ShowWindow(hwndMain, CmdShow);
UpdateWindow(hwndMain);
end;
while (GetMessage(AMessage, 0, 0, 0)) dobegin//Запускаем цикл обработки сообщений
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 instancenil); // no window-creation dataend;
var
hwndMain: HWND;
AMessage: msg;
beginif (not InitApplication) thenbegin
MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok);
Exit;
end;
hwndMain := InitInstance;
if (hwndMain = 0) thenbegin
MessageBox(0, 'Ошибка создания окна', nil, mb_Ok);
Exit;
endelsebegin// Показываем окно и посылаем сообщение WM_PAINT оконной процедуре
ShowWindow(hwndMain, CmdShow);
UpdateWindow(hwndMain);
end;
while (GetMessage(AMessage, 0, 0, 0)) dobegin//Запускаем цикл обработки сообщений
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
Halt(AMessage.wParam);
end.
Программа на Windows API - это отличное упражнение!
Вот моя обратная связь по коду:
InitApplication: Функция корректно регистрирует класс окна, и хорошо, что вы проверяете, была ли регистрация успешной.
MainWndProc: Это процедура окна для вашего основного окна. Она корректно обрабатывает сообщение WM_DESTROY, чтобы выйти из программы. Однако я хотел бы предложить несколько улучшений:
Вместо использования Exit,consider использовать Result := 0 для возврата из функции.
Рассмотрите добавление обработчиков для других общих сообщений, таких как WM_CLOSE или WM_QUIT.
InitInstance: Функция создает экземпляр основного окна. Она корректно создает новое окно с указанным именем класса и заголовком.
Основной цикл программы: Вы используете GetMessage для извлечения и обработки сообщений из очереди сообщений. Это правильное, но вы можете хотел бы добавить некоторые обработчики ошибок в случае неожиданных сообщений.
Некоторые минимальные предложения:
В InitApplication, вместо использования hInstance := hInstance;, вы можете просто опустить эту строку, потому что она не делает ничего.
В MainWndProc, вместо использования PostQuitMessage(0) для выхода из программы, consider использовать Result := 0 как я упомянул ранее.
Вы можете хотел бы добавить некоторые комментарии или документацию, чтобы объяснить, что каждый функция делает.
В отношении альтернативных решений, вот несколько предложений:
Вместо использования CreateWindow для создания основного окна, вы могли использовать CreateWindowEx с дополнительными параметрами (например, WS_EX_OVERLAPPEDWINDOW) для настройки процесса создания окна.
Если вы хотите добавить больше функциональности в вашу программу, рассмотрите создание отдельных функций или процедур для каждого задачи. Это сделает ваш код более модульным и проще для поддержки.
В целом, ваш код хорошо структурирован и легко читаемый. Продолжайте хорошую работу!
Написание программ на чистом API 2: создание приложения с использованием вызовов функций Windows API, без использования VCL.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.