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