#c #windows #winapi #win32gui #win32-process
#c #Windows #winapi #win32gui #win32-процесс
Вопрос:
Запуск моей программы выполняется, и из-за того, что у меня есть меню с ВЫХОДОМ, чтобы уничтожить окно, которое оно запускает и немедленно выходит из окна. Не уверен, как исправить мою проблему здесь при компиляции программы, чтобы она не запускала функцию WindowProcedure и не передавала аргумент EXITMENU, в результате чего окно уничтожается.
* .CPP
#include <windows.h>
#define HELPMENU 1
#define HIGHSCROREMENU 2
#define EXITMENU 3
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow) {
WNDCLASS wc = { 0 }; // WNDCLASSW is a structure
LPCWSTR title = L"Window"; // Long Pointer Constant Wide (UTF-16) String
wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // Background
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_HAND); // Sets Cursor
wc.hInstance = hInst; // Instance of window
wc.lpszClassName = L"windowClass"; // Class name
wc.lpfnWndProc = WindowProcedure; // Pointer to the function // Controller of window handle
if (!RegisterClassW(amp;wc)) { // Registers the window class
return -1;
}
// | binary combination value, posX, posY, Width, Height
// Creates the window
CreateWindow(wc.lpszClassName, title, WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_BORDER, 100, 100, 800, 600, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(amp;msg, NULL, NULL, NULL) > 0) { // Keeps the window running
TranslateMessage(amp;msg);
DispatchMessage(amp;msg);
}
return 0;
}
/* Event Paths */
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg) {
case WM_CREATE: // On window creation
AddControls(hWnd);
AddMenu(hWnd);
break;
case WM_LBUTTONDOWN: // Left Mouse button
break;
case WM_DESTROY: // Makes GetMessage Function return false, closing the window
PostQuitMessage(0);
return 0;
case EXITMENU:
DestroyWindow(hWnd); // This part of the code shouldn't run on creation
break;
default:
return DefWindowProc(hWnd, msg, wp, lp);
}
}
/* Creates menu */
void AddMenu(HWND hWnd) {
hMenu = CreateMenu(); // Creates menu object
// AppendMenu(Menu Instance, Usage Type, Argument, String info);
AppendMenu(hMenu, MF_STRING, HELPMENU, L"Help - F1");
AppendMenu(hMenu, MF_STRING, HIGHSCROREMENU, L"Highscores - F2"); // Menu Created
AppendMenu(hMenu, MF_STRING, EXITMENU, L"Exit - ESC");
// SetMenu(Window Handle , Menu Instance);
SetMenu(hWnd, hMenu); // Sets menu for window //
}
Комментарии:
1.
#define EXITMENU 3
Почему?3
WM_MOVE
определяется в winuser.h.2. EXITMENU не является сообщением. Совпадение с WM_MOVE не является веской причиной для уничтожения окна. Используйте WM_COMMAND для обнаружения команд меню.
3. Спасибо dxiv и @Hans Passant, не понял, что он уже переопределяет определенное значение. Вместо этого я рассмотрю выполнение WM_COMMAND. Все еще пытаюсь понять Win32Api в целом.
Ответ №1:
Вы неправильно обрабатываете команды меню в своем WindowProcedure()
.
Вы определили EXITMENU
как 3, что соответствует тому же значению, WM_MOVE
что и сообщение. Итак, в вашем switch
случае вы уничтожаете свое окно, как только оно получает WM_MOVE
сообщение во время создания окна.
Вместо этого вам необходимо обрабатывать команды меню через WM_COMMAND
сообщение, согласно документации:
О меню: сообщения, используемые с меню
Когда пользователь выбирает командный элемент из меню, система отправляет
WM_COMMAND
сообщение оконной процедуре. Младшее слово параметраWM_COMMAND
сообщенияwParam
содержит идентификатор выбранного элемента. Оконная процедура должна проверить идентификатор и соответствующим образом обработать сообщение.
Попробуйте это вместо:
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg) {
...
case WM_COMMAND:
switch (wp) {
case HELPMENU: {
...
return 0;
}
case HIGHSCROREMENU: {
...
return 0;
}
case EXITMENU: {
DestroyWindow(hWnd);
return 0;
}
}
break;
}
...
}
return DefWindowProc(hWnd, msg, wp, lp);
}
ОБНОВЛЕНИЕ: при этом рассмотрите EXITMENU
возможность использования вашего обработчика SendMessage(WM_CLOSE)
вместо DestroyWindow()
. Если ваше приложение поддерживает данные, которые должны быть сохранены при закрытии приложения пользователем, вы можете добавить WM_CLOSE
обработчик для выполнения этого действия независимо от того, как закрывается окно (ваше меню выхода, X
кнопка закрытия и Alt-F4т. Д.). DefWindowProc()
уничтожает окно при обработке WM_CLOSE
.
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg) {
...
case WM_CLOSE: {
if (data has been modified) {
prompt user to save data...
if (cancelled) {
return 0;
}
if (should save) {
save data ...
}
}
break;
}
case WM_COMMAND:
switch (wp) {
...
case EXITMENU: {
SendMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
}
}
break;
}
...
}
return DefWindowProc(hWnd, msg, wp, lp);
}
Комментарии:
1. Потрясающе, именно то, что я только что сделал, благодаря вам и @Hans Passant.
2. Похожие: Почему редакторы диалоговых окон начинают назначать идентификаторы элементов управления со 100?