windowscodecs: Handle TIFF's with RowsPerStrip greater than Height.
[wine] / dlls / shell32 / tests / ebrowser.c
1 /*
2  *    Unit tests for the Explorer Browser control
3  *
4  * Copyright 2010 David Hedberg
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22
23 #define COBJMACROS
24
25 #include "shlobj.h"
26
27 #include "wine/test.h"
28
29 static HWND hwnd;
30
31 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
32 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
33
34 static void init_function_pointers(void)
35 {
36     HMODULE hmod;
37
38     hmod = GetModuleHandleA("shell32.dll");
39     pSHCreateShellItem = (void*)GetProcAddress(hmod, "SHCreateShellItem");
40     pSHParseDisplayName = (void*)GetProcAddress(hmod, "SHParseDisplayName");
41 }
42
43 /*********************************************************************
44  * Some simple helpers
45  */
46 static HRESULT ebrowser_instantiate(IExplorerBrowser **peb)
47 {
48     return CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
49                             &IID_IExplorerBrowser, (void**)peb);
50 }
51
52 static HRESULT ebrowser_initialize(IExplorerBrowser *peb)
53 {
54     RECT rc;
55     rc.top = rc.left = 0; rc.bottom = rc.right = 500;
56     return IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
57 }
58
59 static HRESULT ebrowser_browse_to_desktop(IExplorerBrowser *peb)
60 {
61     LPITEMIDLIST pidl_desktop;
62     SHGetSpecialFolderLocation (hwnd, CSIDL_DESKTOP, &pidl_desktop);
63     return IExplorerBrowser_BrowseToIDList(peb, pidl_desktop, 0);
64 }
65
66 /* Process some messages */
67 static void process_msgs(void)
68 {
69     MSG msg;
70     while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
71     {
72         TranslateMessage(&msg);
73         DispatchMessage(&msg);
74     }
75 }
76
77 /*********************************************************************
78  * IExplorerBrowserEvents implementation
79  */
80 typedef struct {
81     const IExplorerBrowserEventsVtbl *lpVtbl;
82     LONG ref;
83     UINT pending, created, completed, failed;
84 } IExplorerBrowserEventsImpl;
85
86 static IExplorerBrowserEventsImpl ebev;
87
88 static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
89                                                               REFIID riid, void **ppvObj)
90 {
91     ok(0, "Never called.\n");
92     return E_NOINTERFACE;
93 }
94
95 static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
96 {
97     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
98     return InterlockedIncrement(&This->ref);
99 }
100
101 static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
102 {
103     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
104     return InterlockedDecrement(&This->ref);
105 }
106
107 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
108                                                                    PCIDLIST_ABSOLUTE pidlFolder)
109 {
110     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
111     This->pending++;
112     return S_OK;
113 }
114
115 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
116                                                                     PCIDLIST_ABSOLUTE pidlFolder)
117 {
118     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
119     This->completed++;
120     return S_OK;
121 }
122 static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
123                                                                   PCIDLIST_ABSOLUTE pidlFolder)
124 {
125     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
126     This->failed++;
127     return S_OK;
128 }
129 static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
130                                                              IShellView *psv)
131 {
132     IExplorerBrowserEventsImpl *This = (IExplorerBrowserEventsImpl*)iface;
133     This->created++;
134     return S_OK;
135 }
136
137 static const IExplorerBrowserEventsVtbl ebevents =
138 {
139     IExplorerBrowserEvents_fnQueryInterface,
140     IExplorerBrowserEvents_fnAddRef,
141     IExplorerBrowserEvents_fnRelease,
142     IExplorerBrowserEvents_fnOnNavigationPending,
143     IExplorerBrowserEvents_fnOnViewCreated,
144     IExplorerBrowserEvents_fnOnNavigationComplete,
145     IExplorerBrowserEvents_fnOnNavigationFailed
146 };
147
148 static void test_QueryInterface(void)
149 {
150     IExplorerBrowser *peb;
151     IUnknown *punk;
152     HRESULT hr;
153     LONG lres;
154
155     hr = ebrowser_instantiate(&peb);
156     ok(hr == S_OK, "Got 0x%08x\n", hr);
157
158 #define test_qinterface(iid, exp)                                       \
159     do {                                                                \
160         hr = IExplorerBrowser_QueryInterface(peb, &iid, (void**)&punk); \
161         ok(hr == exp, "(%s:)Expected (0x%08x), got (0x%08x)\n",         \
162            #iid, exp, hr);                                              \
163         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
164     } while(0)
165
166     test_qinterface(IID_IUnknown, S_OK);
167     test_qinterface(IID_IExplorerBrowser, S_OK);
168     test_qinterface(IID_IShellBrowser, S_OK);
169     todo_wine test_qinterface(IID_IOleWindow, S_OK);
170     todo_wine test_qinterface(IID_ICommDlgBrowser, S_OK);
171     todo_wine test_qinterface(IID_ICommDlgBrowser2, S_OK);
172     todo_wine test_qinterface(IID_ICommDlgBrowser3, S_OK);
173     todo_wine test_qinterface(IID_IServiceProvider, S_OK);
174     todo_wine test_qinterface(IID_IObjectWithSite, S_OK);
175     todo_wine test_qinterface(IID_IConnectionPointContainer, S_OK);
176     test_qinterface(IID_IOleObject, E_NOINTERFACE);
177     test_qinterface(IID_IViewObject, E_NOINTERFACE);
178     test_qinterface(IID_IViewObject2, E_NOINTERFACE);
179     test_qinterface(IID_IViewObjectEx, E_NOINTERFACE);
180     test_qinterface(IID_IConnectionPoint, E_NOINTERFACE);
181     test_qinterface(IID_IShellView, E_NOINTERFACE);
182     test_qinterface(IID_INameSpaceTreeControlEvents, E_NOINTERFACE);
183
184 #undef test_qinterface
185
186     lres = IExplorerBrowser_Release(peb);
187     ok(lres == 0, "Got %d\n", lres);
188 }
189
190 static void test_SB_misc(void)
191 {
192     IExplorerBrowser *peb;
193     IShellBrowser *psb;
194     IUnknown *punk;
195     HRESULT hr;
196     HWND retHwnd;
197     LRESULT lres;
198     LONG ref;
199
200     ebrowser_instantiate(&peb);
201     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
202     ok(hr == S_OK, "Got 0x%08x\n", hr);
203     if(FAILED(hr))
204     {
205         skip("Failed to get IShellBrowser interface.\n");
206         return;
207     }
208
209     /* Some unimplemented methods */
210     retHwnd = (HWND)0xDEADBEEF;
211     hr = IShellBrowser_GetControlWindow(psb, FCW_TOOLBAR, &retHwnd);
212     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
213     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
214
215     hr = IShellBrowser_GetControlWindow(psb, FCW_STATUS, &retHwnd);
216     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
217     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
218
219     hr = IShellBrowser_GetControlWindow(psb, FCW_TREE, &retHwnd);
220     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
221     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
222
223     hr = IShellBrowser_GetControlWindow(psb, FCW_PROGRESS, &retHwnd);
224     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
225     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
226
227     /* ::InsertMenuSB */
228     hr = IShellBrowser_InsertMenusSB(psb, NULL, NULL);
229     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
230
231     /* ::RemoveMenusSB */
232     hr = IShellBrowser_RemoveMenusSB(psb, NULL);
233     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
234
235     /* ::SetMenuSB */
236     hr = IShellBrowser_SetMenuSB(psb, NULL, NULL, NULL);
237     ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
238
239     /***** Before EB::Initialize *****/
240
241     /* ::GetWindow */
242     retHwnd = (HWND)0xDEADBEEF;
243     hr = IShellBrowser_GetWindow(psb, &retHwnd);
244     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
245     ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
246
247     todo_wine
248     {
249
250         /* ::SendControlMsg */
251         lres = 0xDEADBEEF;
252         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
253         ok(hr == S_OK, "got (0x%08x)\n", hr);
254         ok(lres == 0, "lres was %ld\n", lres);
255
256         lres = 0xDEADBEEF;
257         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, TB_CHECKBUTTON,
258                                           FCIDM_TB_SMALLICON, TRUE, &lres);
259         ok(hr == S_OK, "got (0x%08x)\n", hr);
260         ok(lres == 0, "lres was %ld\n", lres);
261
262         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
263         ok(hr == S_OK, "got (0x%08x)\n", hr);
264
265         hr = IShellBrowser_SendControlMsg(psb, FCW_TREE, 0, 0, 0, NULL);
266         ok(hr == S_OK, "got (0x%08x)\n", hr);
267
268         hr = IShellBrowser_SendControlMsg(psb, FCW_PROGRESS, 0, 0, 0, NULL);
269         ok(hr == S_OK, "got (0x%08x)\n", hr);
270     }
271
272     /* ::QueryActiveShellView */
273     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
274     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
275
276     /* Initialize ExplorerBrowser */
277     ebrowser_initialize(peb);
278
279     /***** After EB::Initialize *****/
280
281     /* ::GetWindow */
282     hr = IShellBrowser_GetWindow(psb, &retHwnd);
283     ok(hr == S_OK, "got (0x%08x)\n", hr);
284     ok(GetParent(retHwnd) == hwnd, "The HWND returned is not our child.\n");
285
286     todo_wine
287     {
288         /* ::SendControlMsg */
289         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
290         ok(hr == S_OK, "got (0x%08x)\n", hr);
291
292         lres = 0xDEADBEEF;
293         hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, 0, 0, 0, &lres);
294         ok(hr == S_OK, "got (0x%08x)\n", hr);
295         ok(lres == 0, "lres was %ld\n", lres);
296
297         lres = 0xDEADBEEF;
298         hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
299         ok(hr == S_OK, "got (0x%08x)\n", hr);
300         ok(lres == 0, "lres was %ld\n", lres);
301
302         lres = 0xDEADBEEF;
303         hr = IShellBrowser_SendControlMsg(psb, 1234, 0, 0, 0, &lres);
304         ok(hr == S_OK, "got (0x%08x)\n", hr);
305         ok(lres == 0, "lres was %ld\n", lres);
306
307         /* Returns S_OK */
308         hr = IShellBrowser_SetStatusTextSB(psb, NULL);
309         ok(hr == S_OK, "got (0x%08x)\n", hr);
310
311         hr = IShellBrowser_ContextSensitiveHelp(psb, FALSE);
312         ok(hr == S_OK, "got (0x%08x)\n", hr);
313
314         hr = IShellBrowser_EnableModelessSB(psb, TRUE);
315         ok(hr == S_OK, "got (0x%08x)\n", hr);
316
317         hr = IShellBrowser_SetToolbarItems(psb, NULL, 1, 1);
318         ok(hr == S_OK, "got (0x%08x)\n", hr);
319     }
320
321     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
322     ok(hr == E_FAIL, "got (0x%08x)\n", hr);
323
324     IShellBrowser_Release(psb);
325     IExplorerBrowser_Destroy(peb);
326     IExplorerBrowser_Release(peb);
327
328     /* Browse to the desktop. */
329     ebrowser_instantiate(&peb);
330     ebrowser_initialize(peb);
331     IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
332
333     process_msgs();
334     hr = ebrowser_browse_to_desktop(peb);
335     ok(hr == S_OK, "got (0x%08x)\n", hr);
336     process_msgs();
337
338     /****** After Browsing *****/
339
340     hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
341     ok(hr == S_OK, "got (0x%08x)\n", hr);
342     if(SUCCEEDED(hr)) IUnknown_Release(punk);
343
344     IShellBrowser_Release(psb);
345     IExplorerBrowser_Destroy(peb);
346     ref = IExplorerBrowser_Release(peb);
347     ok(ref == 0, "Got %d\n", ref);
348 }
349
350 static void test_initialization(void)
351 {
352     IExplorerBrowser *peb;
353     IShellBrowser *psb;
354     HRESULT hr;
355     ULONG lres;
356     RECT rc;
357
358     ebrowser_instantiate(&peb);
359
360     if(0)
361     {
362         /* Crashes on Windows 7 */
363         hr = IExplorerBrowser_Initialize(peb, NULL, NULL, NULL);
364         hr = IExplorerBrowser_Initialize(peb, hwnd, NULL, NULL);
365     }
366
367     ZeroMemory(&rc, sizeof(RECT));
368
369     hr = IExplorerBrowser_Initialize(peb, NULL, &rc, NULL);
370     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
371
372     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
373     ok(hr == S_OK, "got (0x%08x)\n", hr);
374
375     /* Initialize twice */
376     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
377     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
378
379     hr = IExplorerBrowser_Destroy(peb);
380     ok(hr == S_OK, "got (0x%08x)\n", hr);
381
382     /* Initialize again */
383     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
384     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
385
386     /* Destroy again */
387     hr = IExplorerBrowser_Destroy(peb);
388     ok(hr == S_OK, "got (0x%08x)\n", hr);
389     lres = IExplorerBrowser_Release(peb);
390     ok(lres == 0, "Got %d\n", lres);
391
392     /* Initialize with a few different rectangles */
393     peb = NULL;
394     ebrowser_instantiate(&peb);
395     rc.left = 50; rc.top = 20; rc.right = 100; rc.bottom = 80;
396     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
397     ok(hr == S_OK, "got (0x%08x)\n", hr);
398     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
399     ok(hr == S_OK, "Got 0x%08x\n", hr);
400     if(SUCCEEDED(hr))
401     {
402         HWND eb_hwnd;
403         RECT eb_rc;
404         char buf[1024];
405         LONG style, expected_style;
406         static const RECT exp_rc = {0, 0, 48, 58};
407
408         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
409         ok(hr == S_OK, "Got 0x%08x\n", hr);
410
411         GetClientRect(eb_hwnd, &eb_rc);
412         ok(EqualRect(&eb_rc, &exp_rc), "Got client rect (%d, %d)-(%d, %d)\n",
413            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
414
415         GetWindowRect(eb_hwnd, &eb_rc);
416         ok(eb_rc.right - eb_rc.left == 50, "Got window width %d\n", eb_rc.right - eb_rc.left);
417         ok(eb_rc.bottom - eb_rc.top == 60, "Got window height %d\n", eb_rc.bottom - eb_rc.top);
418
419         buf[0] = '\0';
420         GetClassNameA(eb_hwnd, buf, 1024);
421         ok(!lstrcmpA(buf, "ExplorerBrowserControl"), "Unexpected classname %s\n", buf);
422
423         expected_style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
424         style = GetWindowLongPtrW(eb_hwnd, GWL_STYLE);
425         todo_wine ok(style == expected_style, "Got style 0x%08x, expected 0x%08x\n", style, expected_style);
426
427         expected_style = WS_EX_CONTROLPARENT;
428         style = GetWindowLongPtrW(eb_hwnd, GWL_EXSTYLE);
429         ok(style == expected_style, "Got exstyle 0x%08x, expected 0x%08x\n", style, expected_style);
430
431         ok(GetParent(eb_hwnd) == hwnd, "GetParent returns %p\n", GetParent(eb_hwnd));
432
433         /* ::Destroy() destroys the window. */
434         ok(IsWindow(eb_hwnd), "eb_hwnd invalid.\n");
435         IExplorerBrowser_Destroy(peb);
436         ok(!IsWindow(eb_hwnd), "eb_hwnd valid.\n");
437
438         IShellBrowser_Release(psb);
439         lres = IExplorerBrowser_Release(peb);
440         ok(lres == 0, "Got refcount %d\n", lres);
441     }
442     else
443     {
444         skip("Skipping some tests.\n");
445
446         IExplorerBrowser_Destroy(peb);
447         lres = IExplorerBrowser_Release(peb);
448         ok(lres == 0, "Got refcount %d\n", lres);
449     }
450
451     ebrowser_instantiate(&peb);
452     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
453     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
454     ok(hr == S_OK, "got (0x%08x)\n", hr);
455     IExplorerBrowser_Destroy(peb);
456     lres = IExplorerBrowser_Release(peb);
457     ok(lres == 0, "Got refcount %d\n", lres);
458
459     ebrowser_instantiate(&peb);
460     rc.left = -1; rc.top = -1; rc.right = 1; rc.bottom = 1;
461     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
462     ok(hr == S_OK, "got (0x%08x)\n", hr);
463     IExplorerBrowser_Destroy(peb);
464     lres = IExplorerBrowser_Release(peb);
465     ok(lres == 0, "Got refcount %d\n", lres);
466
467     ebrowser_instantiate(&peb);
468     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
469     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
470     ok(hr == S_OK, "got (0x%08x)\n", hr);
471     IExplorerBrowser_Destroy(peb);
472     lres = IExplorerBrowser_Release(peb);
473     ok(lres == 0, "Got refcount %d\n", lres);
474
475     ebrowser_instantiate(&peb);
476     rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
477     hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
478     ok(hr == S_OK, "got (0x%08x)\n", hr);
479     IExplorerBrowser_Destroy(peb);
480     lres = IExplorerBrowser_Release(peb);
481     ok(lres == 0, "Got refcount %d\n", lres);
482 }
483
484 static void test_basics(void)
485 {
486     IExplorerBrowser *peb;
487     IShellBrowser *psb;
488     FOLDERSETTINGS fs;
489     ULONG lres;
490     DWORD flags;
491     HDWP hdwp;
492     RECT rc;
493     HRESULT hr;
494
495     ebrowser_instantiate(&peb);
496     ebrowser_initialize(peb);
497
498     /* SetRect */
499     rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
500     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
501     ok(hr == S_OK, "got (0x%08x)\n", hr);
502
503     rc.left = 100; rc.top = 100; rc.right = 10; rc.bottom = 10;
504     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
505     ok(hr == S_OK, "got (0x%08x)\n", hr);
506
507     /* SetRect with DeferWindowPos */
508     rc.left = rc.top = 0; rc.right = rc.bottom = 10;
509     hdwp = BeginDeferWindowPos(1);
510     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
511     ok(hr == S_OK, "got (0x%08x)\n", hr);
512     lres = EndDeferWindowPos(hdwp);
513     ok(lres, "EndDeferWindowPos failed.\n");
514
515     hdwp = NULL;
516     hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
517     ok(hr == S_OK, "got (0x%08x)\n", hr);
518     ok(hdwp == NULL, "got %p\n", hdwp);
519     lres = EndDeferWindowPos(hdwp);
520     ok(!lres, "EndDeferWindowPos succeeded unexpectedly.\n");
521
522     /* Test positioning */
523     rc.left = 10; rc.top = 20; rc.right = 50; rc.bottom = 50;
524     hr = IExplorerBrowser_SetRect(peb, NULL, rc);
525     ok(hr == S_OK, "got (0x%08x)\n", hr);
526     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
527     ok(hr == S_OK, "Got 0x%08x\n", hr);
528     if(SUCCEEDED(hr))
529     {
530         HWND eb_hwnd;
531         RECT eb_rc;
532         static const RECT exp_rc = {11, 21, 49, 49};
533
534         hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
535         ok(hr == S_OK, "Got 0x%08x\n", hr);
536
537         GetClientRect(eb_hwnd, &eb_rc);
538         MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
539         ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
540            eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
541
542         IShellBrowser_Release(psb);
543     }
544
545     IExplorerBrowser_Destroy(peb);
546     IExplorerBrowser_Release(peb);
547
548     /* GetOptions/SetOptions*/
549     ebrowser_instantiate(&peb);
550
551     if(0) {
552         /* Crashes on Windows 7 */
553         IExplorerBrowser_GetOptions(peb, NULL);
554     }
555
556     hr = IExplorerBrowser_GetOptions(peb, &flags);
557     ok(hr == S_OK, "got (0x%08x)\n", hr);
558     ok(flags == 0, "got (0x%08x)\n", flags);
559
560     /* Settings preserved through Initialize. */
561     hr = IExplorerBrowser_SetOptions(peb, 0xDEADBEEF);
562     ok(hr == S_OK, "got (0x%08x)\n", hr);
563
564     ebrowser_initialize(peb);
565
566     hr = IExplorerBrowser_GetOptions(peb, &flags);
567     ok(flags == 0xDEADBEEF, "got (0x%08x)\n", flags);
568     ok(hr == S_OK, "got (0x%08x)\n", hr);
569
570     IExplorerBrowser_Destroy(peb);
571     IExplorerBrowser_Release(peb);
572
573     ebrowser_instantiate(&peb);
574     ebrowser_initialize(peb);
575
576     /* SetFolderSettings */
577     hr = IExplorerBrowser_SetFolderSettings(peb, NULL);
578     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
579     fs.ViewMode = 0; fs.fFlags = 0;
580     hr = IExplorerBrowser_SetFolderSettings(peb, &fs);
581     todo_wine ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
582
583     /* TODO: Test after browsing somewhere. */
584
585     IExplorerBrowser_Destroy(peb);
586     lres = IExplorerBrowser_Release(peb);
587     ok(lres == 0, "Got %d\n", lres);
588 }
589
590 static void test_Advise(void)
591 {
592     IExplorerBrowser *peb;
593     IExplorerBrowserEvents *pebe;
594     DWORD cookies[10];
595     HRESULT hr;
596     UINT i, ref;
597
598     /* Set up our IExplorerBrowserEvents implementation */
599     ebev.lpVtbl = &ebevents;
600     pebe = (IExplorerBrowserEvents*) &ebev;
601
602     ebrowser_instantiate(&peb);
603
604     if(0)
605     {
606         /* Crashes on Windows 7 */
607         IExplorerBrowser_Advise(peb, pebe, NULL);
608         IExplorerBrowser_Advise(peb, NULL, &cookies[0]);
609     }
610
611     /* Using Unadvise with a cookie that has yet to be given out
612      * results in E_INVALIDARG */
613     hr = IExplorerBrowser_Unadvise(peb, 11);
614     ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
615
616     /* Add some before initialization */
617     for(i = 0; i < 5; i++)
618     {
619         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
620         ok(hr == S_OK, "got (0x%08x)\n", hr);
621     }
622
623     ebrowser_initialize(peb);
624
625     /* Add some after initialization */
626     for(i = 5; i < 10; i++)
627     {
628         hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
629         ok(hr == S_OK, "got (0x%08x)\n", hr);
630     }
631
632     ok(ebev.ref == 10, "Got %d\n", ebev.ref);
633
634     ebev.completed = 0;
635     ebrowser_browse_to_desktop(peb);
636     process_msgs();
637     ok(ebev.completed == 10, "Got %d\n", ebev.completed);
638
639     /* Remove a bunch somewhere in the middle */
640     for(i = 4; i < 8; i++)
641     {
642         hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
643         ok(hr == S_OK, "got (0x%08x)\n", hr);
644     }
645
646     ebev.completed = 0;
647     ebrowser_browse_to_desktop(peb);
648     process_msgs();
649     ok(ebev.completed == 6, "Got %d\n", ebev.completed);
650
651     if(0)
652     {
653         /* Using unadvise with a previously unadvised cookie results
654          * in a crash. */
655         hr = IExplorerBrowser_Unadvise(peb, cookies[5]);
656     }
657
658     /* Remove the rest. */
659     for(i = 0; i < 10; i++)
660     {
661         if(i<4||i>7)
662         {
663             hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
664             ok(hr == S_OK, "%d: got (0x%08x)\n", i, hr);
665         }
666     }
667
668     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
669
670     ebev.completed = 0;
671     ebrowser_browse_to_desktop(peb);
672     process_msgs();
673     ok(ebev.completed == 0, "Got %d\n", ebev.completed);
674
675     /* ::Destroy implies ::Unadvise. */
676     hr = IExplorerBrowser_Advise(peb, pebe, &cookies[0]);
677     ok(hr == S_OK, "Got 0x%08x\n", hr);
678     ok(ebev.ref == 1, "Got %d\n", ebev.ref);
679
680     hr = IExplorerBrowser_Destroy(peb);
681     ok(hr == S_OK, "Got 0x%08x\n", hr);
682     ok(ebev.ref == 0, "Got %d\n", ebev.ref);
683
684     ref = IExplorerBrowser_Release(peb);
685     ok(!ref, "Got %d", ref);
686 }
687
688 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
689 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
690 {
691   size_t iLen;
692
693   if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
694     return NULL;
695
696   if (iLen)
697   {
698     lpszPath += iLen;
699     if (lpszPath[-1] != '\\')
700     {
701       *lpszPath++ = '\\';
702       *lpszPath = '\0';
703     }
704   }
705   return lpszPath;
706 }
707
708 static void test_browse_pidl_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
709                               LPITEMIDLIST pidl, UINT uFlags,
710                               HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
711                               const char *file, int line)
712 {
713     HRESULT hr;
714     ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
715
716     hr = IExplorerBrowser_BrowseToIDList(peb, pidl, uFlags);
717     ok_(file, line) (hr == hr_exp, "BrowseToIDList returned 0x%08x\n", hr);
718     process_msgs();
719
720     ok_(file, line)
721         (ebev->pending == pending && ebev->created == created &&
722          ebev->failed == failed && ebev->completed == completed,
723          "Events occurred: %d, %d, %d, %d\n",
724          ebev->pending, ebev->created, ebev->failed, ebev->completed);
725 }
726 #define test_browse_pidl(peb, ebev, pidl, uFlags, hr, p, cr, f, co)     \
727     test_browse_pidl_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
728
729 static void test_browse_pidl_sb_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
730                                  LPITEMIDLIST pidl, UINT uFlags,
731                                  HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
732                                  const char *file, int line)
733 {
734     IShellBrowser *psb;
735     HRESULT hr;
736
737     hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
738     ok_(file, line) (hr == S_OK, "QueryInterface returned 0x%08x\n", hr);
739     if(SUCCEEDED(hr))
740     {
741         ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
742
743         hr = IShellBrowser_BrowseObject(psb, pidl, uFlags);
744         ok_(file, line) (hr == hr_exp, "BrowseObject returned 0x%08x\n", hr);
745         process_msgs();
746
747         ok_(file, line)
748             (ebev->pending == pending && ebev->created == created &&
749              ebev->failed == failed && ebev->completed == completed,
750              "Events occurred: %d, %d, %d, %d\n",
751              ebev->pending, ebev->created, ebev->failed, ebev->completed);
752
753         IShellBrowser_Release(psb);
754     }
755 }
756 #define test_browse_pidl_sb(peb, ebev, pidl, uFlags, hr, p, cr, f, co)  \
757     test_browse_pidl_sb_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
758
759 static void test_navigation(void)
760 {
761     IExplorerBrowser *peb, *peb2;
762     IFolderView *pfv;
763     IShellFolder *psf;
764     LPITEMIDLIST pidl_current, pidl_child;
765     DWORD cookie, cookie2;
766     HRESULT hr;
767     LONG lres;
768     WCHAR current_path[MAX_PATH];
769     WCHAR child_path[MAX_PATH];
770     static const WCHAR testfolderW[] =
771         {'w','i','n','e','t','e','s','t','f','o','l','d','e','r','\0'};
772
773     ok(pSHParseDisplayName != NULL, "pSHParseDisplayName unexpectedly missing.\n");
774     ok(pSHCreateShellItem != NULL, "pSHCreateShellItem unexpectedly missing.\n");
775
776     GetCurrentDirectoryW(MAX_PATH, current_path);
777     if(!lstrlenW(current_path))
778     {
779         skip("Failed to create test-directory.\n");
780         return;
781     }
782
783     lstrcpyW(child_path, current_path);
784     myPathAddBackslashW(child_path);
785     lstrcatW(child_path, testfolderW);
786
787     CreateDirectoryW(child_path, NULL);
788
789     pSHParseDisplayName(current_path, NULL, &pidl_current, 0, NULL);
790     pSHParseDisplayName(child_path, NULL, &pidl_child, 0, NULL);
791
792     ebrowser_instantiate(&peb);
793     ebrowser_initialize(peb);
794
795     ebrowser_instantiate(&peb2);
796     ebrowser_initialize(peb2);
797
798     /* Set up our IExplorerBrowserEvents implementation */
799     ebev.lpVtbl = &ebevents;
800
801     IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
802     IExplorerBrowser_Advise(peb2, (IExplorerBrowserEvents*)&ebev, &cookie2);
803
804     /* These should all fail */
805     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
806     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
807     test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
808     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
809     test_browse_pidl(peb, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
810     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
811     test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
812     test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
813
814     /* "The first browse is synchronous" */
815     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
816     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
817
818     /* Relative navigation */
819     test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
820     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
821
822     hr = IExplorerBrowser_GetCurrentView(peb, &IID_IFolderView, (void**)&pfv);
823     ok(hr == S_OK, "Got 0x%08x\n", hr);
824     if(SUCCEEDED(hr))
825     {
826         LPITEMIDLIST pidl_relative;
827
828         hr = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
829         ok(hr == S_OK, "Got 0x%08x\n", hr);
830         hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, (LPWSTR)testfolderW,
831                                            NULL, &pidl_relative, NULL);
832         ok(hr == S_OK, "Got 0x%08x\n", hr);
833
834         /* Browsing to another location here before using the
835          * pidl_relative would make ExplorerBrowser in Windows 7 show a
836          * not-available dialog. Also, passing a relative pidl without
837          * specifying SBSP_RELATIVE makes it look for the pidl on the
838          * desktop
839          */
840
841         test_browse_pidl(peb, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
842         test_browse_pidl_sb(peb2, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
843
844         ILFree(pidl_relative);
845         /* IShellFolder_Release(psf); */
846         IFolderView_Release(pfv);
847     }
848
849     /* misc **/
850     test_browse_pidl(peb, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
851     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
852     test_browse_pidl(peb, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
853     test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
854     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
855     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
856     test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
857     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
858
859     test_browse_pidl(peb, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
860     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
861     test_browse_pidl(peb, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
862     test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
863
864     /* SBSP_NEWBROWSER will return E_INVALIDARG, claims MSDN, but in
865      * reality it works as one would expect (Windows 7 only?).
866      */
867     if(0)
868     {
869         IExplorerBrowser_BrowseToIDList(peb, NULL, SBSP_NEWBROWSER);
870     }
871
872     hr = IExplorerBrowser_Unadvise(peb, cookie);
873     ok(hr == S_OK, "Got 0x%08x\n", hr);
874     IExplorerBrowser_Destroy(peb);
875     process_msgs();
876     hr = IExplorerBrowser_Unadvise(peb2, cookie2);
877     ok(hr == S_OK, "Got 0x%08x\n", hr);
878     IExplorerBrowser_Destroy(peb2);
879     process_msgs();
880
881     /* Attempt browsing after destroyed */
882     test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
883     test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
884
885     lres = IExplorerBrowser_Release(peb);
886     ok(lres == 0, "Got lres %d\n", lres);
887     lres = IExplorerBrowser_Release(peb2);
888     ok(lres == 0, "Got lres %d\n", lres);
889
890     /******************************************/
891     /* Test some options that affect browsing */
892
893     ebrowser_instantiate(&peb);
894     hr = IExplorerBrowser_Advise(peb, (IExplorerBrowserEvents*)&ebev, &cookie);
895     ok(hr == S_OK, "Got 0x%08x\n", hr);
896     hr = IExplorerBrowser_SetOptions(peb, EBO_NAVIGATEONCE);
897     ok(hr == S_OK, "got (0x%08x)\n", hr);
898     ebrowser_initialize(peb);
899
900     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 1, 0, 1);
901     test_browse_pidl(peb, &ebev, pidl_current, 0, E_FAIL, 0, 0, 0, 0);
902
903     hr = IExplorerBrowser_SetOptions(peb, 0);
904     ok(hr == S_OK, "got (0x%08x)\n", hr);
905
906     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
907     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
908
909     /* Difference in behavior lies where? */
910     hr = IExplorerBrowser_SetOptions(peb, EBO_ALWAYSNAVIGATE);
911     ok(hr == S_OK, "got (0x%08x)\n", hr);
912
913     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
914     test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
915
916     hr = IExplorerBrowser_Unadvise(peb, cookie);
917     ok(hr == S_OK, "Got 0x%08x\n", hr);
918
919     IExplorerBrowser_Destroy(peb);
920     lres = IExplorerBrowser_Release(peb);
921     ok(lres == 0, "Got lres %d\n", lres);
922
923     /* Cleanup */
924     RemoveDirectoryW(child_path);
925     ILFree(pidl_current);
926     ILFree(pidl_child);
927 }
928
929 static void test_GetCurrentView(void)
930 {
931     IExplorerBrowser *peb;
932     IUnknown *punk;
933     HRESULT hr;
934
935     /* GetCurrentView */
936     ebrowser_instantiate(&peb);
937
938     if(0)
939     {
940         /* Crashes under Windows 7 */
941         hr = IExplorerBrowser_GetCurrentView(peb, NULL, NULL);
942     }
943     hr = IExplorerBrowser_GetCurrentView(peb, NULL, (void**)&punk);
944     ok(hr == E_FAIL, "Got 0x%08x\n", hr);
945
946 #define test_gcv(iid, exp)                                              \
947     do {                                                                \
948         hr = IExplorerBrowser_GetCurrentView(peb, &iid, (void**)&punk); \
949         ok(hr == exp, "(%s:)Expected (0x%08x), got: (0x%08x)\n",        \
950            #iid ,exp, hr);                                              \
951         if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
952     } while(0)
953
954     test_gcv(IID_IUnknown, E_FAIL);
955     test_gcv(IID_IUnknown, E_FAIL);
956     test_gcv(IID_IShellView, E_FAIL);
957     test_gcv(IID_IShellView2, E_FAIL);
958     test_gcv(IID_IFolderView, E_FAIL);
959     test_gcv(IID_IPersistFolder, E_FAIL);
960     test_gcv(IID_IPersistFolder2, E_FAIL);
961     test_gcv(IID_ICommDlgBrowser, E_FAIL);
962     test_gcv(IID_ICommDlgBrowser2, E_FAIL);
963     test_gcv(IID_ICommDlgBrowser3, E_FAIL);
964
965     ebrowser_initialize(peb);
966     ebrowser_browse_to_desktop(peb);
967
968     test_gcv(IID_IUnknown, S_OK);
969     test_gcv(IID_IUnknown, S_OK);
970     test_gcv(IID_IShellView, S_OK);
971     test_gcv(IID_IShellView2, S_OK);
972     test_gcv(IID_IFolderView, S_OK);
973     todo_wine test_gcv(IID_IPersistFolder, S_OK);
974     test_gcv(IID_IPersistFolder2, E_NOINTERFACE);
975     test_gcv(IID_ICommDlgBrowser, E_NOINTERFACE);
976     test_gcv(IID_ICommDlgBrowser2, E_NOINTERFACE);
977     test_gcv(IID_ICommDlgBrowser3, E_NOINTERFACE);
978
979 #undef test_gcv
980
981     IExplorerBrowser_Destroy(peb);
982     IExplorerBrowser_Release(peb);
983 }
984
985 static BOOL test_instantiate_control(void)
986 {
987     IExplorerBrowser *peb;
988     HRESULT hr;
989
990     hr = ebrowser_instantiate(&peb);
991     ok(hr == S_OK || hr == REGDB_E_CLASSNOTREG, "Got (0x%08x)\n", hr);
992     if(FAILED(hr))
993         return FALSE;
994
995     IExplorerBrowser_Release(peb);
996     return TRUE;
997 }
998
999 static void setup_window(void)
1000 {
1001     WNDCLASSW wc;
1002     static const WCHAR ebtestW[] = {'e','b','t','e','s','t',0};
1003
1004     ZeroMemory(&wc, sizeof(WNDCLASSW));
1005     wc.lpfnWndProc      = DefWindowProcW;
1006     wc.lpszClassName    = ebtestW;
1007     RegisterClassW(&wc);
1008     hwnd = CreateWindowExW(0, ebtestW, NULL, 0,
1009                            0, 0, 500, 500,
1010                            NULL, 0, 0, NULL);
1011     ok(hwnd != NULL, "Failed to create window for tests.\n");
1012 }
1013
1014 START_TEST(ebrowser)
1015 {
1016     OleInitialize(NULL);
1017
1018     if(!test_instantiate_control())
1019     {
1020         win_skip("No ExplorerBrowser control..\n");
1021         OleUninitialize();
1022         return;
1023     }
1024
1025     setup_window();
1026     init_function_pointers();
1027
1028     test_QueryInterface();
1029     test_SB_misc();
1030     test_initialization();
1031     test_basics();
1032     test_Advise();
1033     test_navigation();
1034     test_GetCurrentView();
1035
1036     DestroyWindow(hwnd);
1037     OleUninitialize();
1038 }