https://git.reactos.org/?p=reactos.git;a=commitdiff;h=131678a025601690d655e35ad4b968c1b98297c7

commit 131678a025601690d655e35ad4b968c1b98297c7
Author:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
AuthorDate: Sun Feb 4 18:02:41 2018 +0100
Commit:     Hermès Bélusca-Maïto <hermes.belusca-ma...@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/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.
---
 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/copydata.htm
  */
+/* 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;

Reply via email to