С Новым годом! Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.90/21: Рейтинг темы: голосов - 21, средняя оценка - 4.90
1 / 1 / 0
Регистрация: 28.12.2018
Сообщений: 1

Разбор работы системы сообщений в Win32 проекте

28.12.2018, 16:35. Показов 4151. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, я, вообщем-то, желаю разобраться как работает цикл обработки сообщений в проекте Win32.
Как взаимодействуют между собой TranslateMessage и DispatchMessage.
Для начала, я испытывая код заметил очень интересную штуку.
Штука заключается в том, что в самом цикле обработки сообщений

C++
1
2
3
4
5
6
while((k = GetMessage(&msg, NULL, 0, 0))){ // bool k;
    if(k == (-1))
        return 1;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
царит какой-то хаос. Поясню. Далеко не секрет что при нажатии клавиши(любой алфавитно-цифровой)
генерируется сообщение WM_KEYDOWN. Т.е. GetMessage(&msg, NULL, 0, 0) сделает так, что в переменной
структуры MSG - message, будет значение WM_KEYDOWN. Это можно легко проверить если включить в цикл
условие

C++
1
2
if(msg.message == WM_KEYDOWN)
    MessageBox(NULL, NULL, NULL, 0);
в результате истинности этого условия будет появляться окно, с сообщением об ошибке, которое
будет идентификатором того, то кнопка была нажата. Но помимо нажатия клавиши, есть ещё сообщение о
'разжатии' клавиши. А именно - WM_KEYUP. Вот тут то и возникает важная штука.

Если цикл обработки сообщений определить как

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
while((k = GetMessage(&msg, NULL, 0, 0))){ // bool k;
    if(k == (-1))
        return 1;
    switch(msg.message){
    case WM_KEYUP:{
        MessageBox(NULL, _T("KEYUP"), NULL, 0);
        break;
    }
    case WM_KEYDOWN:{
        MessageBox(NULL, _T("KEYDOWN"), NULL, 0);
        break;
    }
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
То описание его работы примит следующий вид:
После нажатия кнопки сгенерируется сообщение WM_KEYDOWN, затем выскочит сообщение с текстом
"KEYDOWN". Но после всего этого, сообщения "KEYUP" не появляется. Хотя клавиша разжата.
Т.е. генерируется сообщение WM_KEYDOWN, это следует из работы вышеописанного кода, затем по факту
должно генерироваться сообщение о разжатии кнопки WM_KEYUP, но этого не происходит.
В этом заключается ПЕРВЫЙ вопрос. Почему так? Разумеется никакие Sleep() не помогают(отсылка к тому
что дело не во времени). Однако, если закомментировать строку case WM_KEYDOWN(и её содержимое),
то как по волшебству, появится сообщение KEYUP! Как? Что за магия!! Почему когда условия два, и
каждое из них относится к одному из фундаментальных пунктов(нажатие и разжатие клавиши) система
"акцентирует" внимание на нажатии?
Далее, по теории как известно, TranslateMessage добавляет в очередь сообщений (в источник GetMessage)
сообщение WM_CHAR, после поступления в TranslateMessage msg.message == WM_KEYDOWN. Далее, после следующей
итерации цикла msg.message будет равно WM_CHAR. Т.е. той информации, которую "выбросила" функция
TranslateMessage.
Из вышесказанного следует проверить работоспособность следующего кода:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
while ((k = GetMessage(&msg, NULL, 0, 0))) {
        if (k == (-1))
            return 1;
 
        switch (msg.message) {
        case WM_KEYDOWN: {
            MessageBox(NULL, _T("KEYDOWN"), NULL, 0);
            break;
        }
        case WM_KEYUP: {
            MessageBox(NULL, _T("KEYUP"), NULL, 0);
            break;
        }
        case WM_CHAR: {
            MessageBox(NULL, _T("CHAR"), NULL, 0);
            break;
        }
        }
    
        TranslateMessage(&msg);
        DispatchMessage(&msg);
 
    }
 
}
Которая как ни странно, работает следующим образом: "KEYDOWN" затем "CHAR". Но если закомментировать
строки где определёна обработка WM_KEYDOWN, получится: "CHAR". А где "KEYUP"? А нет его! Это очень странно
ведь сообщения получается идут не по правилу : KEYDOWN CHAR KEYUP, а по правилу KEYDOWN CHAR.
Но есть один факт, который меня тоже очень смущает. Если многократно нажимать одну и ту-же клавишу,
при этом успевать закрывать всплывающие окна, картина будет немного иная: "KEYUP" станет появляться.
Что это за магия? Это противоречит визуальным законам программирования! И ни какие Slep(10000) не помогают.
В добавок ко всему: TranslateMessage и DispatchMessage не изменяют ЗНАЧЕНИЙ ПЕРЕМЕННОЙ СТРУКТУРЫ MSG.
Это прямо чемодан со странностями! Если добавить к вышеописанному коду ещё и обработку сообщений всё будет намного
страннее! К примеру у нас остался последний код в качестве основы цикла обработки сообщений. Мы определим
функцию обработки следующим образом:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam) {
    switch (mes) {
    case WM_KEYDOWN: {
        MessageBox(NULL, _T("WND KEYDOWN"), NULL, 0);
        break;
    }
    case WM_KEYUP: {
        MessageBox(NULL, _T("WND KEYUP"), NULL, 0);
        break;
    }
    case WM_CHAR: {
        MessageBox(NULL, _T("WND CHAR"), NULL, 0);
        break;
    }
    case WM_DESTROY: {
        PostQuitMessage(0);
        break;
    }
    default:
        return DefWindowProc(hWnd, mes, wParam, lParam);
    }
 
    return 0;
}
А здесь вообще непонятно что! С начала "KEYDOWN", затем вообще "WND CHAR" и только потом, когда казалось бы вот всё,
символ обработан же, появляется, угадайте-ка что? "WND KEYDOWN" - НАЖАТИЕ КНОПКИ! Вы можете себе представить!
НАЖАТИЕ КНОПКИ ПОСЛЕ ТОГО КАК ОБРАБОТАЛОСЬ СООБЩЕНИЕ WM_CHAR, КОТОРОЕ СТАВИТСЯ В ОЧЕРЕДЬ СООБЩЕНИЙ
САМИМ "ТРАНСЛЕЙТОМ". Ладно, но ведь ещё вдобавок сообщение с текстом "CHAR" не вылазит. Т.е. в самом цикле, после
получения сообщения WM_KEYDOWN, и последующей отправки сообщения WM_CHAR "ТРАНСЛЕЙТОМ" в очередь сообщений, которые
извлекаются функцией GetMessage(), желанного сообщения "CHAR" нет! Ведь всё логично:
1 итерация) WM_KEYDOWN, дальше транслейт добавит WM_CHAR, но функции обработки сообщения должно быть отправлено
и ни как не изменяемо (напоминаю диспатч и транслейт msg не изменяют) сообщение WM_KEYDOWN, оно отправляется..иии...
ни че го! Серьёзно! Ничего. Хотя нет, вместо желанного "WND KEYDOWN"(ведь мы послали в оконную функцию сообщение
WM_KEYDOWN) мы получаем "WND CHAR" и только потом, (во второй итерации) "WND KEYDOWN".
2 итерация) Из очереди выносим сообщение WM_CHAR (помещённое туда ТРАНСЛЕЙТОМ), как ни странно, но
код в котором обрабатывается условие о сообщении WM_CHAR не работает, а потом диспатч отправляет
оконной функции сообщение WM_CHAR, а вылезет "WND KEYDOWN".
Этот вопрос практическо-теоретический, он в целом заключается в - ПОЧЕМУ? и в - КАК? и в - ОБЪЯСНИТЕ ПОЖАЛУЙСТО.
Благодарю за внимание!
1
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
28.12.2018, 16:35
Ответы с готовыми решениями:

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

