Reactos
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