⬆️ ⬇️

C ++ notification area icon



Let's write together a small utility in C ++. Let our program track something in the system and show an icon in the notification area when something happened. For example, the check will be for the presence of a file or a mounted drive. No file - one icon, a file appeared - the icon has changed.

I have such an icon that monitors the connection of an encrypted disk. Maybe someone needs to monitor the appearance of a protocol file with errors or the presence of a connection to a network drive.



For development, you can use the free Visual C ++ Express Edition.

Choose to create a new Win32 Project and name the project “Tray.” Click the Next button to go to the project settings and check the Empty Project box.



Let's start with a greeting



Add a file (.cpp) to the C ++ project and name it “Tray”. Let's start with a practically minimal program. Try to enter its text and run.



#include <windows.h> #include <tchar.h> //   int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int) { MessageBox(0, TEXT(""), TEXT(""), 0); return 0; } 


Calling MessageBox () shows a greeting, and then the program exits. If you succeed, move on.

')

Main window



We don’t need a window in principle - the user interface is represented by an icon. But a window is required to create an icon and process its messages.

To create a window, you need to define the WndProc () message handling function, register the window class in the WNDCLASSEX structure, and actually create the window using the CreateWindowEx () function.



 #include <windows.h> #include <tchar.h> //   LRESULT CALLBACK WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //    case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(window, message, wParam, lParam); } return 0; } //   int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int) { //    WNDCLASSEX main = { 0 }; main.cbSize = sizeof(WNDCLASSEX); main.hInstance = instance; main.lpszClassName = TEXT("Main"); main.lpfnWndProc = WndProc; RegisterClassEx(&main); //    HWND window = CreateWindowEx(0, TEXT("Main"), NULL, 0, 0, 0, 0, 0, NULL, NULL, instance, NULL); MessageBox(0, TEXT(""), TEXT(""), 0); return 0; } 


Our main window will never be displayed, so all the parameters are filled to the minimum. Try to start the program - nothing has changed in its work.



Display icon



The actual output of the icon is performed by the Shell_NotifyIcon () function. She needs the NOTIFYICONDATA structure as a parameter, and this structure should have a window handle.

We will store the NOTIFYICONDATA structure in the global variable Icon, since She still useful to us. We will create the icon before the welcome window, and before leaving the program, delete it.



 #include <windows.h> #include <tchar.h> //   NOTIFYICONDATA Icon = { 0 }; //   //   ... //   int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int) { //    ... //    ... //   Icon.cbSize = sizeof(NOTIFYICONDATA); Icon.hWnd = window; Icon.uVersion = NOTIFYICON_VERSION; Icon.uCallbackMessage = WM_USER; Icon.hIcon = LoadIcon(NULL, IDI_SHIELD); Icon.uFlags = NIF_MESSAGE | NIF_ICON; Shell_NotifyIcon(NIM_ADD, &Icon); MessageBox(0, TEXT(""), TEXT(""), 0); //   Shell_NotifyIcon(NIM_DELETE, &Icon); return 0; } 


Now run the program for execution. Our icon appears on startup and then disappears when you click OK in the dialog box. What the icon looks like is indicated in the hIcon parameter. We put the standard icon IDI_SHIELD there using the LoadIcon () function.



Message loop



It is time to remove the welcome dialog. When you start the program, we will only have an icon in the notification area. Exit the program will do by right-clicking on the icon. A window should appear asking you to close the program.

Processing the message from the icon that the mouse button is pressed will be added to the message handling function. And we will insert the message processing loop where the greeting was.



 ... //   LRESULT CALLBACK WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //    case WM_USER: if (lParam == WM_RBUTTONDOWN) if (MessageBox(NULL, TEXT(" ?"), TEXT("Tray"), MB_YESNO) == IDYES) DestroyWindow(window); break; //    ... } return 0; } //   int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int) { //    ... //    ... //   ... //    MSG message; while (GetMessage(&message, NULL, 0, 0)) { TranslateMessage(&message); DispatchMessage(&message); } //   Shell_NotifyIcon(NIM_DELETE, &Icon); return 0; } 


After starting the program shows only the icon, waiting for a mouse button.



Timer check



Now it remains to do the things for which everything was started. Once a second, a file will be checked. If such a file appears, the icon should change. The timer is activated by the SetTimer () function, for which the time interval should be specified in milliseconds.

The function itself of checking the existence of a file can be implemented in various ways. Here's a way to check through getting attributes.



 /    bool FileExists(PTSTR path) { return GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES; } 


If the GetFileAttributes () function fails to read the file attributes in the specified path, then there is no file. As a path, you can specify the path to the file, and then we check the existence of the file. And if you specify the path to the disk, then we check the presence of the disk. Suppose we check for the presence of the “P:” drive.

In order not to redraw the icon every time, we will save the previous state in the global variable, and we will call Shell_NotifyIcon () with the new image only if the state has changed. Here is the full version of the program.



 #include <windows.h> #include <tchar.h> //   NOTIFYICONDATA Icon = { 0 }; //   bool State = false; //   //    bool FileExists(PTSTR path) { return GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES; } //   LRESULT CALLBACK WndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //    case WM_TIMER: { bool check = FileExists(TEXT("P:\\")); if (State != check) { if (State) Icon.hIcon = LoadIcon(NULL, IDI_SHIELD); else Icon.hIcon = LoadIcon(NULL, IDI_WARNING); Icon.uFlags = NIF_ICON; Shell_NotifyIcon(NIM_MODIFY, &Icon); State = check; } break; } //    case WM_USER: if (lParam == WM_RBUTTONDOWN) if (MessageBox(NULL, TEXT(" ?"), TEXT("Tray"), MB_YESNO) == IDYES) DestroyWindow(window); break; //    case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(window, message, wParam, lParam); } return 0; } //   int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR, int) { //    WNDCLASSEX main = { 0 }; main.cbSize = sizeof(WNDCLASSEX); main.hInstance = instance; main.lpszClassName = TEXT("Main"); main.lpfnWndProc = WndProc; RegisterClassEx(&main); //    HWND window = CreateWindowEx(0, TEXT("Main"), NULL, 0, 0, 0, 0, 0, NULL, NULL, instance, NULL); //   Icon.cbSize = sizeof(NOTIFYICONDATA); Icon.hWnd = window; Icon.uVersion = NOTIFYICON_VERSION; Icon.uCallbackMessage = WM_USER; Icon.hIcon = LoadIcon(NULL, IDI_SHIELD); Icon.uFlags = NIF_MESSAGE | NIF_ICON; Shell_NotifyIcon(NIM_ADD, &Icon); //   SetTimer(window, 0, 1000, NULL); //    MSG message; while (GetMessage(&message, NULL, 0, 0)) { TranslateMessage(&message); DispatchMessage(&message); } //   Shell_NotifyIcon(NIM_DELETE, &Icon); return 0; } 


In the Release configuration, the Tray.exe program turned out to be 8 KB in size.

Source: https://habr.com/ru/post/185252/



All Articles