В настоящее время я изучаю программирование приложений Windows на C++ и экспериментирую с созданием приложения в системной панели. Мне удалось создать значок на панели задач, который при щелчке правой кнопкой мыши отображает окно сообщения и завершает приложение.
Однако после этого я пытаюсь инкапсулировать функциональность системного лотка внутри пользовательского класса и столкнулся с интересным поведением, которое я не до конца понимаю.
Мой код:
Я разбил функциональность на три файлы:
main.cpp
Код: Выделить всё
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
std::unique_ptr driver = std::make_unique(hInstance, nullptr, L"Tree App");
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
// Normally, we'd call DispatchMessage here, but this works without it.
}
if (hAppMutex) CloseHandle(hAppMutex);
return static_cast(msg.wParam);
}
Код: Выделить всё
class windowsSystray :
public SystrayDriver
{
public:
windowsSystray(HINSTANCE hInstance, HWND hWnd, const std::wstring& tooltipText);
~windowsSystray();
private:
void registerWindowClass();
void createSystrayWindow();
void unregisterWindowClass();
void addIcon() override;
void removeIcon() override;
static LRESULT CALLBACK HandleMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static NOTIFYICONDATA nidApp;
static HMENU hPopMenu;
HINSTANCE hInst;
HWND hWnd;
std::wstring tooltipText;
};
Код: Выделить всё
#include "windowsSystray.h"
NOTIFYICONDATA windowsSystray::nidApp = { 0 };
windowsSystray::windowsSystray(HINSTANCE hInstance, HWND hWnd, const std::wstring& tooltipText)
: hInst(hInstance), hWnd(hWnd), tooltipText(tooltipText) {
registerWindowClass();
createSystrayWindow();
addIcon();
}
windowsSystray::~windowsSystray() {
removeIcon();
unregisterWindowClass();
}
void windowsSystray::registerWindowClass() {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = HandleMessage;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SYSTRAY_ICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDM_SYSTRAY);
wc.lpszClassName = L"TreeSystrayClass";
wc.hIconSm = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SYSTRAY_ICON));
RegisterClassEx(&wc);
}
void windowsSystray::createSystrayWindow() {
HICON hMainIcon = LoadIcon(hInst, (LPCTSTR)MAKEINTRESOURCE(IDI_SYSTRAY_ICON));
hWnd = hWnd;
hWnd = CreateWindow(L"TreeSystrayClass", L"treeCollector", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
if (!hWnd) return;
nidApp.cbSize = sizeof(NOTIFYICONDATA); // sizeof the struct in bytes
nidApp.hWnd = (HWND)hWnd; //handle of the window which will process this app. messages
nidApp.uID = IDI_SYSTRAY_ICON; //ID of the icon that willl appear in the system tray
nidApp.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; //ORing of all the flags
nidApp.hIcon = hMainIcon; // handle of the Icon to be displayed, obtained from LoadIcon
nidApp.uCallbackMessage = WM_SYSTRAY;
}
void windowsSystray::unregisterWindowClass() {
UnregisterClass(L"TreeSystrayClass", hInst);
}
void windowsSystray::addIcon() {
Shell_NotifyIcon(NIM_ADD, &nidApp);
}
void windowsSystray::removeIcon() {
Shell_NotifyIcon(NIM_DELETE, &nidApp);
}
LRESULT CALLBACK windowsSystray::HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
int wmId, wmEvent;
//POINT lpClickPoint;
switch (message)
{
case WM_SYSTRAY:
switch (LOWORD(lParam))
{
case WM_RBUTTONDOWN:
MessageBox(hwnd, TEXT("HERE1"), TEXT("Tree"), MB_OK);
Shell_NotifyIcon(NIM_DELETE, &nidApp);
DestroyWindow(hwnd);
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
/*case IDC_MENU_ABOUT:
MessageBox(hwnd, TEXT("HERE2"), TEXT("Tree"), MB_OK);
break;*/
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
Проблема, которую я не понимаю:**
Когда я инкапсулирую функциональность системного лотка внутри класса windowsSystray и запускаю приложение, оно создает значок, а затем остается в цикле GetMessage(), оно работает как положено, хотя я никогда не вызываю DispatchMessage() внутри основного цикла.
Мои вопросы:
Почему Цикл GetMessage() все еще работает без вызова DispatchMessage()? Вызывает ли Windows автоматически обработчик сообщений, если я не вызываю DispatchMessage() явно?
Ожидается ли такое поведение при использовании специального класса для управления системной панелью? Или я упускаю что-то фундаментальное?
Будем благодарны за любую информацию или разъяснения!
Это вторая версия тестирования функциональности системной панели, просто пытаюсь смешать winAPI с POO. В первом не было класса, и он работал точно так же.
При запуске он не расходует память, хотя внутри getmessage пока ничего нет.
Подробнее здесь: https://stackoverflow.com/questions/793 ... -calling-d
Мобильная версия