Редактор форм в проекте Win32
Visual C++ -> проект Win32. Я что-то не нашел где редактировать форму, добавлять элементы управления или в таком проекте по хардкору все...

Разбор NMEA сообщений
Товарищи, подскажите, что не так делаю. Решил распарсить данные с GPS приемника. Принимаю с помощью USART на скорости 9600. Проблема в...

2
Эксперт С++
 Аватар для _lunar_
3701 / 2836 / 451
Регистрация: 03.05.2011
Сообщений: 5,193
Записей в блоге: 21
28.12.2018, 17:10
Цитата Сообщение от DSW_CAST Посмотреть сообщение
Что за магия!!
никакой магии, только цифры
#define WM_KEYDOWN 0x0100
#define WM_KEYUP 0x0101
0
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,098
28.12.2018, 17:22
Лучший ответ Сообщение было отмечено DSW_CAST как решение

Решение

Столько боли
На самом деле всё просто... наверное.
Использовать MessageBox для подобного анализа некорректно. Ведь данная функция подвешивает выполнение вызвавшего его кода до закрытия сообщения, после чего в вызвавший код возвращает результат и исполнение продолжается. Но ведь программа не вешается совсем и некоторые сообщения продолжают приходить. Как же так? Просто при вызове MessageBox запускается собственный цикл обработки сообщений, состоящий из тех же гетмессадже, транслейте и диспатч. Попробуйте заменить вывод сообщений на запись лога в файл.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.12.2018, 17:22
Помогаю со студенческими работами здесь

Как включить поддержку MFC в Win32 проекте VC++ 7.0?
Дело в том, что Debug версия работает, а Release ругается ошибками, похожими на те, которые возникали в VC++ 6 ( error LNK2019: Unresolved...

Разбор методов реализованных в проекте и разьяснение части кода
Программа предназначенна для чтения файлов логов, больших обьемов, я не сосвсем понимаю как она работает и не могу разобраться с лябда...

Отлавливание сообщений в проекте MFC
Есть проект с двумя классами! Первый, который создается при создании проекта, а второй я добавил сам( в нем файлы соответственно **.h и...

Обработка сообщений в win32 api
Написал программу которая после ввода в поле edit текста exit и нажатия на кнопку выходит из программы, но почему то не работает. Вот...

Как в проекте C# Any CPU (или x64) импортировать функции из нативной DLL Win32?
Написал простейшую DLL в VC++ Express 2008 на основе "Проект Win32". DLL получилась x86. Как сделать x64 - не знаю, да и зачем вроде бы это...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru