reactos/dll/win32/shell32/systray.cpp
Hermès Bélusca-Maïto 131678a025
[SHELL32] Rewrite the wrapping code for shell taskbar notifications.
- Introduce the TRAYNOTIFYDATAW structure, as documented by Geoff
  Chappell in "WM_COPYDATA for Taskbar Interface", at
  http://www.geoffchappell.com/studies/windows/shell/shell32/api/shlnot/copydata.htm
  that is the data structure passed between shell32 and explorer for
  communicating shell notify icon information.

- In Shell_NotifyIcon(), correctly capture the (ANSI and) UNICODE
  structures provided by the caller, properly taking into account for
  the different NOTIFYICONDATA structure sizes existing out there.
  The different strings are now properly null-terminated (especially
  szTip if it needs to be truncated out), and the flags validated.

- Remove the now unneeded "SHELL_NotifyIcon()" helper function.

[EXPLORER] Use TRAYNOTIFYDATAW and adjust the callers.
2018-02-04 18:11:50 +01:00

208 lines
6.9 KiB
C++

/*
* Copyright 2004 Martin Fuchs
* Copyright 2018 Hermes Belusca-Maito
*
* Pass on icon notification messages to the systray implementation
* in the currently running shell.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
/*************************************************************************
* Shell_NotifyIcon [SHELL32.296]
* Shell_NotifyIconA [SHELL32.297]
*/
BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid)
{
NOTIFYICONDATAW nidW;
DWORD cbSize, dwValidFlags;
/* Initialize and capture the basic data fields */
ZeroMemory(&nidW, sizeof(nidW));
nidW.cbSize = sizeof(nidW); // Use a default size for the moment
nidW.hWnd = pnid->hWnd;
nidW.uID = pnid->uID;
nidW.uFlags = pnid->uFlags;
nidW.uCallbackMessage = pnid->uCallbackMessage;
nidW.hIcon = pnid->hIcon;
/* Validate the structure size and the flags */
cbSize = pnid->cbSize;
dwValidFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
if (cbSize == sizeof(NOTIFYICONDATAA))
{
nidW.cbSize = sizeof(nidW);
dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID /* | NIF_REALTIME | NIF_SHOWTIP */;
}
else if (cbSize == NOTIFYICONDATAA_V3_SIZE)
{
nidW.cbSize = NOTIFYICONDATAW_V3_SIZE;
dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID;
}
else if (cbSize == NOTIFYICONDATAA_V2_SIZE)
{
nidW.cbSize = NOTIFYICONDATAW_V2_SIZE;
dwValidFlags |= NIF_STATE | NIF_INFO;
}
else // if cbSize == NOTIFYICONDATAA_V1_SIZE or something else
{
if (cbSize != NOTIFYICONDATAA_V1_SIZE)
{
WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
cbSize, NOTIFYICONDATAA_V1_SIZE);
cbSize = NOTIFYICONDATAA_V1_SIZE;
}
nidW.cbSize = NOTIFYICONDATAW_V1_SIZE;
}
nidW.uFlags &= dwValidFlags;
/* Capture the other data fields */
if (nidW.uFlags & NIF_TIP)
{
/*
* Depending on the size of the NOTIFYICONDATA structure
* we should convert part of, or all the szTip string.
*/
if (cbSize <= NOTIFYICONDATAA_V1_SIZE)
{
#define NIDV1_TIP_SIZE_A (NOTIFYICONDATAA_V1_SIZE - FIELD_OFFSET(NOTIFYICONDATAA, szTip))/sizeof(CHAR)
MultiByteToWideChar(CP_ACP, 0, pnid->szTip, NIDV1_TIP_SIZE_A,
nidW.szTip, _countof(nidW.szTip));
/* Truncate the string */
nidW.szTip[NIDV1_TIP_SIZE_A - 1] = 0;
#undef NIDV1_TIP_SIZE_A
}
else
{
MultiByteToWideChar(CP_ACP, 0, pnid->szTip, -1,
nidW.szTip, _countof(nidW.szTip));
}
}
if (cbSize >= NOTIFYICONDATAA_V2_SIZE)
{
nidW.dwState = pnid->dwState;
nidW.dwStateMask = pnid->dwStateMask;
nidW.uTimeout = pnid->uTimeout;
nidW.dwInfoFlags = pnid->dwInfoFlags;
if (nidW.uFlags & NIF_INFO)
{
MultiByteToWideChar(CP_ACP, 0, pnid->szInfo, -1,
nidW.szInfo, _countof(nidW.szInfo));
MultiByteToWideChar(CP_ACP, 0, pnid->szInfoTitle, -1,
nidW.szInfoTitle, _countof(nidW.szInfoTitle));
}
}
if ((cbSize >= NOTIFYICONDATAA_V3_SIZE) && (nidW.uFlags & NIF_GUID))
nidW.guidItem = pnid->guidItem;
if (cbSize >= sizeof(NOTIFYICONDATAA))
nidW.hBalloonIcon = pnid->hBalloonIcon;
/* Call the unicode function */
return Shell_NotifyIconW(dwMessage, &nidW);
}
/*************************************************************************
* Shell_NotifyIconW [SHELL32.298]
*/
BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW pnid)
{
BOOL ret = FALSE;
HWND hShellTrayWnd;
DWORD cbSize, dwValidFlags;
TRAYNOTIFYDATAW tnid;
COPYDATASTRUCT data;
/* Find a handle to the shell tray window */
hShellTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
if (!hShellTrayWnd)
return FALSE; // None found, bail out
/* Validate the structure size and the flags */
cbSize = pnid->cbSize;
dwValidFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
if (cbSize == sizeof(NOTIFYICONDATAW))
{
dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID /* | NIF_REALTIME | NIF_SHOWTIP */;
}
else if (cbSize == NOTIFYICONDATAW_V3_SIZE)
{
dwValidFlags |= NIF_STATE | NIF_INFO | NIF_GUID;
}
else if (cbSize == NOTIFYICONDATAW_V2_SIZE)
{
dwValidFlags |= NIF_STATE | NIF_INFO;
}
else // if cbSize == NOTIFYICONDATAW_V1_SIZE or something else
{
if (cbSize != NOTIFYICONDATAW_V1_SIZE)
{
WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
cbSize, NOTIFYICONDATAW_V1_SIZE);
cbSize = NOTIFYICONDATAW_V1_SIZE;
}
}
/* Build the data structure */
ZeroMemory(&tnid, sizeof(tnid));
tnid.dwSignature = NI_NOTIFY_SIG;
tnid.dwMessage = dwMessage;
/* Copy only the needed data, everything else is zeroed out */
CopyMemory(&tnid.nid, pnid, cbSize);
/* Adjust the size (the NOTIFYICONDATA structure is the full-fledged one) and the flags */
tnid.nid.cbSize = sizeof(tnid.nid);
tnid.nid.uFlags &= dwValidFlags;
/* Be sure the szTip member (that could be cut-off) is correctly NULL-terminated */
if (tnid.nid.uFlags & NIF_TIP)
{
if (cbSize <= NOTIFYICONDATAW_V1_SIZE)
{
#define NIDV1_TIP_SIZE_W (NOTIFYICONDATAW_V1_SIZE - FIELD_OFFSET(NOTIFYICONDATAW, szTip))/sizeof(WCHAR)
tnid.nid.szTip[NIDV1_TIP_SIZE_W - 1] = 0;
#undef NIDV1_TIP_SIZE_W
}
else
{
tnid.nid.szTip[_countof(tnid.nid.szTip) - 1] = 0;
}
}
/* Be sure the info strings are correctly NULL-terminated */
if (tnid.nid.uFlags & NIF_INFO)
{
tnid.nid.szInfo[_countof(tnid.nid.szInfo) - 1] = 0;
tnid.nid.szInfoTitle[_countof(tnid.nid.szInfoTitle) - 1] = 0;
}
/* Send the data */
data.dwData = 1;
data.cbData = sizeof(tnid);
data.lpData = &tnid;
if (SendMessageW(hShellTrayWnd, WM_COPYDATA, (WPARAM)pnid->hWnd, (LPARAM)&data))
ret = TRUE;
return ret;
}