https://git.reactos.org/?p=reactos.git;a=commitdiff;h=131678a025601690d655e…
commit 131678a025601690d655e35ad4b968c1b98297c7
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Feb 4 18:02:41 2018 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Feb 4 18:11:50 2018 +0100
[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/copyd…
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.
---
base/shell/explorer/syspager.cpp | 45 ++++----
dll/win32/shell32/precomp.h | 5 +
dll/win32/shell32/systray.cpp | 217 ++++++++++++++++++++++++++-------------
sdk/include/reactos/undocshell.h | 31 ++++--
4 files changed, 193 insertions(+), 105 deletions(-)
diff --git a/base/shell/explorer/syspager.cpp b/base/shell/explorer/syspager.cpp
index 9ba0f2fc99..32d4b45c6c 100644
--- a/base/shell/explorer/syspager.cpp
+++ b/base/shell/explorer/syspager.cpp
@@ -21,14 +21,6 @@
#include "precomp.h"
-// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
-typedef struct _SYS_PAGER_COPY_DATA
-{
- DWORD cookie;
- DWORD notify_code;
- NOTIFYICONDATA nicon_data;
-} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
-
struct InternalIconData : NOTIFYICONDATA
{
// Must keep a separate copy since the original is unioned with uTimeout.
@@ -236,7 +228,7 @@ public:
COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
END_COM_MAP()
- BOOL NotifyIcon(DWORD notify_code, _In_ CONST NOTIFYICONDATA *iconData);
+ BOOL NotifyIcon(DWORD dwMessage, _In_ CONST NOTIFYICONDATA *iconData);
void GetSize(IN BOOL IsHorizontal, IN PSIZE size);
DECLARE_WND_CLASS_EX(szSysPagerWndClass, CS_DBLCLKS, COLOR_3DFACE)
@@ -454,22 +446,18 @@ UINT WINAPI CIconWatcher::WatcherThread(_In_opt_ LPVOID lpParam)
TRACE("Pid %lu owns a notification icon and has stopped without deleting
it. We'll cleanup on its behalf", Icon->ProcessId);
- int len = FIELD_OFFSET(SYS_PAGER_COPY_DATA, nicon_data) +
Icon->IconData.cbSize;
- PSYS_PAGER_COPY_DATA pnotify_data = (PSYS_PAGER_COPY_DATA)new BYTE[len];
- pnotify_data->cookie = 1;
- pnotify_data->notify_code = NIM_DELETE;
- memcpy(&pnotify_data->nicon_data, &Icon->IconData,
Icon->IconData.cbSize);
+ TRAYNOTIFYDATAW tnid = {0};
+ tnid.dwSignature = NI_NOTIFY_SIG;
+ tnid.dwMessage = NIM_DELETE;
+ CopyMemory(&tnid.nid, &Icon->IconData, Icon->IconData.cbSize);
COPYDATASTRUCT data;
data.dwData = 1;
- data.cbData = len;
- data.lpData = pnotify_data;
-
- BOOL Success = FALSE;
- ::SendMessage(This->m_hwndSysTray, WM_COPYDATA,
(WPARAM)&Icon->IconData, (LPARAM)&data);
-
- delete pnotify_data;
+ data.cbData = sizeof(tnid);
+ data.lpData = &tnid;
+ BOOL Success = ::SendMessage(This->m_hwndSysTray, WM_COPYDATA,
+ (WPARAM)&Icon->IconData,
(LPARAM)&data);
if (!Success)
{
// If we failed to handle the delete message, forcibly remove it
@@ -1263,14 +1251,14 @@ LRESULT CSysPagerWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL& b
return TRUE;
}
-BOOL CSysPagerWnd::NotifyIcon(DWORD notify_code, _In_ CONST NOTIFYICONDATA *iconData)
+BOOL CSysPagerWnd::NotifyIcon(DWORD dwMessage, _In_ CONST NOTIFYICONDATA *iconData)
{
BOOL ret = FALSE;
int VisibleButtonCount = Toolbar.GetVisibleButtonCount();
- TRACE("NotifyIcon received. Code=%d\n", notify_code);
- switch (notify_code)
+ TRACE("NotifyIcon received. Code=%d\n", dwMessage);
+ switch (dwMessage)
{
case NIM_ADD:
ret = Toolbar.AddButton(iconData);
@@ -1295,7 +1283,7 @@ BOOL CSysPagerWnd::NotifyIcon(DWORD notify_code, _In_ CONST
NOTIFYICONDATA *icon
case NIM_SETVERSION:
ret = Toolbar.SwitchVersion(iconData);
default:
- TRACE("NotifyIcon received with unknown code %d.\n", notify_code);
+ TRACE("NotifyIcon received with unknown code %d.\n", dwMessage);
return FALSE;
}
@@ -1420,9 +1408,12 @@ LRESULT CSysPagerWnd::OnCopyData(UINT uMsg, WPARAM wParam, LPARAM
lParam, BOOL&
PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
if (cpData->dwData == 1)
{
- PSYS_PAGER_COPY_DATA pData = (PSYS_PAGER_COPY_DATA)cpData->lpData;
- return NotifyIcon(pData->notify_code, &pData->nicon_data);
+ /* A taskbar NotifyIcon notification */
+ PTRAYNOTIFYDATAW pData = (PTRAYNOTIFYDATAW)cpData->lpData;
+ if (pData->dwSignature == NI_NOTIFY_SIG)
+ return NotifyIcon(pData->dwMessage, &pData->nid);
}
+ // TODO: Handle other types of taskbar notifications
return FALSE;
}
diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h
index 03166e37e6..f059e5b0b9 100644
--- a/dll/win32/shell32/precomp.h
+++ b/dll/win32/shell32/precomp.h
@@ -17,6 +17,7 @@
#include <wincon.h>
#include <commdlg.h>
#include <ddeml.h>
+
#include <shlwapi.h>
#include <shlobj.h>
#include <shobjidl.h>
@@ -36,7 +37,11 @@
#include <shlguid_undoc.h>
#include <shlobj_undoc.h>
#include <shlwapi_undoc.h>
+
+#include <shellapi.h>
+#undef ShellExecute
#include <undocshell.h>
+
#include <browseui_undoc.h>
#include <shellutils.h>
diff --git a/dll/win32/shell32/systray.cpp b/dll/win32/shell32/systray.cpp
index aa07708d4d..482abf0e1b 100644
--- a/dll/win32/shell32/systray.cpp
+++ b/dll/win32/shell32/systray.cpp
@@ -1,5 +1,6 @@
/*
* Copyright 2004 Martin Fuchs
+ * Copyright 2018 Hermes Belusca-Maito
*
* Pass on icon notification messages to the systray implementation
* in the currently running shell.
@@ -23,91 +24,101 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
-/* copy data structure for tray notifications */
-typedef struct TrayNotifyCDS_Dummy {
- DWORD cookie;
- DWORD notify_code;
- DWORD nicon_data[1]; // placeholder for NOTIFYICONDATA structure
-} TrayNotifyCDS_Dummy;
-
-/* The only difference between Shell_NotifyIconA and Shell_NotifyIconW is the call to
SendMessageA/W. */
-static BOOL SHELL_NotifyIcon(DWORD dwMessage, void* pnid, HWND nid_hwnd, DWORD nid_size,
BOOL unicode)
-{
- HWND hwnd;
- COPYDATASTRUCT data;
-
- BOOL ret = FALSE;
- int len = FIELD_OFFSET(TrayNotifyCDS_Dummy, nicon_data) + nid_size;
-
- TrayNotifyCDS_Dummy* pnotify_data = (TrayNotifyCDS_Dummy*) alloca(len);
-
- pnotify_data->cookie = 1;
- pnotify_data->notify_code = dwMessage;
- memcpy(&pnotify_data->nicon_data, pnid, nid_size);
-
- data.dwData = 1;
- data.cbData = len;
- data.lpData = pnotify_data;
-
- for(hwnd = 0; (hwnd = FindWindowExW(0, hwnd, L"Shell_TrayWnd", NULL)); )
- if ((unicode ? SendMessageW : SendMessageA)(hwnd, WM_COPYDATA, (WPARAM)nid_hwnd,
(LPARAM)&data))
- ret = TRUE;
-
- return ret;
-}
-
-
/*************************************************************************
- * Shell_NotifyIcon [SHELL32.296]
+ * Shell_NotifyIcon [SHELL32.296]
* Shell_NotifyIconA [SHELL32.297]
*/
BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid)
{
NOTIFYICONDATAW nidW;
- DWORD cbSize;
-
- /* Validate the cbSize as Windows XP does */
- if (pnid->cbSize != NOTIFYICONDATAA_V1_SIZE &&
- pnid->cbSize != NOTIFYICONDATAA_V2_SIZE &&
- pnid->cbSize != sizeof(NOTIFYICONDATAA))
- {
- WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
- pnid->cbSize, NOTIFYICONDATAA_V1_SIZE);
- cbSize = NOTIFYICONDATAA_V1_SIZE;
- }
- else
- cbSize = pnid->cbSize;
+ DWORD cbSize, dwValidFlags;
+ /* Initialize and capture the basic data fields */
ZeroMemory(&nidW, sizeof(nidW));
- nidW.cbSize = 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;
- /* szTip */
- if (pnid->uFlags & NIF_TIP)
- MultiByteToWideChar(CP_ACP, 0, pnid->szTip, -1, nidW.szTip,
_countof(nidW.szTip));
-
- if (cbSize >= NOTIFYICONDATAA_V2_SIZE)
+ /* 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
{
- nidW.dwState = pnid->dwState;
- nidW.dwStateMask = pnid->dwStateMask;
+ 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 */
- /* szInfo, szInfoTitle */
- if (pnid->uFlags & NIF_INFO)
+ 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->szInfo, -1, nidW.szInfo,
_countof(nidW.szInfo));
- MultiByteToWideChar(CP_ACP, 0, pnid->szInfoTitle, -1, nidW.szInfoTitle,
_countof(nidW.szInfoTitle));
+ MultiByteToWideChar(CP_ACP, 0, pnid->szTip, -1,
+ nidW.szTip, _countof(nidW.szTip));
}
+ }
- nidW.uTimeout = pnid->uTimeout;
+ 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);
}
@@ -116,19 +127,81 @@ BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA
pnid)
*/
BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW pnid)
{
- DWORD cbSize;
+ BOOL ret = FALSE;
+ HWND hShellTrayWnd;
+ DWORD cbSize, dwValidFlags;
+ TRAYNOTIFYDATAW tnid;
+ COPYDATASTRUCT data;
- /* Validate the cbSize so that WM_COPYDATA doesn't crash the application */
- if (pnid->cbSize != NOTIFYICONDATAW_V1_SIZE &&
- pnid->cbSize != NOTIFYICONDATAW_V2_SIZE &&
- pnid->cbSize != sizeof(NOTIFYICONDATAW))
+ /* 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)
{
- WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n",
- pnid->cbSize, NOTIFYICONDATAW_V1_SIZE);
- cbSize = NOTIFYICONDATAW_V1_SIZE;
+ dwValidFlags |= NIF_STATE | NIF_INFO;
}
- else
- cbSize = pnid->cbSize;
+ 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 SHELL_NotifyIcon(dwMessage, pnid, pnid->hWnd, cbSize, TRUE);
+ return ret;
}
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 4a68feb63e..e74f201f86 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -30,10 +30,29 @@ extern "C" {
#define DBIMF_NOMARGINS 0x2000
#endif // NTDDI_LONGHORN
+#if defined (_SHELLAPI_H) || defined (_INC_SHELLAPI)
+
/****************************************************************************
- * Taskbar WM_COMMAND identifiers
+ * Taskbar interface WM_COPYDATA structures
+ * See
http://www.geoffchappell.com/studies/windows/shell/shell32/api/shlnot/copyd…
*/
+/* Data structure for Shell_NotifyIcon messages */
+typedef struct _TRAYNOTIFYDATAW
+{
+ DWORD dwSignature;
+ DWORD dwMessage;
+ NOTIFYICONDATAW nid; // Always use the latest NOTIFYICONDATAW structure version.
+} TRAYNOTIFYDATAW, *PTRAYNOTIFYDATAW;
+// Note: One could also introduce TRAYNOTIFYDATAA
+
+#define NI_NOTIFY_SIG 0x34753423 /* TRAYNOTIFYDATA */
+
+#endif /* defined (_SHELLAPI_H) || defined (_INC_SHELLAPI) */
+
+/****************************************************************************
+ * Taskbar WM_COMMAND identifiers
+ */
#define TWM_DOEXITWINDOWS (WM_USER + 342)
#define TWM_CYCLEFOCUS (WM_USER + 348)
@@ -79,8 +98,8 @@ BOOL WINAPI StrRetToStrNW(LPWSTR,DWORD,LPSTRRET,const ITEMIDLIST*);
/****************************************************************************
-* SHChangeNotifyRegister API
-*/
+ * SHChangeNotifyRegister API
+ */
#define SHCNRF_InterruptLevel 0x0001
#define SHCNRF_ShellLevel 0x0002
#define SHCNRF_RecursiveInterrupt 0x1000 /* Must be combined with
SHCNRF_InterruptLevel */
@@ -580,7 +599,7 @@ BOOL WINAPI GUIDFromStringW(
_In_ PCWSTR psz,
_Out_ LPGUID pguid
);
-
+
static inline ULONG
Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...)
{
@@ -838,7 +857,7 @@ typedef struct tagSHELL_LINK_INFOW
/*****************************************************************************
* SHELL_LINK_INFO_VOLUME_IDA/W
- * If cbVolumeLabelOffset != 0x00000014 (should be 0x00000010) then use
+ * If cbVolumeLabelOffset != 0x00000014 (should be 0x00000010) then use
* SHELL_LINK_INFO_VOLUME_IDA
* If cbVolumeLabelOffset == 0x00000014 then use SHELL_LINK_INFO_VOLUME_IDW
*/
@@ -958,7 +977,7 @@ typedef struct tagEXP_VISTA_ID_LIST
{
/* .cbSize >= 0x0000000a, .dwSignature = 0xa000000c */
DATABLOCK_HEADER dbh;
- /* Specifies an alternate IDList that can be used instead
+ /* Specifies an alternate IDList that can be used instead
of the "normal" IDList (SLDF_HAS_ID_LIST) */
/* LPITEMIDLIST pIDList; (variable) */
} EXP_VISTA_ID_LIST, *LPEXP_VISTA_ID_LIST;