[SHELL32] Rewrite the wrapping code for shell taskbar notifications.
[reactos.git] / dll / win32 / shell32 / systray.cpp
1 /*
2 * Copyright 2004 Martin Fuchs
3 * Copyright 2018 Hermes Belusca-Maito
4 *
5 * Pass on icon notification messages to the systray implementation
6 * in the currently running shell.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "precomp.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 /*************************************************************************
28 * Shell_NotifyIcon [SHELL32.296]
29 * Shell_NotifyIconA [SHELL32.297]
30 */
31 BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid)
32 {
33 NOTIFYICONDATAW nidW;
34 DWORD cbSize, dwValidFlags;
35
36 /* Initialize and capture the basic data fields */
37 ZeroMemory(&nidW, sizeof(nidW));
38 nidW.cbSize = sizeof(nidW); // Use a default size for the moment
39 nidW.hWnd = pnid->hWnd;
40 nidW.uID = pnid->uID;
41 nidW.uFlags = pnid->uFlags;
42 nidW.uCallbackMessage = pnid->uCallbackMessage;
43 nidW.hIcon = pnid->hIcon;
44
45 /* Validate the structure size and the flags */
46 cbSize = pnid->cbSize;
47 dwValidFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
48 if (cbSize == sizeof(NOTIFYICONDATAA))
49 {
50 nidW.cbSize = sizeof(nidW);
51 dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID /* | NIF_REALTIME | NIF_SHOWTIP */;
52 }
53 else if (cbSize == NOTIFYICONDATAA_V3_SIZE)
54 {
55 nidW.cbSize = NOTIFYICONDATAW_V3_SIZE;
56 dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID;
57 }
58 else if (cbSize == NOTIFYICONDATAA_V2_SIZE)
59 {
60 nidW.cbSize = NOTIFYICONDATAW_V2_SIZE;
61 dwValidFlags |= NIF_STATE | NIF_INFO;
62 }
63 else // if cbSize == NOTIFYICONDATAA_V1_SIZE or something else
64 {
65 if (cbSize != NOTIFYICONDATAA_V1_SIZE)
66 {
67 WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
68 cbSize, NOTIFYICONDATAA_V1_SIZE);
69 cbSize = NOTIFYICONDATAA_V1_SIZE;
70 }
71 nidW.cbSize = NOTIFYICONDATAW_V1_SIZE;
72 }
73 nidW.uFlags &= dwValidFlags;
74
75 /* Capture the other data fields */
76
77 if (nidW.uFlags & NIF_TIP)
78 {
79 /*
80 * Depending on the size of the NOTIFYICONDATA structure
81 * we should convert part of, or all the szTip string.
82 */
83 if (cbSize <= NOTIFYICONDATAA_V1_SIZE)
84 {
85 #define NIDV1_TIP_SIZE_A (NOTIFYICONDATAA_V1_SIZE - FIELD_OFFSET(NOTIFYICONDATAA, szTip))/sizeof(CHAR)
86 MultiByteToWideChar(CP_ACP, 0, pnid->szTip, NIDV1_TIP_SIZE_A,
87 nidW.szTip, _countof(nidW.szTip));
88 /* Truncate the string */
89 nidW.szTip[NIDV1_TIP_SIZE_A - 1] = 0;
90 #undef NIDV1_TIP_SIZE_A
91 }
92 else
93 {
94 MultiByteToWideChar(CP_ACP, 0, pnid->szTip, -1,
95 nidW.szTip, _countof(nidW.szTip));
96 }
97 }
98
99 if (cbSize >= NOTIFYICONDATAA_V2_SIZE)
100 {
101 nidW.dwState = pnid->dwState;
102 nidW.dwStateMask = pnid->dwStateMask;
103 nidW.uTimeout = pnid->uTimeout;
104 nidW.dwInfoFlags = pnid->dwInfoFlags;
105
106 if (nidW.uFlags & NIF_INFO)
107 {
108 MultiByteToWideChar(CP_ACP, 0, pnid->szInfo, -1,
109 nidW.szInfo, _countof(nidW.szInfo));
110 MultiByteToWideChar(CP_ACP, 0, pnid->szInfoTitle, -1,
111 nidW.szInfoTitle, _countof(nidW.szInfoTitle));
112 }
113 }
114
115 if ((cbSize >= NOTIFYICONDATAA_V3_SIZE) && (nidW.uFlags & NIF_GUID))
116 nidW.guidItem = pnid->guidItem;
117
118 if (cbSize >= sizeof(NOTIFYICONDATAA))
119 nidW.hBalloonIcon = pnid->hBalloonIcon;
120
121 /* Call the unicode function */
122 return Shell_NotifyIconW(dwMessage, &nidW);
123 }
124
125 /*************************************************************************
126 * Shell_NotifyIconW [SHELL32.298]
127 */
128 BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW pnid)
129 {
130 BOOL ret = FALSE;
131 HWND hShellTrayWnd;
132 DWORD cbSize, dwValidFlags;
133 TRAYNOTIFYDATAW tnid;
134 COPYDATASTRUCT data;
135
136 /* Find a handle to the shell tray window */
137 hShellTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
138 if (!hShellTrayWnd)
139 return FALSE; // None found, bail out
140
141 /* Validate the structure size and the flags */
142 cbSize = pnid->cbSize;
143 dwValidFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
144 if (cbSize == sizeof(NOTIFYICONDATAW))
145 {
146 dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID /* | NIF_REALTIME | NIF_SHOWTIP */;
147 }
148 else if (cbSize == NOTIFYICONDATAW_V3_SIZE)
149 {
150 dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID;
151 }
152 else if (cbSize == NOTIFYICONDATAW_V2_SIZE)
153 {
154 dwValidFlags |= NIF_STATE | NIF_INFO;
155 }
156 else // if cbSize == NOTIFYICONDATAW_V1_SIZE or something else
157 {
158 if (cbSize != NOTIFYICONDATAW_V1_SIZE)
159 {
160 WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
161 cbSize, NOTIFYICONDATAW_V1_SIZE);
162 cbSize = NOTIFYICONDATAW_V1_SIZE;
163 }
164 }
165
166 /* Build the data structure */
167 ZeroMemory(&tnid, sizeof(tnid));
168 tnid.dwSignature = NI_NOTIFY_SIG;
169 tnid.dwMessage = dwMessage;
170
171 /* Copy only the needed data, everything else is zeroed out */
172 CopyMemory(&tnid.nid, pnid, cbSize);
173 /* Adjust the size (the NOTIFYICONDATA structure is the full-fledged one) and the flags */
174 tnid.nid.cbSize = sizeof(tnid.nid);
175 tnid.nid.uFlags &= dwValidFlags;
176
177 /* Be sure the szTip member (that could be cut-off) is correctly NULL-terminated */
178 if (tnid.nid.uFlags & NIF_TIP)
179 {
180 if (cbSize <= NOTIFYICONDATAW_V1_SIZE)
181 {
182 #define NIDV1_TIP_SIZE_W (NOTIFYICONDATAW_V1_SIZE - FIELD_OFFSET(NOTIFYICONDATAW, szTip))/sizeof(WCHAR)
183 tnid.nid.szTip[NIDV1_TIP_SIZE_W - 1] = 0;
184 #undef NIDV1_TIP_SIZE_W
185 }
186 else
187 {
188 tnid.nid.szTip[_countof(tnid.nid.szTip) - 1] = 0;
189 }
190 }
191
192 /* Be sure the info strings are correctly NULL-terminated */
193 if (tnid.nid.uFlags & NIF_INFO)
194 {
195 tnid.nid.szInfo[_countof(tnid.nid.szInfo) - 1] = 0;
196 tnid.nid.szInfoTitle[_countof(tnid.nid.szInfoTitle) - 1] = 0;
197 }
198
199 /* Send the data */
200 data.dwData = 1;
201 data.cbData = sizeof(tnid);
202 data.lpData = &tnid;
203 if (SendMessageW(hShellTrayWnd, WM_COPYDATA, (WPARAM)pnid->hWnd, (LPARAM)&data))
204 ret = TRUE;
205
206 return ret;
207 }