Как бы мне реализовать главный цикл программы, чтобы в одном потоке:
1) обрабатывать сообщения windows
2) делать вычисления и отрисовку с нужной частотой
3) остальное время спать
4) даже во время сна обрабатывать новые сообщения
Является ли такая реализация через PeekMessageA:
Аналогом такой типичной реализации через GetMessageA?
Плохо только, что я не проверяю возвращаемое значение функции MsgWaitForMultipleObjects, но это только демонстрационный пример.
ссылка на канал | ссылка на группу
1) обрабатывать сообщения windows
2) делать вычисления и отрисовку с нужной частотой
3) остальное время спать
4) даже во время сна обрабатывать новые сообщения
Является ли такая реализация через PeekMessageA:
MSG message { };
while(true)
{
while(PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessageA(&message);
}
if(message.message == WM_QUIT)
{
break;
}
MsgWaitForMultipleObjects(0, nullptr, false, INFINITE, QS_ALLINPUT);
}Аналогом такой типичной реализации через GetMessageA?
MSG message { };
while(GetMessageA(&message, nullptr, 0, 0))
{
TranslateMessage(&message);
DispatchMessageA(&message);
}Плохо только, что я не проверяю возвращаемое значение функции MsgWaitForMultipleObjects, но это только демонстрационный пример.
ссылка на канал | ссылка на группу
👏1
C MsgWaitForMultipleObjects, CreateWaitableTimerA и SetWaitableTimer у меня не получилось достигнуть более 60 FPS.
Windows, конечно, не RTOS, но и само разрешение системного таймера довольно низкое.
Можно его изменить при помощи timeBeginPeriod, но мне этот способ не нравится.
Зато этот просто способ даёт точную и стабильную частоту кадров).
Правда, этот способ впустую тратит такты процессора, создаёт повышенную нагрузку и тепловыделение.
В диспетчере задач будет большой процент использования ЦП.
Поэтому мне нужен другой способ или комбинированный предыдущий.
ссылка на канал | ссылка на группу
Windows, конечно, не RTOS, но и само разрешение системного таймера довольно низкое.
Можно его изменить при помощи timeBeginPeriod, но мне этот способ не нравится.
Зато этот просто способ даёт точную и стабильную частоту кадров).
// timeNow возвращает текущее время в наносекундах (windows QPC)
while(true)
{
...
static int64_t nextIter { };
int64_t now { };
timeNow(&now);
if(now >= nextIter)
{
InvalidateRect(window, nullptr, false);
const int64_t targetFPS { 240 };
nextIter = now + 1'000'000'000 / targetFPS;
}
...
}
Правда, этот способ впустую тратит такты процессора, создаёт повышенную нагрузку и тепловыделение.
В диспетчере задач будет большой процент использования ЦП.
Поэтому мне нужен другой способ или комбинированный предыдущий.
ссылка на канал | ссылка на группу
🤔1
Dmitry Develop
ссылка на канал | ссылка на группу
Необычная ошибка возникла при реализации off-screen bitmap rendering).
Как хорошо, что я уже давно не начинающий, поэтому никаких сложностей с отладкой не возникнет).
На экране рисуются две строки: 1) FPS, 2) задержка в наносекундах после отрисовки кадра.
Причина проблемы была в заполнении прямоугольника RECT функцией GetWindowRect вместо GetClientRect.
ссылка на канал | ссылка на группу
Как хорошо, что я уже давно не начинающий, поэтому никаких сложностей с отладкой не возникнет).
На экране рисуются две строки: 1) FPS, 2) задержка в наносекундах после отрисовки кадра.
Причина проблемы была в заполнении прямоугольника RECT функцией GetWindowRect вместо GetClientRect.
ссылка на канал | ссылка на группу
Dmitry Develop
winAPIWrapper.png
Как же мне надоело, что в winAPI вроде есть общий механизм обработки ошибок, но используется он не во всех функциях и не везде одинаково.
Где-то функция при успешном выполнении не выставляет
Где-то при неуспешном выполнении возвращается -1, любое отрицательное число, NULL или какое-то специальное значение вида 0xFFFFFFFF.
При написании кода просто невозможно за всеми этими тонкостями уследить, даже имея документацию перед глазами.
Поэтому всё-таки я сделаю небольшую обёртку над каждой функцией, чтобы в моём проекте был общий стиль обработки ошибок.
ссылка на канал | ссылка на группу
Где-то функция при успешном выполнении не выставляет
SetLastError(ERROR_SUCCESS), где-то выставляет.Где-то при неуспешном выполнении возвращается -1, любое отрицательное число, NULL или какое-то специальное значение вида 0xFFFFFFFF.
При написании кода просто невозможно за всеми этими тонкостями уследить, даже имея документацию перед глазами.
Поэтому всё-таки я сделаю небольшую обёртку над каждой функцией, чтобы в моём проекте был общий стиль обработки ошибок.
ссылка на канал | ссылка на группу
👍1
Dmitry Develop
usedWinapiFunctions.png
Пересмотрел все файлы проекта и выписал все используемые функции из winAPI, их получилось аж 82!
Уверен, если бы я был более внимательным, а также посмотрел ещё другие свои проекты, их стало бы гораздо больше.
А теперь вспоминаем проблемы, которые я описывал в предыдущем посте... поэтому возникновение идеи написания простой обёртки было делом времени.
Кстати, на фото перечислены 83 функции, но только 82 из них без повторов).
ссылка на канал | ссылка на группу
Уверен, если бы я был более внимательным, а также посмотрел ещё другие свои проекты, их стало бы гораздо больше.
А теперь вспоминаем проблемы, которые я описывал в предыдущем посте... поэтому возникновение идеи написания простой обёртки было делом времени.
Кстати, на фото перечислены 83 функции, но только 82 из них без повторов).
ссылка на канал | ссылка на группу
Dmitry Develop
windowsInterestingFact.png
Интересный факт в windows.
Когда у вас зависала программа или выполняла какую-то тяжёлую и долгую работу, тем самым не отвечав на сообщения от windows, такая программа и её окно получали статус не отвечает, но окно всё равно можно было свернуть или переместить.
Так вот, на самом деле вы взаимодействовали не с оригинальным окном, а его копией).
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window.
Ссылка на документацию, секция Remarks, самый последний абзац.
Кстати, эту функцию можно даже отключить:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting
Узнать, что период, через который окно получает статус неактивного, равен 5 секундам можно тут:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-ishungappwindow
ссылка на канал | ссылка на группу
Когда у вас зависала программа или выполняла какую-то тяжёлую и долгую работу, тем самым не отвечав на сообщения от windows, такая программа и её окно получали статус не отвечает, но окно всё равно можно было свернуть или переместить.
Так вот, на самом деле вы взаимодействовали не с оригинальным окном, а его копией).
If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding and replaces it with a ghost window that has the same z-order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window.
Ссылка на документацию, секция Remarks, самый последний абзац.
Кстати, эту функцию можно даже отключить:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting
Узнать, что период, через который окно получает статус неактивного, равен 5 секундам можно тут:
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-ishungappwindow
ссылка на канал | ссылка на группу
👍3🔥3
Dmitry Develop
winAPIWrapperProject.png
Сделал я необходимый минимум обёрток, который занимает 500 строк кода и это только начало.
И написал простой проект с созданием окна.
У моего стиля есть куча недостатков, но он мне всё равно нравится.
Теперь всегда можно единообразно обрабатывать ошибку, не обращая внимания, что это за функция.
Также нужно будет скоро начать писать тесты для всех этих функций.
Над этим проектом работаю только я, поэтому у меня нет привычки писать тесты.
Хотя в прошлом уже были случаи, когда в своей стандартной библиотеке я изменял логику работы какой-то фундаментальной функции, а потом ломалась какая-то другая зависимая функция.
ссылка на канал | ссылка на группу
И написал простой проект с созданием окна.
У моего стиля есть куча недостатков, но он мне всё равно нравится.
Теперь всегда можно единообразно обрабатывать ошибку, не обращая внимания, что это за функция.
Также нужно будет скоро начать писать тесты для всех этих функций.
Над этим проектом работаю только я, поэтому у меня нет привычки писать тесты.
Хотя в прошлом уже были случаи, когда в своей стандартной библиотеке я изменял логику работы какой-то фундаментальной функции, а потом ломалась какая-то другая зависимая функция.
ссылка на канал | ссылка на группу
👍1
Dmitry Develop
winAPIWrapperDefinition.png
Я довольно консервативен к стилю форматирования кода.
Я всегда писал объявление и определение функций в одну строку, даже с большим количеством параметров.
Но у меня планируется около сотни, а то и более, функций, которые в таком стиле форматирования просто превратятся в кашу (смотри фото в предыдущем посте).
Поэтому я задумался над тем, чтобы немного изменить свой стиль ради удобства.
Что скажете чтобы это:
Превратить в это:
Очень непривычно будет оформлять функции в таком стиле, но читать и работать с таким кодом станет одно удовольствие.
Бонусом я смогу сделать моё любимое выравнивание по левому краю по колонкам отдельно по типам данных, отдельно по названию параметров.
Также вероятность просмотреть и не заметить опечатку или ошибку значительно уменьшается.
ссылка на канал | ссылка на группу
Я всегда писал объявление и определение функций в одну строку, даже с большим количеством параметров.
Но у меня планируется около сотни, а то и более, функций, которые в таком стиле форматирования просто превратятся в кашу (смотри фото в предыдущем посте).
Поэтому я задумался над тем, чтобы немного изменить свой стиль ради удобства.
Что скажете чтобы это:
void CreateWindowExAWrapper(HWND* returnValue, DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam, status_s* status);
Превратить в это:
void CreateWindowExAWrapper
(
HWND* returnValue,
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
status_s* status
);
Очень непривычно будет оформлять функции в таком стиле, но читать и работать с таким кодом станет одно удовольствие.
Бонусом я смогу сделать моё любимое выравнивание по левому краю по колонкам отдельно по типам данных, отдельно по названию параметров.
Также вероятность просмотреть и не заметить опечатку или ошибку значительно уменьшается.
ссылка на канал | ссылка на группу
👍2💊1
Dmitry Develop
createWindowExAWrapper.png
Когда уже сделал обёртку для 23 функций на 1000 строк кода, сделать 24-ую с уже написанной документацией с шаблонами было даже слишком легко и быстро.
Добавил корректировку размера окна, чтобы можно было указывать размер клиентской области.
Пока что мне стиль форматирования и написанный код нравятся, довольно удобно.
(Проверки status в коде пока что нет, чтобы не портить внешний вид кода 😏)
ссылка на канал | ссылка на группу
Добавил корректировку размера окна, чтобы можно было указывать размер клиентской области.
Пока что мне стиль форматирования и написанный код нравятся, довольно удобно.
(Проверки status в коде пока что нет, чтобы не портить внешний вид кода 😏)
ссылка на канал | ссылка на группу
👍2
Dmitry Develop
pythonNTreeDFS.png
Недавно на работе мне поставили задачу написать метод, который должен сделать запрос к API yandex, получить в ответ JSON структуру, обработать её и преобразовать, чтобы потом сохранить это в нашу базу данных.
Условия задачи мне показались совсем несложными, но как же я ошибался...
Я структуры данных посложнее массива не изучал, поэтому задача резко стала очень сложной, когда я понял, что столкнулся с деревом (N tree): практических умений-то нет, ни то что теоретических знаний.
Спустя очень много часов я всё-таки смог написать код обработки, но мне не хотелось писать рекурсивный метод, хотя это была бы самая простая реализация.
Ну, ладно, когда-нибудь потом перепишу этот метод, я всё-таки люблю алгоритмы, но не когда надо здесь и сейчас их изучить и понять).
Я такого говнокода давно не писал).
ссылка на канал | ссылка на группу
Условия задачи мне показались совсем несложными, но как же я ошибался...
Я структуры данных посложнее массива не изучал, поэтому задача резко стала очень сложной, когда я понял, что столкнулся с деревом (N tree): практических умений-то нет, ни то что теоретических знаний.
Спустя очень много часов я всё-таки смог написать код обработки, но мне не хотелось писать рекурсивный метод, хотя это была бы самая простая реализация.
Ну, ладно, когда-нибудь потом перепишу этот метод, я всё-таки люблю алгоритмы, но не когда надо здесь и сейчас их изучить и понять).
Я такого говнокода давно не писал).
ссылка на канал | ссылка на группу
👍2