Приветствую читателя этой статьи. Я студент, учусь по направлению «Приборостроение», но большую часть времени занимаюсь программированием. Все таки это меня привлекает больше. Задумывался по поводу смены ОС на Arch Linux, но пока отложил эту затею в долгий ящик. Смотрел различные ролики на YouTube и заметил, что многие пользователи ставят себе Polybar, в котором можно легко настраивать информацию, выводимую на нечто похожее на Панель задач в Windows. Тогда я подумал «А почему бы не сделать такое в винде?!» и сразу начал гуглить что к чему. Попытался найти готовые аналоги, но ничего не впечатлило, поэтому решил написать свою программу на C++.
Заранее хочу предупредить, это моя первая статья, поэтому было бы неплохо получить достаточно аргументированной критики. Может я что-то пропустил или недостаточно понятно объяснил, жду фидбека.
Выглядеть оно будет примерно так:
При наведении на иконку ОЗУ мы увидим загрузку памяти в GB и %, а на иконку CPU — загрузку процессора в процентах. Цвет иконку cpu будет меняться в зависимости от загрузки:
-
Зеленый — загрузка <25%
-
Оранжевый — загрузка 25-50%
-
Красный — >50%
Приступаем к разработке
Для начала создадим оконное приложение в VS и удалим все лишнее оттуда из .cpp и .rc файлов.
Подготовим иконки и добавим их в папку проекта.
Эту иконку я нашел на сайте -> https://www.flaticon.com/ru/free-icons/prosessor. Там же можно найти и иконку RAM. Они там в черном цвете, поэтому можно в обычной Paint залить их в нужный цвет, а через онлайн ресурсы конвертировать в .ico. Иконки можно подобрать любые, которые вам нравятся
В файле .rc (ресурсов) добавляем иконки следующим образом, чтобы их не пришлось тянуть рядом с нашим готовым exeшником.
IDR_CPUICON1 ICON "cpu4.ico"
IDR_CPUICON2 ICON "cpu6.ico"
IDR_CPUICON3 ICON "cpu5.ico"
IDR_RAMICON0 ICON "ram0.ico"
А в файле Recource.h добавляем им idшники#define IDR_CPUICON1131
#define IDR_CPUICON2132
#define IDR_CPUICON3133
#define IDR_RAMICON0134
Создадим 2 структуры, которые как раз таки и отвечают за иконку программы в таск баре:
NOTIFYICONDATA cpu_status_icon;
NOTIFYICONDATA ram_status_icon;
Подробнее о структуре -> https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataa
И 2 хендлера таймеров, которые будут работать в параллельных потоках, таким образом вывод информации будет независимый:
HANDLE htimer_ram = NULL;
HANDLE htimer_cpu = NULL;
void CALLBACK TimerRAM(PVOID pVoid, BOOLEAN TimerOrWaitFired) { static wchar_t ram_info[128]; if (GlobalMemoryStatusEx(&mem_info)) { static uint16_t totalPhys = (uint16_t)ceil((float)mem_info.ullTotalPhys / 1024 / 1024 / 1024); float physUsed = (float)(mem_info.ullTotalPhys - mem_info.ullAvailPhys) / 1024 / 1024 / 1024; uint16_t usagePercent = mem_info.dwMemoryLoad; swprintf(ram_info, 128, L"%.2f\\%u Gb %u%%", physUsed, totalPhys, usagePercent); lstrcpy(ram_status_icon.szTip, ram_info); Shell_NotifyIcon(NIM_MODIFY, &ram_status_icon); } } void CALLBACK TimerCPU(PVOID pVoid, BOOLEAN TimerOrWaitFired) { static wchar_t cpu_inf[8]; double cpu_total = GetCPULoad(); if (cpu_total < 25) cpu_status_icon.hIcon = cpu_icons[0]; else if (cpu_total < 50) cpu_status_icon.hIcon = cpu_icons[1]; else if (cpu_total >= 50) cpu_status_icon.hIcon = cpu_icons[2]; swprintf(cpu_inf, 8, L"%.2f %%", cpu_total); lstrcpy(cpu_status_icon.szTip, cpu_inf); Shell_NotifyIcon(NIM_MODIFY, &cpu_status_icon); }
Обновлять информацию об ОЗУ будет сразу в таймере. Функция загрузки проца выглядит следующим образом:
float GetCPULoad() { static FILETIME idleTimePrev = {}, kernelTimePrev = {}, userTimePrev = {}; FILETIME idleTime, kernelTime, userTime; if (!GetSystemTimes(&idleTime, &kernelTime, &userTime)) return 0.0; auto toUInt64 = [](FILETIME ft) { return ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime; }; uint64_t idleDiff = toUInt64(idleTime) - toUInt64(idleTimePrev); uint64_t kernelDiff = toUInt64(kernelTime) - toUInt64(kernelTimePrev); uint64_t userDiff = toUInt64(userTime) - toUInt64(userTimePrev); idleTimePrev = idleTime; kernelTimePrev = kernelTime; userTimePrev = userTime; uint64_t total = kernelDiff + userDiff; return total ? (1.0 - (float)idleDiff / total) * 100.0 : 0.0; }
Затем инициализируем все необходимые переменные, таймеры и т.п.:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // Сохранить маркер экземпляра в глобальной переменной HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } cpu_icons[0] = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDR_CPUICON1), IMAGE_ICON, 64, 64, 0); cpu_icons[1] = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDR_CPUICON2), IMAGE_ICON, 64, 64, 0); cpu_icons[2] = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDR_CPUICON3), IMAGE_ICON, 64, 64, 0); cpu_status_icon.cbSize = sizeof(NOTIFYICONDATA); cpu_status_icon.hWnd = hWnd; cpu_status_icon.uID = 1; cpu_status_icon.hIcon = cpu_icons[0]; lstrcpy(cpu_status_icon.szTip, L"%"); cpu_status_icon.uFlags = NIF_ICON | NIF_TIP; Shell_NotifyIcon(NIM_ADD, &cpu_status_icon); mem_info.dwLength = sizeof(mem_info); ram_status_icon.cbSize = sizeof(NOTIFYICONDATA); ram_status_icon.hWnd = hWnd; ram_status_icon.uID = 2; ram_status_icon.hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDR_RAMICON0), IMAGE_ICON, 64, 64, 0);; lstrcpy(ram_status_icon.szTip, L"%"); ram_status_icon.uFlags = NIF_ICON | NIF_TIP; Shell_NotifyIcon(NIM_ADD, &ram_status_icon); if (!CreateTimerQueueTimer(&htimer_cpu, NULL, TimerCPU, NULL, 1000, 1500, WT_EXECUTEDEFAULT)) { std::cerr << "Error cpu timer\n"; return -1; } if (!CreateTimerQueueTimer(&htimer_ram, NULL, TimerRAM, NULL, 1000, 1500, WT_EXECUTEDEFAULT)) { std::cerr << "Error ram timer\n"; return -2; } return TRUE; }
Не забываем удалить таймеры при завершении работы:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: DeleteTimerQueueTimer(NULL, htimer_cpu, NULL); DeleteTimerQueueTimer(NULL, htimer_ram, NULL); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
ссылка на оригинал статьи https://habr.com/ru/articles/928602/
Добавить комментарий