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