Форум программистов, компьютерный форум, киберфорум
C++: WinAPI
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
1 / 1 / 0
Регистрация: 28.12.2018
Сообщений: 1
1

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

28.12.2018, 16:35. Просмотров 2042. Ответов 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)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.12.2018, 16:35
Ответы с готовыми решениями:

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

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

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

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

2
Эксперт С++
1926 / 1759 / 258
Регистрация: 03.05.2011
Сообщений: 4,022
Записей в блоге: 11
28.12.2018, 17:10 2
Цитата Сообщение от DSW_CAST Посмотреть сообщение
Что за магия!!
никакой магии, только цифры
#define WM_KEYDOWN 0x0100
#define WM_KEYUP 0x0101
0
2082 / 650 / 242
Регистрация: 10.02.2018
Сообщений: 1,519
28.12.2018, 17:22 3
Лучший ответ Сообщение было отмечено DSW_CAST как решение

Решение

Столько боли
На самом деле всё просто... наверное.
Использовать MessageBox для подобного анализа некорректно. Ведь данная функция подвешивает выполнение вызвавшего его кода до закрытия сообщения, после чего в вызвавший код возвращает результат и исполнение продолжается. Но ведь программа не вешается совсем и некоторые сообщения продолжают приходить. Как же так? Просто при вызове MessageBox запускается собственный цикл обработки сообщений, состоящий из тех же гетмессадже, транслейте и диспатч. Попробуйте заменить вывод сообщений на запись лога в файл.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
28.12.2018, 17:22

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.