diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index a30f8db8865..e2c5e0c663f 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -12,6 +12,7 @@ list(APPEND SOURCE CMyComputer.cpp CShellDesktop.cpp CShellLink.cpp + CUserNotification.cpp menu.cpp PathResolve.cpp SHCreateFileExtractIconW.cpp diff --git a/modules/rostests/apitests/shell32/CUserNotification.cpp b/modules/rostests/apitests/shell32/CUserNotification.cpp new file mode 100644 index 00000000000..b10185cee99 --- /dev/null +++ b/modules/rostests/apitests/shell32/CUserNotification.cpp @@ -0,0 +1,179 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for CUserNotification + * COPYRIGHT: Copyright 2018 Hermes Belusca-Maito + */ + +#include "shelltest.h" + +#define NDEBUG +#include + +#define ok_hr(status, expected) ok_hex(status, expected) + +#define HRESULT_CANCELLED HRESULT_FROM_WIN32(ERROR_CANCELLED) + + +/* An implementation of the IQueryContinue interface */ +class CQueryContinue : public IQueryContinue +{ +private: + HRESULT m_hContinue; + +public: + CQueryContinue(HRESULT hContinue = S_OK) : m_hContinue(hContinue) {} + ~CQueryContinue() {} + + CQueryContinue& operator=(const CQueryContinue& qc) + { + if (this != &qc) + m_hContinue = qc.m_hContinue; + return *this; + } + + CQueryContinue& operator=(HRESULT hContinue) + { + m_hContinue = hContinue; + return *this; + } + + operator HRESULT() + { + return m_hContinue; + } + +public: + // IUnknown + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return 0; + } + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) + { + return S_OK; + } + + // IQueryContinue + virtual HRESULT STDMETHODCALLTYPE QueryContinue(void) + { + // TRACE("IQueryContinue::QueryContinue() returning 0x%lx\n", m_hContinue); + return m_hContinue; + } +}; + + +static void +TestNotification(void) +{ + HRESULT hr; + CComPtr pUserNotif; + CQueryContinue queryContinue(S_OK); + + // hr = pUserNotif.CoCreateInstance(CLSID_UserNotification); + hr = ::CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_ALL, + /*IID_PPV_ARG(IUserNotification, &pUserNotif)*/ + IID_IUserNotification, (void**)&pUserNotif); + ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); + if (FAILED(hr)) + { + skip("Could not instantiate IUserNotification\n"); + return; + } + + /* Set an invalid icon for the notification icon */ + hr = pUserNotif->SetIconInfo((HICON)0xdeadbeef, L"Tooltip text"); + ok_hr(hr, S_OK); + +#if 0 + /* Seting an invalid string would crash the application */ + hr = pUserNotif->SetIconInfo(NULL, (LPCWSTR)0xdeadbeef); + ok_hr(hr, S_OK); +#endif + + /* Set a default icon for the notification icon */ + hr = pUserNotif->SetIconInfo(NULL, L"Tooltip text"); + ok_hr(hr, S_OK); + + /* + * Since just displaying a notification icon without balloon hangs (expected), + * for making this test automatable we instead just test balloon functionality + * where timeouts can be programmed. + */ + + /* Set up a balloon associated to the notification icon */ + hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_ERROR); + ok_hr(hr, S_OK); + + /* + * Try to display twice the balloon if the user cancels it. + * Without setting balloon retry, we would wait for a very long time... + */ + hr = pUserNotif->SetBalloonRetry(2000, 1000, 2); + ok_hr(hr, S_OK); + + /* Display the balloon and also the tooltip if one points on the icon */ + hr = pUserNotif->Show(NULL, 0); + ok_hr(hr, HRESULT_CANCELLED); + + /* + * Setting icon information *after* having enabled balloon info, + * allows to automatically set the notification icon according + * to the dwInfoFlags passed to SetBalloonInfo() and by giving + * NULL to the hIcon parameter of SetIconInfo(). + */ + hr = pUserNotif->SetIconInfo(NULL, NULL); + ok_hr(hr, S_OK); + + /* Display the balloon and also the tooltip if one points on the icon */ + hr = pUserNotif->Show(NULL, 0); + ok_hr(hr, HRESULT_CANCELLED); + + /* + * This line shows the balloon, but without title nor icon in it. + * Note that the balloon icon is not displayed when not setting any title. + */ + hr = pUserNotif->SetBalloonInfo(NULL, L"Balloon text", NIIF_WARNING); + ok_hr(hr, S_OK); + + hr = pUserNotif->Show(NULL, 0); + ok_hr(hr, HRESULT_CANCELLED); + + + /* Test support of the IQueryContinue interface */ + + hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_WARNING); + ok_hr(hr, S_OK); + + hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ + ok_hr(hr, HRESULT_CANCELLED); + +#if 0 // Commented because this test (the Show() call) is unreliable. + /* Try to hide the balloon by setting an empty string (can use either NULL or L"") */ + hr = pUserNotif->SetBalloonInfo(L"Balloon title", NULL, NIIF_WARNING); + ok_hr(hr, S_OK); + + hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ + ok_hr(hr, HRESULT_CANCELLED); +#endif + + hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_WARNING); + ok_hr(hr, S_OK); + + queryContinue = S_FALSE; + hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ + ok_hr(hr, S_FALSE); +} + +START_TEST(CUserNotification) +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + TestNotification(); + CoUninitialize(); +} diff --git a/modules/rostests/apitests/shell32/testlist.c b/modules/rostests/apitests/shell32/testlist.c index b0a86380465..792bf49503b 100644 --- a/modules/rostests/apitests/shell32/testlist.c +++ b/modules/rostests/apitests/shell32/testlist.c @@ -9,6 +9,7 @@ extern void func_CFSFolder(void); extern void func_CMyComputer(void); extern void func_CShellDesktop(void); extern void func_CShellLink(void); +extern void func_CUserNotification(void); extern void func_menu(void); extern void func_PathResolve(void); extern void func_SHCreateFileExtractIconW(void); @@ -23,6 +24,7 @@ const struct test winetest_testlist[] = { "CMyComputer", func_CMyComputer }, { "CShellDesktop", func_CShellDesktop }, { "CShellLink", func_CShellLink }, + { "CUserNotification", func_CUserNotification }, { "menu", func_menu }, { "PathResolve", func_PathResolve }, { "SHCreateFileExtractIconW", func_SHCreateFileExtractIconW },