Why aren't Shell_NotifyIcon balloon tips working? - c++

According to everything I've seen, the following C++ program should be displaying a balloon tool tip from the tray icon when I left-click in the application window, yet it's not working. Can anyone tell me what I'm missing?
This is on XP with version 6.0 of Shell32.dll (verified with DllGetVersion).
Thanks!
#include "stdafx.h"
#include "shellapi.h"
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "sysTrayTest";
RegisterClass(&wc);
HWND hWnd = CreateWindow("sysTrayTest", "",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 500, 500,
NULL, NULL, hInstance, NULL);
if (hWnd)
{
ShowWindow(hWnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 1;
Shell_NotifyIcon(NIM_DELETE, &nid);
PostQuitMessage(0);
}
break;
case WM_CREATE:
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER + 200;
nid.hIcon = LoadIcon(NULL, IDI_INFORMATION);
lstrcpy (nid.szTip, "Test Tip");
Shell_NotifyIcon(NIM_ADD, &nid);
}
break;
case WM_LBUTTONDOWN:
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 1;
nid.uFlags = NIF_INFO;
lstrcpy(nid.szInfo, "Test balloon tip");
lstrcpy(nid.szInfoTitle, "Test Title");
nid.dwInfoFlags = NIIF_INFO;
nid.uTimeout = 15000;
Shell_NotifyIcon(NIM_MODIFY, &nid);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

Bah, I figured it out. For some reason with the headers I have...
sizeof(NOTIFYICONDATA) == 508
whereas...
NOTIFYICONDATA_V3_SIZE == 504
NOTIFYICONDATA_V2_SIZE == 488
NOTIFYICONDATA_V1_SIZE == 88
If I specify either V2 or V3 instead of sizeof(NOTIFYICONDATA) the balloon tips show up just fine.

Have you checked in the registry under ...
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
... for EnableBalloonTips? It's something very common for users to turn off.

The problem is that you are assuming Windows is going to send you a WM_LBUTTONDOWN when the user click on the icon, but that is not correct. WM_LBUTTONDOWN is sent only when the user clicks inside the hWnd's client area, if you read carefully the documentation of NOTIFYICONDATA you will realize that when the user clicks the icon Windows will send you a WM_USER+20 message (according to your code) and in the lParam paramter you will get the WM_LBUTTONDOWN notification.

Related

Winapi: Child window that is registered and not created gives the parent window it's background color

