1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PURPOSE: Test for shell menu objects 5 * PROGRAMMERS: Giannis Adamopoulos 6 */ 7 8 #include "shelltest.h" 9 10 #include <shlwapi.h> 11 #include <unknownbase.h> 12 #include <shlguid_undoc.h> 13 14 #define test_S_OK(hres, message) ok(hres == S_OK, "%s (0x%lx instead of S_OK)\n",message, hResult); 15 #define test_HRES(hres, hresExpected, message) ok(hres == hresExpected, "%s (0x%lx instead of 0x%lx)\n",message, hResult,hresExpected); 16 17 BOOL CheckWindowClass(HWND hwnd, PCWSTR className) 18 { 19 ULONG size = (lstrlenW(className) + 1)* sizeof(WCHAR); 20 PWCHAR buffer = (PWCHAR)malloc(size); 21 if (GetClassNameW(hwnd, buffer, size ) == 0) 22 { 23 free(buffer); 24 return FALSE; 25 } 26 int res = wcscmp(buffer, className); 27 free(buffer); 28 return res == 0; 29 } 30 31 class CDummyWindow : public CUnknownBase<IOleWindow> 32 { 33 protected: 34 HWND m_hwnd; 35 36 const QITAB* GetQITab() 37 { 38 static const QITAB tab[] = {{ &IID_IOleWindow, OFFSETOFCLASS(IOleWindow, CDummyWindow) }, {0}}; 39 return tab; 40 } 41 42 public: 43 CDummyWindow(HWND hwnd) 44 :CUnknownBase( true, 0 ) 45 { 46 m_hwnd = hwnd; 47 } 48 49 HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd) 50 { 51 *phwnd = m_hwnd; 52 return S_OK; 53 } 54 55 HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode) 56 { 57 return S_OK; 58 } 59 }; 60 61 BOOL CreateCShellMenu(IShellMenu** shellMenu, IDockingWindow** dockingMenu, IObjectWithSite **menuWithSite) 62 { 63 HRESULT hResult; 64 hResult = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER, IID_IShellMenu, reinterpret_cast<void **>(shellMenu)); 65 test_S_OK(hResult, "Failed to instantiate CLSID_MenuBand"); 66 if (!shellMenu) return FALSE; 67 68 hResult = (*shellMenu)->QueryInterface(IID_IDockingWindow, reinterpret_cast<void **>(dockingMenu)); 69 test_S_OK(hResult, "Failed to query IID_IDockingWindow"); 70 hResult = (*shellMenu)->QueryInterface(IID_IObjectWithSite, reinterpret_cast<void **>(menuWithSite)); 71 test_S_OK(hResult, "Failed to query IID_IObjectWithSite"); 72 if (!dockingMenu || !menuWithSite) return FALSE; 73 return TRUE; 74 } 75 76 77 void test_CShellMenu_params() 78 { 79 HRESULT hResult; 80 IShellMenu* shellMenu; 81 IDockingWindow* dockingMenu; 82 IObjectWithSite* menuWithSite; 83 84 IShellMenuCallback *psmc; 85 UINT uId; 86 UINT uIdAncestor; 87 DWORD dwFlags; 88 HWND hwndToolbar; 89 HMENU hmenu; 90 HWND hwndOwner; 91 DWORD menuFlagss; 92 IShellFolder *shellFolder; 93 94 if (!CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite)) 95 { 96 skip("failed to create CShellMenuObject\n"); 97 return; 98 } 99 100 hResult = shellMenu->Initialize(NULL, 11, 22, 0xdeadbeef); 101 test_S_OK(hResult, "Initialize failed"); 102 103 hResult = shellMenu->GetMenuInfo(&psmc, &uId, &uIdAncestor, &dwFlags); 104 test_S_OK(hResult, "GetMenuInfo failed"); 105 ok (psmc == NULL, "wrong psmc\n"); 106 ok (uId == 11, "wrong uid\n"); 107 ok (uIdAncestor == 22, "wrong uIdAncestor\n"); 108 ok (dwFlags == 0xdeadbeef, "wrong dwFlags\n"); 109 110 hResult = shellMenu->Initialize(NULL, 0, ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 111 test_S_OK(hResult, "Initialize failed"); 112 113 hResult = dockingMenu->GetWindow(&hwndToolbar); 114 test_HRES(hResult, E_FAIL, "GetWindow should fail"); 115 116 hResult = shellMenu->GetMenu(&hmenu, &hwndOwner, &menuFlagss); 117 test_HRES(hResult, E_FAIL, "GetMenu should fail"); 118 119 hmenu = CreatePopupMenu(); 120 hResult = shellMenu->SetMenu(hmenu, NULL, 0); 121 test_S_OK(hResult, "SetMenu failed"); 122 123 hwndToolbar = (HWND)UlongToPtr(0xdeadbeef); 124 hResult = dockingMenu->GetWindow(&hwndToolbar); 125 test_S_OK(hResult, "GetWindow failed"); 126 ok (hwndToolbar == NULL, "Expected NULL window\n"); 127 128 hResult = shellMenu->SetMenu(NULL, NULL, 0); 129 test_S_OK(hResult, "SetMenu failed"); 130 131 hResult = shellMenu->GetMenu(&hmenu, &hwndOwner, &menuFlagss); 132 test_S_OK(hResult, "GetMenu failed"); 133 ok (hmenu == NULL, "Got a menu\n"); 134 135 hResult = dockingMenu->GetWindow(&hwndToolbar); 136 test_S_OK(hResult, "GetWindow failed"); 137 138 hResult = SHGetDesktopFolder(&shellFolder); 139 test_S_OK(hResult, "SHGetDesktopFolder failed"); 140 141 hResult = shellMenu->SetShellFolder(shellFolder, NULL, 0, 0); 142 test_S_OK(hResult, "SetShellFolder failed"); 143 144 hResult = shellMenu->SetShellFolder(NULL, NULL, 0, 0); 145 test_HRES(hResult, E_INVALIDARG, "SetShellFolder should fail"); 146 147 hwndToolbar = (HWND)UlongToHandle(0xdeadbeef); 148 hResult = dockingMenu->GetWindow(&hwndToolbar); 149 test_S_OK(hResult, "GetWindow failed"); 150 ok (hwndToolbar == NULL, "Expected NULL window\n"); 151 152 hResult = dockingMenu->ShowDW(TRUE); 153 test_HRES(hResult, S_FALSE, "ShowDW should fail"); 154 155 menuWithSite->Release(); 156 dockingMenu->Release(); 157 shellMenu->Release(); 158 } 159 160 void test_CShellMenu() 161 { 162 HRESULT hResult; 163 IShellMenu* shellMenu; 164 IDockingWindow* dockingMenu; 165 IShellFolder *shellFolder; 166 IObjectWithSite *menuWithSite; 167 HWND hwndToolbar; 168 169 HWND hWndParent = CreateWindowExW(0, L"EDIT", L"miau", 0, CW_USEDEFAULT, CW_USEDEFAULT, 170 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL); 171 CDummyWindow* dummyWindow = new CDummyWindow(hWndParent); 172 173 if (!CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite)) 174 { 175 skip("failed to create CShellMenuObject\n"); 176 delete dummyWindow; 177 return; 178 } 179 180 hResult = SHGetDesktopFolder(&shellFolder); 181 test_S_OK(hResult, "SHGetDesktopFolder failed"); 182 183 hResult = shellMenu->Initialize(NULL, 0, ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 184 test_S_OK(hResult, "Initialize failed"); 185 186 hResult = shellMenu->SetShellFolder(shellFolder, NULL, NULL, 0); 187 test_S_OK(hResult, "SetShellFolder failed"); 188 189 hResult = menuWithSite->SetSite(dummyWindow); 190 test_S_OK(hResult, "SetSite failed"); 191 192 hResult = dockingMenu->GetWindow(&hwndToolbar); 193 test_S_OK(hResult, "GetWindow failed"); 194 ok(hwndToolbar != NULL, "GetWindow should return a window\n"); 195 196 HWND hwndRealParent = GetParent(hwndToolbar); 197 ok(GetParent(hwndRealParent) == hWndParent, "Wrong parent\n"); 198 ok(CheckWindowClass(hwndToolbar, L"ToolbarWindow32"), "Wrong class\n"); 199 ok(CheckWindowClass(hwndRealParent, L"SysPager"), "Wrong class\n"); 200 201 menuWithSite->Release(); 202 dockingMenu->Release(); 203 shellMenu->Release(); 204 ok(!IsWindow(hwndToolbar), "The toolbar window should not exist\n"); 205 206 DestroyWindow(hWndParent); 207 } 208 209 /* The folowing struct holds info about the order callbacks are called */ 210 /* By passing different arrays of results to CMenuCallback, we can test different sequenses of callbacks */ 211 struct _test_info{ 212 int iTest; 213 UINT uMsg;}; 214 215 class CMenuCallback : public CUnknownBase<IShellMenuCallback> 216 { 217 protected: 218 int m_iTest; 219 int m_iCallback; 220 struct _test_info *m_results; 221 int m_testsCount; 222 223 const QITAB* GetQITab() 224 { 225 static const QITAB tab[] = {{ &IID_IShellMenuCallback, OFFSETOFCLASS(IShellMenuCallback, CMenuCallback) }, {0}}; 226 return tab; 227 } 228 229 public: 230 CMenuCallback(struct _test_info *testResults, int testsCount) 231 :CUnknownBase( true, 0 ) 232 { 233 m_iTest = 0; 234 m_iCallback = 0; 235 m_results = testResults; 236 m_testsCount = testsCount; 237 } 238 239 void SetTest(int i) 240 { 241 m_iTest = i; 242 } 243 244 HRESULT STDMETHODCALLTYPE CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam) 245 { 246 /*trace ("callback type %d\n", uMsg);*/ 247 248 /* 249 * it seems callback 0x10000000 is called for every item added so 250 * we will ignore consecutive callbacks of this type 251 * Note: this callback is invoked by shell32.dll!CMenuSFToolbar::_FilterPidl 252 */ 253 if (uMsg == 0x10000000 && m_results[m_iCallback-1].uMsg == 0x10000000) 254 { 255 return S_OK; 256 } 257 258 m_iCallback++; 259 if (m_iCallback > m_testsCount) 260 { 261 ok(0, "Got more callbacks than expected! (%d not %d). uMsg: %d\n", m_iCallback, m_testsCount, uMsg); 262 return S_OK; 263 } 264 265 struct _test_info *result = &m_results[m_iCallback-1]; 266 267 ok(psmd != NULL, "Got NULL psmd\n"); 268 ok(m_iTest == result->iTest, "Wrong test number (%d not %d)\n", m_iTest, result->iTest); 269 ok(result->uMsg == uMsg, "%d: Got wrong uMsg (%d instead of %d)\n", m_iCallback, uMsg, result->uMsg); 270 271 if(uMsg == SMC_CREATE) 272 { 273 ok(psmd->dwFlags == 0, "wrong dwFlags\n"); 274 ok(psmd->dwMask == 0, "wrong dwMask\n"); 275 ok(psmd->hmenu == 0, "wrong hmenu\n"); 276 ok(psmd->hwnd == 0, "wrong hwnd\n"); 277 ok(psmd->punk != NULL, "punk is null\n"); 278 } 279 280 if (uMsg == SMC_GETSFOBJECT) 281 { 282 ok(psmd->psf != 0, "wrong dwFlags\n"); 283 } 284 285 return S_FALSE; 286 } 287 }; 288 289 void test_CShellMenu_callbacks(IShellFolder *shellFolder, HMENU hmenu) 290 { 291 HRESULT hResult; 292 IShellMenu* shellMenu; 293 IDockingWindow* dockingMenu; 294 IObjectWithSite *menuWithSite; 295 CMenuCallback *callback; 296 297 HWND hWndParent = CreateWindowExW(0, L"EDIT", L"miau", 0, CW_USEDEFAULT, CW_USEDEFAULT, 298 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL); 299 CDummyWindow* dummyWindow = new CDummyWindow(hWndParent); 300 ShowWindow(hWndParent, SW_SHOW); 301 302 if (!CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite)) 303 { 304 skip("failed to create CShellMenuObject\n"); 305 delete dummyWindow; 306 return; 307 } 308 309 struct _test_info cbtest_info[] = { {1, SMC_CREATE}, 310 {2, SMC_GETSFOBJECT}, 311 {3, 0x31}, 312 {4, SMC_INITMENU}, 313 {4, 53}, 314 {4, 19}, 315 {4, 0x10000000}, 316 {4, SMC_NEWITEM}, 317 {4, 20}, 318 {4, 19}, 319 {4, 6}, 320 {4, 20}, 321 {4, 8}, 322 {4, 24}, 323 {4, 5}, 324 {4, 5}, 325 {4, 5}}; 326 327 callback = new CMenuCallback(cbtest_info,18); 328 329 callback->SetTest(1); 330 hResult = shellMenu->Initialize(callback, 0,ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 331 test_S_OK(hResult, "Initialize failed"); 332 333 callback->SetTest(2); 334 hResult = shellMenu->SetShellFolder(shellFolder, NULL, NULL, 0); 335 test_S_OK(hResult, "SetShellFolder failed"); 336 337 callback->SetTest(3); 338 hResult = shellMenu->SetMenu(hmenu, hWndParent, SMSET_TOP); 339 test_S_OK(hResult, "SetMenu failed"); 340 341 hResult = menuWithSite->SetSite(dummyWindow); 342 test_S_OK(hResult, "SetSite failed"); 343 344 callback->SetTest(4); 345 hResult = dockingMenu->ShowDW(TRUE); 346 test_HRES(hResult, S_FALSE, "ShowDW failed"); 347 } 348 349 void test_CShellMenu_with_DeskBar(IShellFolder *shellFolder, HMENU hmenu) 350 { 351 HRESULT hResult; 352 IShellMenu* shellMenu; 353 IDockingWindow* dockingMenu; 354 IObjectWithSite *menuWithSite; 355 IMenuPopup* menuPopup; 356 IBandSite* bandSite; 357 358 /* Create the tree objects and query the nescesary interfaces */ 359 BOOL bCreated = CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite); 360 hResult = CoCreateInstance(CLSID_MenuDeskBar, NULL, CLSCTX_INPROC_SERVER, IID_IMenuPopup, reinterpret_cast<void **>(&menuPopup)); 361 test_S_OK(hResult, "Failed to instantiate CLSID_MenuDeskBar"); 362 hResult = CoCreateInstance(CLSID_MenuBandSite, NULL, CLSCTX_INPROC_SERVER, IID_IBandSite, reinterpret_cast<void **>(&bandSite)); 363 test_S_OK(hResult, "Failed to instantiate CLSID_MenuBandSite"); 364 if (!bCreated || !menuPopup || !bandSite) 365 { 366 skip("failed to create MenuBandSite object\n"); 367 return; 368 } 369 370 /* Create the popup menu */ 371 hResult = shellMenu->Initialize(NULL, 0, ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 372 test_S_OK(hResult, "Initialize failed"); 373 hResult = shellMenu->SetMenu( hmenu, NULL, SMSET_TOP); 374 test_S_OK(hResult, "SetMenu failed"); 375 hResult = menuPopup->SetClient(bandSite); 376 test_S_OK(hResult, "SetClient failed"); 377 hResult = bandSite->AddBand(shellMenu); 378 test_S_OK(hResult, "AddBand failed"); 379 380 /* Show the popum menu */ 381 POINTL p = {10,10}; 382 hResult = menuPopup->Popup(&p, NULL, 0); 383 test_HRES(hResult, S_FALSE, "Popup failed"); 384 385 HWND hWndToolbar, hWndToplevel; 386 387 /* Ensure that the created windows are correct */ 388 hResult = dockingMenu->GetWindow(&hWndToolbar); 389 test_S_OK(hResult, "GetWindow failed"); 390 ok(hWndToolbar != NULL, "GetWindow should return a window\n"); 391 392 hResult = menuPopup->GetWindow(&hWndToplevel); 393 test_S_OK(hResult, "GetWindow failed"); 394 ok(hWndToolbar != NULL, "GetWindow should return a window\n"); 395 396 HWND hwndRealParent = GetParent(hWndToolbar); 397 ok(GetParent(hwndRealParent) == hWndToplevel, "Wrong parent\n"); 398 ok(CheckWindowClass(hWndToolbar, L"ToolbarWindow32"), "Wrong class\n"); 399 ok(CheckWindowClass(hwndRealParent, L"MenuSite"), "Wrong class\n"); 400 ok(CheckWindowClass(hWndToplevel, L"BaseBar"), "Wrong class\n"); 401 402 ok(GetAncestor (hWndToplevel, GA_PARENT) == GetDesktopWindow(), "Expected the BaseBar window to be top level\n"); 403 } 404 405 START_TEST(menu) 406 { 407 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 408 409 IShellFolder *shellFolder; 410 HRESULT hResult; 411 hResult = SHGetDesktopFolder(&shellFolder); 412 test_S_OK(hResult, "SHGetDesktopFolder failed"); 413 414 HMENU hSubMenu = CreatePopupMenu(); 415 AppendMenuW(hSubMenu, 0,0, L"Submenu item1"); 416 AppendMenuW(hSubMenu, 0,0, L"Submenu item2"); 417 HMENU hmenu = CreatePopupMenu(); 418 AppendMenuW(hmenu, 0,0, L"test"); 419 AppendMenuW(hmenu, 0,1, L"test1"); 420 MENUITEMINFOW iteminfo = {0}; 421 iteminfo.cbSize = sizeof(iteminfo); 422 iteminfo.hSubMenu = hSubMenu; 423 iteminfo.fMask = MIIM_STRING | MIIM_SUBMENU; 424 iteminfo.dwTypeData = const_cast<LPWSTR>(L"submenu"); 425 iteminfo.cch = 7; 426 InsertMenuItemW(hmenu, 0, TRUE, &iteminfo); 427 428 test_CShellMenu_params(); 429 test_CShellMenu(); 430 test_CShellMenu_callbacks(shellFolder, hmenu); 431 test_CShellMenu_with_DeskBar(shellFolder, hmenu); 432 } 433 434