xref: /reactos/dll/win32/shell32/systray.cpp (revision d5b576b2)
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_notify);
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 }
208