Im trying to create a windows application with winapi. So i want to have one parent window and one child window in it. Here is my code:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
const char szChildName[] = "Child window title";
const UINT PM_COLORCHANGED = WM_APP + 1;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASS wc;
char szAppName[] = "title";
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = (LPCWSTR)szAppName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.hIcon = NULL;
wc.lpfnWndProc = ChildProc;
wc.lpszClassName = (LPCWSTR)szChildName;
RegisterClass(&wc);
hWnd = CreateWindow((LPCWSTR)szAppName,
(LPCWSTR)szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hChild;
static RECT rect;
switch (message)
{
case WM_CREATE:
{
GetClientRect(hWnd, &rect);
hChild = CreateWindow((LPCWSTR)szChildName,
NULL,
WS_CHILD | WS_VISIBLE | WS_DLGFRAME,
5,
rect.bottom - 35,
rect.right - 10,
30,
hWnd,
NULL,
((LPCREATESTRUCT)lParam)->hInstance,
NULL);
return 0;
}
case WM_SIZE:
{
return 0;
}
case PM_COLORCHANGED:
{
return 0;
}
case WM_PAINT:
{
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
{
return 0;
}
case WM_LBUTTONDOWN:
{
return 0;
}
case WM_PAINT:
{
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
This works perfect, so i see the child window at the bottom of the application.
But, instead of WNDCLASS I want to use WNDCLASSEX, which forces me to use RegisterClassEx() to register the windows. Also I want to use CreateWindowEx, my code looks like that:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
const char szChildName[] = "Child name";
const UINT PM_COLORCHANGED = WM_APP + 1;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASSEX wc;
char szAppName[] = "The Child Window";
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.lpszClassName = (LPCWSTR)szAppName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wc);
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.hIcon = NULL;
wc.lpfnWndProc = (WNDPROC)ChildProc;
wc.lpszClassName = (LPCWSTR)szChildName;
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL,
wc.lpszClassName,
L"parent window",
(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU),
200,
150,
1000,
1000,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hChild;
static RECT rect;
switch (message)
{
case WM_CREATE:
{
GetClientRect(hWnd, &rect);
hChild = CreateWindowEx(NULL,
(LPCWSTR)szChildName,
L"child window",
(WS_CHILD | WS_VISIBLE | WS_DLGFRAME),
200,
150,
200,
200,
hWnd,
NULL,
((LPCREATESTRUCT)lParam)->hInstance,
NULL
);
return 0;
}
case WM_SIZE:
{
return 0;
}
case PM_COLORCHANGED:
{
return 0;
}
case WM_PAINT:
{
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
{
return 0;
}
case WM_LBUTTONDOWN:
{
return 0;
}
case WM_PAINT:
{
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
The problem: Now i only see the color of the child window, so the whole application has this background color of the child window, so somehow the pc repainted everything in the color of the child window. (no child window is even visible, everything i see is only this LTGRAY_Brush of the child window.
Weird is: If i delete the line where the child window is created, so this line:
hChild = CreateWindowEx(NULL,
(LPCWSTR)szChildName,
L"child window",
(WS_CHILD | WS_VISIBLE | WS_DLGFRAME),
200,
150,
200,
200,
hWnd,
NULL,
((LPCREATESTRUCT)lParam)->hInstance,
NULL
then even now, the background color gets the same as the one that i registered the child class with. Altough the child class hasn't been created. Thanks for your help.

Adding Multiple Windows to WinAPI Application

I am building an app with WinAPI that consists of basically two main parts: a panel on the left hand that is always shown and an area on the right that changes based on which screen is shown. Currently the left-hand, static area is just being drawn onto the main window; however, for I don't believe that I can simply draw the right area onto the main window as it needs to change. Therefore, I believe that I need to create windows there and just control what is shown by controlling its visibility. I read a lot about the Multiple Document Interface in the MSDN, but I'm not sure if that is what I am looking for. Specifically, I don't want the child windows to act like real windows, meaning I don't want them to have a title or icon or be able to be minimized, closed, resized, or moved. Basically, I want them to just be frames that hold controls/D2D geometry. What would be the best way to go about implementing this?
As Remy said, you only need to re-register a new window and then create it as a subclass in the main window. You don't need to set the title and maximize and minimize buttons in setting the style, and you can also decide by yourself whether you need to deal with the WNDPROC function of the subclass.
Here is a sample(In order to display the child window, I set its background to black.):
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK cldWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szCmdLine, _In_ int iCmdShow)
{
static TCHAR szAppName[] = TEXT("hello windows");
static TCHAR cldwndName[] = TEXT("test app");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
100,
100,
800,
600,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
WNDCLASS cldclass;
cldclass.style = CS_HREDRAW | CS_VREDRAW;
cldclass.lpfnWndProc = cldWndProc;
cldclass.cbClsExtra = 0;
cldclass.cbWndExtra = 0;
cldclass.hInstance = hInstance;
cldclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
cldclass.hCursor = LoadCursor(NULL, IDC_ARROW);
cldclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
cldclass.lpszMenuName = NULL;
cldclass.lpszClassName = cldwndName;
if (!RegisterClass(&cldclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
HWND hwnd1 = CreateWindow(cldwndName,
NULL,
WS_CHILD|WS_VISIBLE,
400,
200,
200,
300,
hwnd,
NULL,
hInstance,
NULL);
ShowWindow(hwnd1, iCmdShow);
UpdateWindow(hwnd1);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK cldWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
It works for me:

Detect mouse click on application and call function

My requirement is that:
I want to detect left mouse click event and take some action. Mouse click should get detected only on the given application if mouse click is on other application then it should not take action.
Currently I am using :
mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);
POINT p;
if (wParam == WM_LBUTTONDOWN)
{
// MB1 click
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
but it is working for mouse click anywhere on the desktop screen. I want to detect it for current application only.
If you have Win32 application. Probably you can handle mouse events in your Window proc itself.
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
// your code
return 0;
case WM_LBUTTONUP:
// your code
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Window creation:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Connect");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Connect−the−Points Mouse Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

winapi display icon on the screen with mouseclick event

In WINAPI, I have seen a virus which displays an icon on the x-y of the mouse whenever a mouse click event occurs (the red one which has a white X inside). How do I show an icon like that whenever I click the mouse? I know how to hook mouse clicks with setwindowshookex. Is there a function like iconshow as I have shown below.
HHOOK msHOOK;
//getting the icon let's say from a rc file
HICON redIcon;
msHOOK = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, NULL, 0);
LRESULT CALLBACK mouseProc(int nCode, WPARAM wPar, LPARAM lPar){
IconShow(NULL, redIcon, xofMouse, yofMouse, 0);
MessageBox(NULL, "Icon showed", "Cap", 0);
return CallNextHookEx(NULL, nCode, wPar, lPar);
}
while(GetMessage(&msg, NULL, 0, 0) > 0){
TranslateMessage(&msg);
}
Thanks
UPDATE
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow){
HWND wnd;
MSG msg;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = "ClassName";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, "ClassName", "ss", NULL, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, NULL, NULL, NULL, NULL);
SetLayeredWindowAttributes(wnd, RGB(255, 255, 0), 20, LWA_COLORKEY);
ShowWindow(wnd, SW_SHOW);
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
//stuff here
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
You would have to create your own always-on-top window to display the cursor.
It probably needs to be a layered window so you can use UpdateLayeredWindow() and a 32-bit RGBA bitmap to get every cursor looking correct.
If you are only using a specific cursor you control, and it does not have an alpha channel, you can save yourself some work by painting the image as-is onto your window in a WM_ERASEBKGND or WM_PAINT message handler, and then use SetLayeredWindowAttributes(..., LWA_COLORKEY, ...) to set the window's transparency color.

C++ event handling for click on notification area Icon Windows

I want to achieve some kind of event handling for Windows. I have a program, that has a symbol in the Notification Area (System Tray) and I want the programm to show up again, when the user clicks on the Icon. Is there a simple Way to implement that in c++ as an Event? I have only found ways to this in C#.
It is a console Application and I want to change as few things as possible. But there is no WndProc handler for Console Application as far as I can tell.
Why no WndProc? Console application is a perfect win32 application, and it can use anything which non-console application can use.
Here's a simple, but a bit long example.
#include <windows.h>
#include <shellapi.h>
#include <iostream>
#include <cstring>
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
BOOL WINAPI ConsoleRoutine(DWORD dwCtrlType);
LPCWSTR lpszClass = L"__hidden__";
int main()
{
HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASS wc;
HWND hWnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = nullptr;
wc.hCursor = nullptr;
wc.hIcon = nullptr;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = lpszClass;
wc.lpszMenuName = nullptr;
wc.style = 0;
RegisterClass(&wc);
hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, hInstance, nullptr);
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static NOTIFYICONDATA nid;
switch (iMsg)
{
case WM_CREATE:
std::memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hWnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_APP + 1;
nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
lstrcpy(nid.szTip, L"con-notify");
Shell_NotifyIcon(NIM_ADD, &nid);
Shell_NotifyIcon(NIM_SETVERSION, &nid);
return 0;
case WM_APP + 1:
switch (lParam)
{
case WM_LBUTTONDBLCLK:
std::cout << "notify dblclk" << std::endl;
break;
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
break;
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
MessageBox(nullptr, L"asdf", L"asdf", MB_OK);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,iMsg,wParam,lParam);
}
You probably want not to mess up your console program with message loop. If so, you can put notification code into another thread.