Reactos
at master 460 lines 16 kB view raw
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 17BOOL 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 31class CDummyWindow : public CUnknownBase<IOleWindow> 32{ 33protected: 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 42public: 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 61BOOL 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 77void 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 160void 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 sequences of callbacks */ 211 struct _test_info{ 212 int iTest; 213 UINT uMsg;}; 214 215class CMenuCallback : public CUnknownBase<IShellMenuCallback> 216{ 217protected: 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 229public: 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 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 == 0x13) 254 { 255 return S_OK; 256 } 257 258 m_iCallback++; 259 if (m_iCallback > m_testsCount) 260 { 261 ok(FALSE, "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 if (!g_bVista || uMsg != 0x38) // Vista bug 268 ok(psmd != NULL, "Got NULL psmd\n"); 269 ok(m_iTest == result->iTest, "Wrong test number (%d not %d)\n", m_iTest, result->iTest); 270 ok(result->uMsg == uMsg, "%d: Got wrong uMsg (%d instead of %d)\n", m_iCallback, uMsg, result->uMsg); 271 272 if (uMsg == SMC_CREATE) 273 { 274 ok(psmd->dwFlags == 0, "wrong dwFlags\n"); 275 ok(psmd->dwMask == 0, "wrong dwMask\n"); 276 ok(psmd->hmenu == 0, "wrong hmenu\n"); 277 ok(psmd->hwnd == 0, "wrong hwnd\n"); 278 ok(psmd->punk != NULL, "punk is null\n"); 279 } 280 281 if (uMsg == SMC_GETSFOBJECT) 282 { 283 ok(psmd->psf != 0, "wrong dwFlags\n"); 284 } 285 286 return S_FALSE; 287 } 288}; 289 290void test_CShellMenu_callbacks(IShellFolder *shellFolder, HMENU hmenu) 291{ 292 HRESULT hResult; 293 IShellMenu* shellMenu; 294 IDockingWindow* dockingMenu; 295 IObjectWithSite *menuWithSite; 296 CMenuCallback *callback; 297 298 HWND hWndParent = CreateWindowExW(0, L"EDIT", L"miau", 0, CW_USEDEFAULT, CW_USEDEFAULT, 299 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL); 300 CDummyWindow* dummyWindow = new CDummyWindow(hWndParent); 301 ShowWindow(hWndParent, SW_SHOW); 302 303 if (!CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite)) 304 { 305 skip("failed to create CShellMenuObject\n"); 306 delete dummyWindow; 307 return; 308 } 309 310 if (GetNTVersion() <= _WIN32_WINNT_WS03) 311 { 312 struct _test_info cbtest_info[] = { {1, SMC_CREATE}, 313 {2, SMC_GETSFOBJECT}, 314 {3, SMC_SFEXEC_MIDDLE}, 315 {4, SMC_INITMENU}, 316 {4, 0x35}, 317 {4, 0x13}, 318 {4, 0x14}, 319 {4, 0x13}, 320 {4, 0x14}, 321 {4, SMC_GETSFOBJECT}, 322 {4, 0x18}, 323 {4, SMC_GETINFO}, 324 {4, SMC_GETINFO}, 325 {4, SMC_GETINFO}, 326 {4, SMC_GETINFO}, 327 {4, SMC_GETINFO}, 328 {4, SMC_GETINFO} }; 329 330 callback = new CMenuCallback(cbtest_info, _countof(cbtest_info)); 331 } 332 333 else 334 { 335 struct _test_info cbtest_info[] = { {1, SMC_CREATE}, 336 {2, SMC_GETSFOBJECT}, 337 {3, SMC_SFEXEC_MIDDLE}, 338 {4, SMC_INITMENU}, 339 {4, 0x38}, 340 {4, 0x35}, 341 {4, 0x13}, 342 {4, 0x14}, 343 {4, 0x13}, 344 {4, 0x14}, 345 {4, SMC_GETSFOBJECT}, 346 {4, 0x18}, 347 {4, SMC_GETINFO}, 348 {4, SMC_GETINFO}, 349 {4, SMC_GETINFO}, 350 {4, SMC_GETINFO}, 351 {4, SMC_GETINFO} }; 352 353 callback = new CMenuCallback(cbtest_info, _countof(cbtest_info)); 354 } 355 356 callback->SetTest(1); 357 hResult = shellMenu->Initialize(callback, 0,ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 358 test_S_OK(hResult, "Initialize failed"); 359 360 callback->SetTest(2); 361 hResult = shellMenu->SetShellFolder(shellFolder, NULL, NULL, 0); 362 test_S_OK(hResult, "SetShellFolder failed"); 363 364 callback->SetTest(3); 365 hResult = shellMenu->SetMenu(hmenu, hWndParent, SMSET_TOP); 366 test_S_OK(hResult, "SetMenu failed"); 367 368 hResult = menuWithSite->SetSite(dummyWindow); 369 test_S_OK(hResult, "SetSite failed"); 370 371 callback->SetTest(4); 372 hResult = dockingMenu->ShowDW(TRUE); 373 test_HRES(hResult, S_FALSE, "ShowDW failed"); 374} 375 376void test_CShellMenu_with_DeskBar(IShellFolder *shellFolder, HMENU hmenu) 377{ 378 HRESULT hResult; 379 IShellMenu* shellMenu; 380 IDockingWindow* dockingMenu; 381 IObjectWithSite *menuWithSite; 382 IMenuPopup* menuPopup; 383 IBandSite* bandSite; 384 385 /* Create the tree objects and query the nescesary interfaces */ 386 BOOL bCreated = CreateCShellMenu(&shellMenu, &dockingMenu, &menuWithSite); 387 hResult = CoCreateInstance(CLSID_MenuDeskBar, NULL, CLSCTX_INPROC_SERVER, IID_IMenuPopup, reinterpret_cast<void **>(&menuPopup)); 388 test_S_OK(hResult, "Failed to instantiate CLSID_MenuDeskBar"); 389 hResult = CoCreateInstance(CLSID_MenuBandSite, NULL, CLSCTX_INPROC_SERVER, IID_IBandSite, reinterpret_cast<void **>(&bandSite)); 390 test_S_OK(hResult, "Failed to instantiate CLSID_MenuBandSite"); 391 if (!bCreated || !menuPopup || !bandSite) 392 { 393 skip("failed to create MenuBandSite object\n"); 394 return; 395 } 396 397 /* Create the popup menu */ 398 hResult = shellMenu->Initialize(NULL, 0, ANCESTORDEFAULT, SMINIT_TOPLEVEL|SMINIT_VERTICAL); 399 test_S_OK(hResult, "Initialize failed"); 400 hResult = shellMenu->SetMenu( hmenu, NULL, SMSET_TOP); 401 test_S_OK(hResult, "SetMenu failed"); 402 hResult = menuPopup->SetClient(bandSite); 403 test_S_OK(hResult, "SetClient failed"); 404 hResult = bandSite->AddBand(shellMenu); 405 test_S_OK(hResult, "AddBand failed"); 406 407 /* Show the popum menu */ 408 POINTL p = {10,10}; 409 hResult = menuPopup->Popup(&p, NULL, 0); 410 test_HRES(hResult, S_FALSE, "Popup failed"); 411 412 HWND hWndToolbar, hWndToplevel; 413 414 /* Ensure that the created windows are correct */ 415 hResult = dockingMenu->GetWindow(&hWndToolbar); 416 test_S_OK(hResult, "GetWindow failed"); 417 ok(hWndToolbar != NULL, "GetWindow should return a window\n"); 418 419 hResult = menuPopup->GetWindow(&hWndToplevel); 420 test_S_OK(hResult, "GetWindow failed"); 421 ok(hWndToolbar != NULL, "GetWindow should return a window\n"); 422 423 HWND hwndRealParent = GetParent(hWndToolbar); 424 ok(GetParent(hwndRealParent) == hWndToplevel, "Wrong parent\n"); 425 ok(CheckWindowClass(hWndToolbar, L"ToolbarWindow32"), "Wrong class\n"); 426 ok(CheckWindowClass(hwndRealParent, L"MenuSite"), "Wrong class\n"); 427 ok(CheckWindowClass(hWndToplevel, L"BaseBar"), "Wrong class\n"); 428 429 ok(GetAncestor (hWndToplevel, GA_PARENT) == GetDesktopWindow(), "Expected the BaseBar window to be top level\n"); 430} 431 432START_TEST(menu) 433{ 434 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 435 436 IShellFolder *shellFolder; 437 HRESULT hResult; 438 hResult = SHGetDesktopFolder(&shellFolder); 439 test_S_OK(hResult, "SHGetDesktopFolder failed"); 440 441 HMENU hSubMenu = CreatePopupMenu(); 442 AppendMenuW(hSubMenu, 0,0, L"Submenu item1"); 443 AppendMenuW(hSubMenu, 0,0, L"Submenu item2"); 444 HMENU hmenu = CreatePopupMenu(); 445 AppendMenuW(hmenu, 0,0, L"test"); 446 AppendMenuW(hmenu, 0,1, L"test1"); 447 MENUITEMINFOW iteminfo = {0}; 448 iteminfo.cbSize = sizeof(iteminfo); 449 iteminfo.hSubMenu = hSubMenu; 450 iteminfo.fMask = MIIM_STRING | MIIM_SUBMENU; 451 iteminfo.dwTypeData = const_cast<LPWSTR>(L"submenu"); 452 iteminfo.cch = 7; 453 InsertMenuItemW(hmenu, 0, TRUE, &iteminfo); 454 455 test_CShellMenu_params(); 456 test_CShellMenu(); 457 test_CShellMenu_callbacks(shellFolder, hmenu); 458 test_CShellMenu_with_DeskBar(shellFolder, hmenu); 459} 460