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