https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fe4704fa64eab91615913…
commit fe4704fa64eab916159131a5ec3bc8074958b9f2
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Feb 7 02:20:26 2018 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Thu Feb 15 22:38:22 2018 +0100
[SHELL32] Implement the CUserNotification class, which implements the
IUserNotification interface. CORE-13177
---
dll/win32/shell32/CMakeLists.txt | 1 +
dll/win32/shell32/CUserNotification.cpp | 478 +++++++++++++++++++++++++
dll/win32/shell32/CUserNotification.h | 111 ++++++
dll/win32/shell32/precomp.h | 1 +
dll/win32/shell32/res/rgs/usernotification.rgs | 43 +++
dll/win32/shell32/rgs_res.rc | 1 +
dll/win32/shell32/shell32.cpp | 5 +-
dll/win32/shell32/shresdef.h | 3 +-
dll/win32/shell32/systray.cpp | 2 +-
9 files changed, 641 insertions(+), 4 deletions(-)
diff --git a/dll/win32/shell32/CMakeLists.txt b/dll/win32/shell32/CMakeLists.txt
index 8bdf3ee56f..76ebf226e3 100644
--- a/dll/win32/shell32/CMakeLists.txt
+++ b/dll/win32/shell32/CMakeLists.txt
@@ -67,6 +67,7 @@ list(APPEND SOURCE
CDefViewBckgrndMenu.cpp
stubs.cpp
systray.cpp
+ CUserNotification.cpp
CDefaultContextMenu.cpp
COpenWithMenu.cpp
CNewMenu.cpp
diff --git a/dll/win32/shell32/CUserNotification.cpp
b/dll/win32/shell32/CUserNotification.cpp
new file mode 100644
index 0000000000..c76bd0b10f
--- /dev/null
+++ b/dll/win32/shell32/CUserNotification.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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"
+
+#include <mmsystem.h>
+#undef PlaySound
+
+WINE_DEFAULT_DEBUG_CHANNEL(shell_notify);
+
+
+/* Use Windows-compatible window callback message */
+#define WM_TRAYNOTIFY (WM_USER + 100)
+
+/* Notification icon ID */
+#define ID_NOTIFY_ICON 0
+
+/* Balloon timers */
+#define ID_BALLOON_TIMEOUT 1
+#define ID_BALLOON_DELAYREMOVE 2
+#define ID_BALLOON_QUERYCONT 3
+#define ID_BALLOON_SHOWTIME 4
+
+#define BALLOON_DELAYREMOVE_TIMEOUT 250 // milliseconds
+
+
+CUserNotification::CUserNotification() :
+ m_hWorkerWnd(NULL),
+ m_hIcon(NULL),
+ m_dwInfoFlags(0),
+ m_uShowTime(15000),
+ m_uInterval(10000),
+ m_cRetryCount(-1),
+ m_uContinuePoolInterval(0),
+ m_bIsShown(FALSE),
+ m_hRes(S_OK),
+ m_pqc(NULL)
+{
+}
+
+CUserNotification::~CUserNotification()
+{
+ /* If we have a notification window... */
+ if (m_hWorkerWnd)
+ {
+ /* ... remove the notification icon and destroy the window */
+ RemoveIcon();
+ ::DestroyWindow(m_hWorkerWnd);
+ m_hWorkerWnd = NULL;
+ }
+
+ /* Destroy our local icon copy */
+ if (m_hIcon)
+ ::DestroyIcon(m_hIcon);
+}
+
+VOID CUserNotification::RemoveIcon()
+{
+ NOTIFYICONDATAW nid = {0};
+
+ nid.cbSize = NOTIFYICONDATAW_V3_SIZE; // sizeof(nid);
+ nid.hWnd = m_hWorkerWnd;
+ nid.uID = ID_NOTIFY_ICON;
+
+ /* Remove the notification icon */
+ ::Shell_NotifyIconW(NIM_DELETE, &nid);
+}
+
+VOID CUserNotification::DelayRemoveIcon(IN HRESULT hRes)
+{
+ /* Set the return value for CUserNotification::Show() and defer icon removal */
+ m_hRes = hRes;
+ ::SetTimer(m_hWorkerWnd, ID_BALLOON_DELAYREMOVE,
+ BALLOON_DELAYREMOVE_TIMEOUT, NULL);
+}
+
+VOID CUserNotification::TimeoutIcon()
+{
+ /*
+ * The balloon timed out, we need to wait before showing it again.
+ * If we retried too many times, delete the notification icon.
+ */
+ if (m_cRetryCount > 0)
+ {
+ /* Decrement the retry count */
+ --m_cRetryCount;
+
+ /* Set the timeout interval timer */
+ ::SetTimer(m_hWorkerWnd, ID_BALLOON_TIMEOUT, m_uInterval, NULL);
+ }
+ else
+ {
+ /* No other retry: delete the notification icon */
+ DelayRemoveIcon(HRESULT_FROM_WIN32(ERROR_CANCELLED));
+ }
+}
+
+VOID CUserNotification::SetUpNotifyData(
+ IN UINT uFlags,
+ IN OUT PNOTIFYICONDATAW pnid)
+{
+ pnid->cbSize = NOTIFYICONDATAW_V3_SIZE; // sizeof(nid);
+ pnid->hWnd = m_hWorkerWnd;
+ pnid->uID = ID_NOTIFY_ICON;
+ // pnid->uVersion = NOTIFYICON_VERSION;
+
+ if (uFlags & NIF_MESSAGE)
+ {
+ pnid->uFlags |= NIF_MESSAGE;
+ pnid->uCallbackMessage = WM_TRAYNOTIFY;
+ }
+
+ if (uFlags & NIF_ICON)
+ {
+ pnid->uFlags |= NIF_ICON;
+ /* Use a default icon if we do not have one already */
+ pnid->hIcon = (m_hIcon ? m_hIcon : LoadIcon(NULL, IDI_WINLOGO));
+ }
+
+ if (uFlags & NIF_TIP)
+ {
+ pnid->uFlags |= NIF_TIP;
+ ::StringCchCopyW(pnid->szTip, _countof(pnid->szTip), m_szTip);
+ }
+
+ if (uFlags & NIF_INFO)
+ {
+ pnid->uFlags |= NIF_INFO;
+
+ // pnid->uTimeout = m_uShowTime; // NOTE: Deprecated
+ pnid->dwInfoFlags = m_dwInfoFlags;
+
+ ::StringCchCopyW(pnid->szInfo, _countof(pnid->szInfo), m_szInfo);
+ ::StringCchCopyW(pnid->szInfoTitle, _countof(pnid->szInfoTitle),
m_szInfoTitle);
+ }
+}
+
+
+/* IUserNotification Implementation */
+
+HRESULT STDMETHODCALLTYPE
+CUserNotification::SetBalloonInfo(
+ IN LPCWSTR pszTitle,
+ IN LPCWSTR pszText,
+ IN DWORD dwInfoFlags)
+{
+ NOTIFYICONDATAW nid = {0};
+
+ m_szInfo = pszText;
+ m_szInfoTitle = pszTitle;
+ m_dwInfoFlags = dwInfoFlags;
+
+ /* Update the notification icon if we have one */
+ if (!m_hWorkerWnd)
+ return S_OK;
+
+ /* Modify the notification icon */
+ SetUpNotifyData(NIF_INFO, &nid);
+ if (::Shell_NotifyIconW(NIM_MODIFY, &nid))
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE
+CUserNotification::SetBalloonRetry(
+ IN DWORD dwShowTime, // Time intervals in milliseconds
+ IN DWORD dwInterval,
+ IN UINT cRetryCount)
+{
+ m_uShowTime = dwShowTime;
+ m_uInterval = dwInterval;
+ m_cRetryCount = cRetryCount;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE
+CUserNotification::SetIconInfo(
+ IN HICON hIcon,
+ IN LPCWSTR pszToolTip)
+{
+ NOTIFYICONDATAW nid = {0};
+
+ /* Destroy our local icon copy */
+ if (m_hIcon)
+ ::DestroyIcon(m_hIcon);
+
+ if (hIcon)
+ {
+ /* Copy the icon from the user */
+ m_hIcon = ::CopyIcon(hIcon);
+ }
+ else
+ {
+ /* Use the same icon as the one for the balloon if specified */
+ UINT uIcon = (m_dwInfoFlags & NIIF_ICON_MASK);
+ LPCWSTR pIcon = NULL;
+
+ if (uIcon == NIIF_INFO)
+ pIcon = IDI_INFORMATION;
+ else if (uIcon == NIIF_WARNING)
+ pIcon = IDI_WARNING;
+ else if (uIcon == NIIF_ERROR)
+ pIcon = IDI_ERROR;
+ else if (uIcon == NIIF_USER)
+ pIcon = NULL;
+
+ m_hIcon = (pIcon ? ::LoadIconW(NULL, pIcon) : NULL);
+ }
+
+ m_szTip = pszToolTip;
+
+ /* Update the notification icon if we have one */
+ if (!m_hWorkerWnd)
+ return S_OK;
+
+ /* Modify the notification icon */
+ SetUpNotifyData(NIF_ICON | NIF_TIP, &nid);
+ if (::Shell_NotifyIconW(NIM_MODIFY, &nid))
+ return S_OK;
+ else
+ return E_FAIL;
+}
+
+
+LRESULT CALLBACK
+CUserNotification::WorkerWndProc(
+ IN HWND hWnd,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam)
+{
+ /* Retrieve the current user notification object stored in the window extra bits */
+ CUserNotification* pThis =
reinterpret_cast<CUserNotification*>(::GetWindowLongPtrW(hWnd, 0));
+ ASSERT(pThis);
+ ASSERT(hWnd == pThis->m_hWorkerWnd);
+
+ TRACE("Msg = 0x%x\n", uMsg);
+ switch (uMsg)
+ {
+ /*
+ * We do not receive any WM_(NC)CREATE message since worker windows
+ * are first created using the default window procedure DefWindowProcW.
+ * The window procedure is changed only subsequently to the user one.
+ * We however receive WM_(NC)DESTROY messages.
+ */
+ case WM_DESTROY:
+ {
+ /* Post a WM_QUIT message only if the Show() method's message loop is
running */
+ if (pThis->m_bIsShown)
+ ::PostQuitMessage(0);
+ return 0;
+ }
+
+ case WM_NCDESTROY:
+ {
+ ::SetWindowLongPtrW(hWnd, 0, (LONG_PTR)NULL);
+ pThis->m_hWorkerWnd = NULL;
+ return 0;
+ }
+
+ case WM_QUERYENDSESSION:
+ {
+ /*
+ * User session is ending or a shutdown is occurring: perform cleanup.
+ * Set the return value for CUserNotification::Show() and remove the
notification.
+ */
+ pThis->m_hRes = HRESULT_FROM_WIN32(ERROR_CANCELLED);
+ pThis->RemoveIcon();
+ ::DestroyWindow(pThis->m_hWorkerWnd);
+ return TRUE;
+ }
+
+ case WM_TIMER:
+ {
+ TRACE("WM_TIMER(0x%lx)\n", wParam);
+
+ /* Destroy the associated timer */
+ ::KillTimer(hWnd, (UINT_PTR)wParam);
+
+ if (wParam == ID_BALLOON_TIMEOUT)
+ {
+ /* Timeout interval timer expired: display the balloon again */
+ NOTIFYICONDATAW nid = {0};
+ pThis->SetUpNotifyData(NIF_INFO, &nid);
+ ::Shell_NotifyIconW(NIM_MODIFY, &nid);
+ }
+ else if (wParam == ID_BALLOON_DELAYREMOVE)
+ {
+ /* Delay-remove timer expired: remove the notification */
+ pThis->RemoveIcon();
+ ::DestroyWindow(pThis->m_hWorkerWnd);
+ }
+ else if (wParam == ID_BALLOON_QUERYCONT)
+ {
+ /*
+ * Query-continue timer expired: ask the user whether the
+ * notification should continue to be displayed or not.
+ */
+ if (pThis->m_pqc && pThis->m_pqc->QueryContinue() ==
S_OK)
+ {
+ /* The notification can be displayed */
+ ::SetTimer(hWnd, ID_BALLOON_QUERYCONT,
pThis->m_uContinuePoolInterval, NULL);
+ }
+ else
+ {
+ /* The notification should be removed */
+ pThis->DelayRemoveIcon(S_FALSE);
+ }
+ }
+ else if (wParam == ID_BALLOON_SHOWTIME)
+ {
+ /* Show-time timer expired: wait before showing the balloon again */
+ pThis->TimeoutIcon();
+ }
+ return 0;
+ }
+
+ /*
+ * Shell User Notification message.
+ * We use NOTIFYICON_VERSION == 0 or 3 callback version, with:
+ * wParam == identifier of the taskbar icon in which the event occurred;
+ * lParam == holds the mouse or keyboard message associated with the event.
+ */
+ case WM_TRAYNOTIFY:
+ {
+ TRACE("WM_TRAYNOTIFY - wParam = 0x%lx ; lParam = 0x%lx\n", wParam,
lParam);
+ ASSERT(wParam == ID_NOTIFY_ICON);
+
+ switch (lParam)
+ {
+ case NIN_BALLOONSHOW:
+ TRACE("NIN_BALLOONSHOW\n");
+ break;
+
+ case NIN_BALLOONHIDE:
+ TRACE("NIN_BALLOONHIDE\n");
+ break;
+
+ /* The balloon timed out, or the user closed it by clicking on the
'X' button */
+ case NIN_BALLOONTIMEOUT:
+ {
+ TRACE("NIN_BALLOONTIMEOUT\n");
+ pThis->TimeoutIcon();
+ break;
+ }
+
+ /* The user clicked on the balloon: delete the notification icon */
+ case NIN_BALLOONUSERCLICK:
+ TRACE("NIN_BALLOONUSERCLICK\n");
+ /* Fall back to icon click behaviour */
+
+ /* The user clicked on the notification icon: delete it */
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ {
+ pThis->DelayRemoveIcon(S_OK);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+ }
+ }
+
+ return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+
+// Blocks until the notification times out.
+HRESULT STDMETHODCALLTYPE
+CUserNotification::Show(
+ IN IQueryContinue* pqc,
+ IN DWORD dwContinuePollInterval)
+{
+ NOTIFYICONDATAW nid = {0};
+ MSG msg;
+
+ /* Create the hidden notification message worker window if we do not have one already
*/
+ if (!m_hWorkerWnd)
+ {
+ m_hWorkerWnd = ::SHCreateWorkerWindowW(CUserNotification::WorkerWndProc,
+ NULL, 0, 0, NULL, (LONG_PTR)this);
+ if (!m_hWorkerWnd)
+ {
+ FAILED_UNEXPECTEDLY(E_FAIL);
+ return E_FAIL;
+ }
+
+ /* Add and display the notification icon */
+ SetUpNotifyData(NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO, &nid);
+ if (!::Shell_NotifyIconW(NIM_ADD, &nid))
+ {
+ ::DestroyWindow(m_hWorkerWnd);
+ m_hWorkerWnd = NULL;
+ return E_FAIL;
+ }
+ }
+
+ m_hRes = S_OK;
+
+ /* Set up the user-continue callback mechanism */
+ m_pqc = pqc;
+ if (pqc)
+ {
+ m_uContinuePoolInterval = dwContinuePollInterval;
+ ::SetTimer(m_hWorkerWnd, ID_BALLOON_QUERYCONT, m_uContinuePoolInterval, NULL);
+ }
+
+ /* Control how long the balloon notification is displayed */
+ if ((nid.uFlags & NIF_INFO) && !*nid.szInfo /* &&
!*nid.szInfoTitle */)
+ ::SetTimer(m_hWorkerWnd, ID_BALLOON_SHOWTIME, m_uShowTime, NULL);
+
+ /* Dispatch messsages to the worker window */
+ m_bIsShown = TRUE;
+ while (::GetMessageW(&msg, NULL, 0, 0))
+ {
+ ::TranslateMessage(&msg);
+ ::DispatchMessageW(&msg);
+ }
+ m_bIsShown = FALSE;
+
+ /* Reset the user-continue callback mechanism */
+ if (pqc)
+ {
+ ::KillTimer(m_hWorkerWnd, ID_BALLOON_QUERYCONT);
+ m_uContinuePoolInterval = 0;
+ }
+ m_pqc = NULL;
+
+ /* Return the notification error code */
+ return m_hRes;
+}
+
+#if 0 // IUserNotification2
+// Blocks until the notification times out.
+HRESULT STDMETHODCALLTYPE
+CUserNotification::Show(
+ IN IQueryContinue* pqc,
+ IN DWORD dwContinuePollInterval,
+ IN IUserNotificationCallback* pSink)
+{
+ return S_OK;
+}
+#endif
+
+HRESULT STDMETHODCALLTYPE
+CUserNotification::PlaySound(
+ IN LPCWSTR pszSoundName)
+{
+ /* Call the Win32 API - Ignore the PlaySoundW() return value as on Windows */
+ ::PlaySoundW(pszSoundName,
+ NULL,
+ SND_ALIAS | SND_APPLICATION |
+ SND_NOSTOP | SND_NODEFAULT | SND_ASYNC);
+ return S_OK;
+}
diff --git a/dll/win32/shell32/CUserNotification.h
b/dll/win32/shell32/CUserNotification.h
new file mode 100644
index 0000000000..4f01e0c9be
--- /dev/null
+++ b/dll/win32/shell32/CUserNotification.h
@@ -0,0 +1,111 @@
+/*
+ * 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
+ */
+
+#ifndef _USERNOTIFICATION_H_
+#define _USERNOTIFICATION_H_
+
+#undef PlaySound
+
+class CUserNotification :
+ public CComCoClass<CUserNotification, &CLSID_UserNotification>,
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IUserNotification
+// public IUserNotification2 // On Vista+
+{
+private:
+ HWND m_hWorkerWnd;
+ HICON m_hIcon;
+ DWORD m_dwInfoFlags;
+ UINT m_uShowTime;
+ UINT m_uInterval;
+ UINT m_cRetryCount;
+ UINT m_uContinuePoolInterval;
+ BOOL m_bIsShown;
+ HRESULT m_hRes;
+ IQueryContinue* m_pqc;
+ CStringW m_szTip;
+ CStringW m_szInfo;
+ CStringW m_szInfoTitle;
+
+private:
+ VOID RemoveIcon();
+ VOID DelayRemoveIcon(IN HRESULT hRes);
+ VOID TimeoutIcon();
+
+ VOID SetUpNotifyData(
+ IN UINT uFlags,
+ IN OUT PNOTIFYICONDATAW pnid);
+
+ static LRESULT CALLBACK
+ WorkerWndProc(
+ IN HWND hWnd,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam);
+
+public:
+ CUserNotification();
+ ~CUserNotification();
+
+ // IUserNotification
+ virtual HRESULT STDMETHODCALLTYPE SetBalloonInfo(
+ IN LPCWSTR pszTitle,
+ IN LPCWSTR pszText,
+ IN DWORD dwInfoFlags);
+
+ virtual HRESULT STDMETHODCALLTYPE SetBalloonRetry(
+ IN DWORD dwShowTime, // Time intervals in milliseconds
+ IN DWORD dwInterval,
+ IN UINT cRetryCount);
+
+ virtual HRESULT STDMETHODCALLTYPE SetIconInfo(
+ IN HICON hIcon,
+ IN LPCWSTR pszToolTip);
+
+ // Blocks until the notification times out.
+ virtual HRESULT STDMETHODCALLTYPE Show(
+ IN IQueryContinue* pqc,
+ IN DWORD dwContinuePollInterval);
+
+ virtual HRESULT STDMETHODCALLTYPE PlaySound(
+ IN LPCWSTR pszSoundName);
+
+#if 0
+ // IUserNotification2
+ // Blocks until the notification times out.
+ virtual HRESULT STDMETHODCALLTYPE Show(
+ IN IQueryContinue* pqc,
+ IN DWORD dwContinuePollInterval,
+ IN IUserNotificationCallback* pSink);
+#endif
+
+ DECLARE_REGISTRY_RESOURCEID(IDR_USERNOTIFICATION)
+ DECLARE_NOT_AGGREGATABLE(CUserNotification)
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ BEGIN_COM_MAP(CUserNotification)
+ COM_INTERFACE_ENTRY_IID(IID_IUserNotification , IUserNotification )
+ // COM_INTERFACE_ENTRY_IID(IID_IUserNotification2, IUserNotification2)
+ END_COM_MAP()
+};
+
+#endif /* _USERNOTIFICATION_H_ */
diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h
index f059e5b0b9..f85423ea85 100644
--- a/dll/win32/shell32/precomp.h
+++ b/dll/win32/shell32/precomp.h
@@ -84,6 +84,7 @@
#include "shellmenu/CMenuSite.h"
#include "shellmenu/CMergedFolder.h"
#include "shellmenu/shellmenu.h"
+#include "CUserNotification.h"
#include <wine/debug.h>
#include <wine/unicode.h>
diff --git a/dll/win32/shell32/res/rgs/usernotification.rgs
b/dll/win32/shell32/res/rgs/usernotification.rgs
new file mode 100644
index 0000000000..61c585f432
--- /dev/null
+++ b/dll/win32/shell32/res/rgs/usernotification.rgs
@@ -0,0 +1,43 @@
+HKCR
+{
+ NoRemove AppID
+ {
+ {0010890E-8789-413C-ADBC-48F5B511B3AF}
+ {
+ val DllSurrogate = s ''
+ val RunAs = s 'Interactive User'
+ }
+ }
+ NoRemove CLSID
+ {
+ ForceRemove {0010890E-8789-413C-ADBC-48F5B511B3AF} = s 'User Notification'
+ {
+ InprocServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Apartment'
+ }
+ val AppID = s '{0010890E-8789-413C-ADBC-48F5B511B3AF}'
+ }
+ NoRemove Interface
+ {
+ ForceRemove {7307055C-B24A-486B-9F25-163E597A28A9} = s 'IQueryContinue'
+ {
+ NumMethods = s '4'
+ {
+ }
+ ProxyStubClsid32 = s '{B8DA6310-E19B-11D0-933C-00A0C90DCAA9}'
+ {
+ }
+ }
+ ForceRemove {BA9711BA-5893-4787-A7E1-41277151550B} = s 'IUserNotification'
+ {
+ NumMethods = s '8'
+ {
+ }
+ ProxyStubClsid32 = s '{B8DA6310-E19B-11D0-933C-00A0C90DCAA9}'
+ {
+ }
+ }
+ }
+ }
+}
diff --git a/dll/win32/shell32/rgs_res.rc b/dll/win32/shell32/rgs_res.rc
index 118eb51e01..67e072d530 100644
--- a/dll/win32/shell32/rgs_res.rc
+++ b/dll/win32/shell32/rgs_res.rc
@@ -26,4 +26,5 @@ IDR_DRVDEFEXT REGISTRY "res/rgs/shelldrvdefext.rgs"
IDR_EXEDROPHANDLER REGISTRY "res/rgs/exedrophandler.rgs"
IDR_MERGEDFOLDER REGISTRY "res/rgs/mergedfolder.rgs"
IDR_REBARBANDSITE REGISTRY "res/rgs/rebarbandsite.rgs"
+IDR_USERNOTIFICATION REGISTRY "res/rgs/usernotification.rgs"
IDR_SHELL REGISTRY "res/rgs/shell.rgs"
diff --git a/dll/win32/shell32/shell32.cpp b/dll/win32/shell32/shell32.cpp
index 12c5a1e24d..ac0a3bd08c 100644
--- a/dll/win32/shell32/shell32.cpp
+++ b/dll/win32/shell32/shell32.cpp
@@ -253,9 +253,10 @@ BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_MergedFolder, CMergedFolder)
OBJECT_ENTRY(CLSID_ExeDropHandler, CExeDropHandler)
OBJECT_ENTRY(CLSID_QueryAssociations, CQueryAssociations)
+ OBJECT_ENTRY(CLSID_UserNotification, CUserNotification)
END_OBJECT_MAP()
-CShell32Module gModule;
+CShell32Module gModule;
/***********************************************************************
@@ -311,7 +312,7 @@ STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
* all are once per process
*
*/
-HINSTANCE shell32_hInstance;
+HINSTANCE shell32_hInstance;
/*************************************************************************
* SHELL32 DllMain
diff --git a/dll/win32/shell32/shresdef.h b/dll/win32/shell32/shresdef.h
index 5b607a6943..53e4896713 100644
--- a/dll/win32/shell32/shresdef.h
+++ b/dll/win32/shell32/shresdef.h
@@ -689,4 +689,5 @@
#define IDR_QUERYASSOCIATIONS 152
#define IDR_MERGEDFOLDER 153
#define IDR_REBARBANDSITE 154
-#define IDR_SHELL 155
+#define IDR_USERNOTIFICATION 155
+#define IDR_SHELL 156
diff --git a/dll/win32/shell32/systray.cpp b/dll/win32/shell32/systray.cpp
index 482abf0e1b..a64d68950c 100644
--- a/dll/win32/shell32/systray.cpp
+++ b/dll/win32/shell32/systray.cpp
@@ -22,7 +22,7 @@
#include "precomp.h"
-WINE_DEFAULT_DEBUG_CHANNEL(shell);
+WINE_DEFAULT_DEBUG_CHANNEL(shell_notify);
/*************************************************************************
* Shell_NotifyIcon [SHELL32.296]