Добавляем иконку в System Tray
Исходный текст был откомпилирован в Visual C++ 4.2. Выбор данного компилятора ни чем не обоснован, просто мне удобно в нём работать, вот и всё.
А теперь по-порядку. Сразу представлю исходный код , а в конце подробно его прокомментирую. Листинг 1 (status_ico.cpp)
#include <windows.h>Комментарии:
#include <windowsx.h>
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
void WndProc_OnDestroy(HWND hWnd);
void AddStatusIcon(HWND hWnd, DWORD dwMessage);
void HandlePopupMenu (HWND hwnd, POINT point);
#define WM_NOTIFYICONMSG (WM_USER + 2)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASSEX wndclass;
hInst = hInstance;
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "WSCLAS";
if(!RegisterClassEx(&wndclass))
if(!RegisterClass((LPWNDCLASS)&wndclass.style)) return FALSE;
hWnd=CreateWindow("WSCLAS", "", 0, 0, 0, 1, 1, HWND_DESKTOP, NULL, hInst, NULL);
AddStatusIcon(hWnd, NIM_ADD);
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
POINT pt;
case WM_NOTIFYICONMSG:
switch(lParam) {
case WM_LBUTTONDBLCLK:
MessageBox(NULL, "Двойной щелчок по иконке", "Сообщение от иконки", MB_OK);
break;
case WM_RBUTTONDOWN: // нажатие на иконку правой кнопкой мыши
GetCursorPos(&pt); //вычисляем текущее положение курсора
HandlePopupMenu (hWnd, pt); //рисуем меню от координат курсора
break;
default:
break;
}
break;
HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate); //стандартный обработчик создания окна
HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy); //стандартный обработчик уничтожения окна
default:
return(DefWindowProc(hWnd, msg, wParam, lParam));
}
return 0;
}
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
return TRUE;
}
void WndProc_OnDestroy(HWND hWnd)
{
PostQuitMessage(0);
}
void AddStatusIcon(HWND hWnd, DWORD dwMessage)
{
HICON hStatusIcon; // Хэндл иконки в статус-баре
LPCSTR pszIDStatusIcon; // Указатель на Иконку в статус-баре
NOTIFYICONDATA tnd;
pszIDStatusIcon = MAKEINTRESOURCE(IDI_ICON1);
hStatusIcon = LoadIcon( hInst,pszIDStatusIcon );
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = hWnd;
tnd.uID = 1;
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
tnd.uCallbackMessage = WM_NOTIFYICONMSG;
tnd.hIcon = hStatusIcon;
lstrcpyn(tnd.szTip, "Пример", sizeof(tnd.szTip));
Shell_NotifyIcon( dwMessage, &tnd );
}
void HandlePopupMenu (HWND hWnd, POINT point)
{
HMENU hMenu;
HMENU hMenuTrackPopup;
LPCSTR pszIDMenu;
pszIDMenu = MAKEINTRESOURCE(IDM_POPUPMENU1);
hMenu = LoadMenu (hInst, pszIDMenu);
if (!hMenu) return;
hMenuTrackPopup = GetSubMenu (hMenu, 0);
TrackPopupMenu (hMenuTrackPopup, 0, point.x, point.y, 0, hWnd, NULL);
DestroyMenu (hMenu);
}
В самом начале идёт обязательное включение Виндузовых заголовков (как и в любой программе под Windows. Далее я объявляю используемые в программе функции. Обычно такое объявление делается в файле-заголовке (.h) , но когда функций не так много, то я обычно эти описания вставляю в главный файл. Описание главной функции WinMain не нужно добавлять.
Далее идёт определение идентификатора сообщения (#define WM_NOTIFYICONMSG (WM_USER + 2)), которое будет поступать от иконки. Впринципе этому идентификатору можно приствоить любое число, но чтобы быть уверенным, что такое число не используется каким-нибудь другим идентификатором, обычно присваивают WM_USER + n , где n - любое число.
Далее идёт основная функция, с которой начинает работать данная программа. Вообще-то в разных версиях API данная функция описывается по-разному. Например в API 16 её описание начинается с дескриптора PASCAL, но в API 32 - это WINAPI.
Следующим шагом программа создаёт окно, но не простое, а невидимое. То есть запущенная программа не будет видна в панели задач. Вообще процесс создания окна в Windows состоит из двух шагов. Первый ( RegisterClassEx(&wndclass) )- это регистрация класса окна в системе, и второй ( hWnd=CreateWindow(.... )- создание непосредственно окна. Параметр wndclass.lpfnWndProc = (WNDPROC)WndProc; указывает классу окна, что все сообщения, поступающие окну будут обрабатываться функцией WndProc. Все описания данных функций и их входных параметров Вы можете найти во многих книгах по программированию в API 32, поэтому здесь я не буду отвлекаться на эти вопросы.
Далее вызывается функция AddStatusIcon(hWnd, NIM_ADD) , задача которой заключается в том, чтобы нарисовать в панели статуса нужную иконку. Параметр hWnd означает, что все сообщения (...нажатия на ней мышкой...) от иконки будут передаваться главному окну нашей программы. Параметр NIM_ADD указывает функции, что иконка будет добавлена в статус-бар. Этот параметр может принимать значение NIM_MODIFY, означающий, что уже существующая иконка будет изменена или будет изменена её информационная надпись, которая появляется при навидении на иконку мышкой.
И наконец функция WinMain завершается бесконечным циклом, задача которого обрабатывать сообщения, поступающие главному окну. Естевственно этот цикл не такой уж и бесконечный, при поступлении определённых сообщений (например WM_CLOSE ) цикл может звершиться, и соответственно завершится сама программа. Например, если послать окну сообщение WM_DESTROY , то функция обработки оконных сообщений ( WndProc ) вызовет WndProc_OnDestroy , и наша программа завершит свою работу в системе. Соответственно при создании окна окно получает сообщение WM_CREATE и оконная функция вызывает WndProc_OnCreate(). Ещё можно добавить, что все неопознанные сообщения, или те, для которых Вы не предусмотрите обработчики сообщений напрвляются DefWindowProc(hWnd, msg, wParam, lParam) , вызов каторой находится в конце WndProc.