1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Test for CUserNotification 5 * COPYRIGHT: Copyright 2018 Hermes Belusca-Maito 6 */ 7 8 #include "shelltest.h" 9 10 #define NDEBUG 11 #include <debug.h> 12 13 #define ok_hr(status, expected) ok_hex(status, expected) 14 15 #define HRESULT_CANCELLED HRESULT_FROM_WIN32(ERROR_CANCELLED) 16 17 18 /* An implementation of the IQueryContinue interface */ 19 class CQueryContinue : public IQueryContinue 20 { 21 private: 22 HRESULT m_hContinue; 23 24 public: 25 CQueryContinue(HRESULT hContinue = S_OK) : m_hContinue(hContinue) {} 26 ~CQueryContinue() {} 27 28 CQueryContinue& operator=(const CQueryContinue& qc) 29 { 30 if (this != &qc) 31 m_hContinue = qc.m_hContinue; 32 return *this; 33 } 34 35 CQueryContinue& operator=(HRESULT hContinue) 36 { 37 m_hContinue = hContinue; 38 return *this; 39 } 40 41 operator HRESULT() 42 { 43 return m_hContinue; 44 } 45 46 public: 47 // IUnknown 48 virtual ULONG STDMETHODCALLTYPE AddRef() 49 { 50 return 1; 51 } 52 53 virtual ULONG STDMETHODCALLTYPE Release() 54 { 55 return 0; 56 } 57 58 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) 59 { 60 return S_OK; 61 } 62 63 // IQueryContinue 64 virtual HRESULT STDMETHODCALLTYPE QueryContinue(void) 65 { 66 // TRACE("IQueryContinue::QueryContinue() returning 0x%lx\n", m_hContinue); 67 return m_hContinue; 68 } 69 }; 70 71 72 static void 73 TestNotification(void) 74 { 75 HRESULT hr; 76 CComPtr<IUserNotification> pUserNotif; 77 CQueryContinue queryContinue(S_OK); 78 79 // hr = pUserNotif.CoCreateInstance(CLSID_UserNotification); 80 hr = ::CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_ALL, 81 /*IID_PPV_ARG(IUserNotification, &pUserNotif)*/ 82 IID_IUserNotification, (void**)&pUserNotif); 83 ok(hr == S_OK, "CoCreateInstance, hr = 0x%lx\n", hr); 84 if (FAILED(hr)) 85 { 86 skip("Could not instantiate IUserNotification\n"); 87 return; 88 } 89 90 /* Set an invalid icon for the notification icon */ 91 hr = pUserNotif->SetIconInfo((HICON)UlongToHandle(0xdeadbeef), L"Tooltip text"); 92 ok_hr(hr, S_OK); 93 94 #if 0 95 /* Seting an invalid string would crash the application */ 96 hr = pUserNotif->SetIconInfo(NULL, (LPCWSTR)0xdeadbeef); 97 ok_hr(hr, S_OK); 98 #endif 99 100 /* Set a default icon for the notification icon */ 101 hr = pUserNotif->SetIconInfo(NULL, L"Tooltip text"); 102 ok_hr(hr, S_OK); 103 104 /* 105 * Since just displaying a notification icon without balloon hangs (expected), 106 * for making this test automatable we instead just test balloon functionality 107 * where timeouts can be programmed. 108 */ 109 110 /* Set up a balloon associated to the notification icon */ 111 hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_ERROR); 112 ok_hr(hr, S_OK); 113 114 /* 115 * Try to display twice the balloon if the user cancels it. 116 * Without setting balloon retry, we would wait for a very long time... 117 */ 118 hr = pUserNotif->SetBalloonRetry(2000, 1000, 2); 119 ok_hr(hr, S_OK); 120 121 /* Display the balloon and also the tooltip if one points on the icon */ 122 hr = pUserNotif->Show(NULL, 0); 123 ok_hr(hr, HRESULT_CANCELLED); 124 125 /* 126 * Setting icon information *after* having enabled balloon info, 127 * allows to automatically set the notification icon according 128 * to the dwInfoFlags passed to SetBalloonInfo() and by giving 129 * NULL to the hIcon parameter of SetIconInfo(). 130 */ 131 hr = pUserNotif->SetIconInfo(NULL, NULL); 132 ok_hr(hr, S_OK); 133 134 /* Display the balloon and also the tooltip if one points on the icon */ 135 hr = pUserNotif->Show(NULL, 0); 136 ok_hr(hr, HRESULT_CANCELLED); 137 138 /* 139 * This line shows the balloon, but without title nor icon in it. 140 * Note that the balloon icon is not displayed when not setting any title. 141 */ 142 hr = pUserNotif->SetBalloonInfo(NULL, L"Balloon text", NIIF_WARNING); 143 ok_hr(hr, S_OK); 144 145 hr = pUserNotif->Show(NULL, 0); 146 ok_hr(hr, HRESULT_CANCELLED); 147 148 149 /* Test support of the IQueryContinue interface */ 150 151 hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_WARNING); 152 ok_hr(hr, S_OK); 153 154 hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ 155 ok_hr(hr, HRESULT_CANCELLED); 156 157 #if 0 // Commented because this test (the Show() call) is unreliable. 158 /* Try to hide the balloon by setting an empty string (can use either NULL or L"") */ 159 hr = pUserNotif->SetBalloonInfo(L"Balloon title", NULL, NIIF_WARNING); 160 ok_hr(hr, S_OK); 161 162 hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ 163 ok_hr(hr, HRESULT_CANCELLED); 164 #endif 165 166 hr = pUserNotif->SetBalloonInfo(L"Balloon title", L"Balloon text", NIIF_WARNING); 167 ok_hr(hr, S_OK); 168 169 queryContinue = S_FALSE; 170 hr = pUserNotif->Show(&queryContinue, 2000); /* Timeout of 2 seconds */ 171 ok_hr(hr, S_FALSE); 172 } 173 174 DWORD 175 CALLBACK 176 TestThread(LPVOID lpParam) 177 { 178 /* Initialize COM */ 179 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 180 181 /* Start the test */ 182 TestNotification(); 183 184 /* Cleanup and return */ 185 CoUninitialize(); 186 return 0; 187 } 188 189 START_TEST(CUserNotification) 190 { 191 HANDLE hThread; 192 DWORD dwWait; 193 194 /* We create a test thread, because the notification tests can hang */ 195 hThread = CreateThread(NULL, 0, TestThread, NULL, 0, NULL); 196 ok(hThread != NULL, "CreateThread failed with error 0x%lu\n", GetLastError()); 197 if (!hThread) 198 { 199 skip("Could not create the CUserNotification test thread!\n"); 200 return; 201 } 202 203 /* Wait a maximum of 60 seconds for the thread to finish (the timeout tests take some time) */ 204 dwWait = WaitForSingleObject(hThread, 60 * 1000); 205 ok(dwWait == WAIT_OBJECT_0, "WaitForSingleObject returned %lu, expected WAIT_OBJECT_0\n", dwWait); 206 207 /* Cleanup and return */ 208 CloseHandle(hThread); 209 } 210