hlink/tests: Add a trailing '\n' to an ok() call.
[wine] / dlls / shell32 / tests / shlview.c
1 /*
2  * Unit test of the IShellView
3  *
4  * Copyright 2010 Nikolay Sivov for CodeWeavers
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 <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define CONST_VTABLE
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
31
32 #include "shlguid.h"
33 #include "shlobj.h"
34 #include "shobjidl.h"
35 #include "shlwapi.h"
36 #include "ocidl.h"
37 #include "oleauto.h"
38
39 #include "wine/test.h"
40
41 #include "msg.h"
42
43 #define LISTVIEW_SEQ_INDEX  0
44 #define NUM_MSG_SEQUENCES   1
45
46 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
47
48 static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
49 {
50     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
51     static LONG defwndproc_counter = 0;
52     LRESULT ret;
53     struct message msg;
54
55     trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
56
57     msg.message = message;
58     msg.flags = sent|wparam|lparam;
59     if (defwndproc_counter) msg.flags |= defwinproc;
60     msg.wParam = wParam;
61     msg.lParam = lParam;
62     add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
63
64     defwndproc_counter++;
65     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
66     defwndproc_counter--;
67     return ret;
68 }
69
70 static HWND subclass_listview(HWND hwnd)
71 {
72     WNDPROC oldproc;
73     HWND listview;
74
75     /* listview is a first child */
76     listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
77
78     oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
79                                         (LONG_PTR)listview_subclass_proc);
80     SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
81
82     return listview;
83 }
84
85 typedef struct {
86
87     const IShellBrowserVtbl *lpVtbl;
88     LONG ref;
89 } IShellBrowserImpl;
90
91 /* dummy IShellBrowser implementation */
92 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
93
94 IShellBrowser* IShellBrowserImpl_Construct(void)
95 {
96     IShellBrowserImpl *browser;
97
98     browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
99     browser->lpVtbl = &IShellBrowserImpl_Vtbl;
100     browser->ref = 1;
101
102     return (IShellBrowser*)browser;
103 }
104
105 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
106                                             REFIID riid,
107                                             LPVOID *ppvObj)
108 {
109     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
110
111     *ppvObj = NULL;
112
113     if(IsEqualIID(riid, &IID_IUnknown))
114     {
115         *ppvObj = This;
116     }
117     else if(IsEqualIID(riid, &IID_IOleWindow))
118     {
119         *ppvObj = This;
120     }
121     else if(IsEqualIID(riid, &IID_IShellBrowser))
122     {
123         *ppvObj = This;
124     }
125
126     if(*ppvObj)
127     {
128         IUnknown_AddRef( (IShellBrowser*) *ppvObj);
129         return S_OK;
130     }
131
132     return E_NOINTERFACE;
133 }
134
135 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
136 {
137     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
138     return InterlockedIncrement(&This->ref);
139 }
140
141 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
142 {
143     IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
144     ULONG ref = InterlockedDecrement(&This->ref);
145
146     if (!ref)
147     {
148         HeapFree(GetProcessHeap(), 0, This);
149         return 0;
150     }
151     return ref;
152 }
153
154 static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
155                                            HWND *phwnd)
156 {
157     if (phwnd) *phwnd = GetDesktopWindow();
158     return S_OK;
159 }
160
161 static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
162                                                       BOOL fEnterMode)
163 {
164     return E_NOTIMPL;
165 }
166
167 static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
168                                               LPCITEMIDLIST pidl,
169                                               UINT wFlags)
170 {
171     return E_NOTIMPL;
172 }
173
174 static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
175                                               BOOL fEnable)
176
177 {
178     return E_NOTIMPL;
179 }
180
181 static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
182                                               UINT id,
183                                               HWND *lphwnd)
184
185 {
186     return E_NOTIMPL;
187 }
188
189 static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
190                                                 DWORD mode,
191                                                 LPSTREAM *pStrm)
192
193 {
194     return E_NOTIMPL;
195 }
196
197 static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
198                                            HMENU hmenuShared,
199                                            LPOLEMENUGROUPWIDTHS lpMenuWidths)
200
201 {
202     return E_NOTIMPL;
203 }
204
205 static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
206                                                 IShellView *ppshv)
207
208 {
209     return E_NOTIMPL;
210 }
211
212 static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
213                                                   IShellView **ppshv)
214
215 {
216     return E_NOTIMPL;
217 }
218
219 static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
220                                            HMENU hmenuShared)
221
222 {
223     return E_NOTIMPL;
224 }
225
226 static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
227                                             UINT id,
228                                             UINT uMsg,
229                                             WPARAM wParam,
230                                             LPARAM lParam,
231                                             LRESULT *pret)
232
233 {
234     return E_NOTIMPL;
235 }
236
237 static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
238                                        HMENU hmenuShared,
239                                        HOLEMENU holemenuReserved,
240                                        HWND hwndActiveObject)
241
242 {
243     return E_NOTIMPL;
244 }
245
246 static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
247                                              LPCOLESTR lpszStatusText)
248
249 {
250     return E_NOTIMPL;
251 }
252
253 static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
254                                              LPTBBUTTON lpButtons,
255                                              UINT nButtons,
256                                              UINT uFlags)
257
258 {
259     return E_NOTIMPL;
260 }
261
262 static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
263                                                     LPMSG lpmsg,
264                                                     WORD wID)
265
266 {
267     return E_NOTIMPL;
268 }
269
270 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
271 {
272     IShellBrowserImpl_QueryInterface,
273     IShellBrowserImpl_AddRef,
274     IShellBrowserImpl_Release,
275     IShellBrowserImpl_GetWindow,
276     IShellBrowserImpl_ContextSensitiveHelp,
277     IShellBrowserImpl_InsertMenusSB,
278     IShellBrowserImpl_SetMenuSB,
279     IShellBrowserImpl_RemoveMenusSB,
280     IShellBrowserImpl_SetStatusTextSB,
281     IShellBrowserImpl_EnableModelessSB,
282     IShellBrowserImpl_TranslateAcceleratorSB,
283     IShellBrowserImpl_BrowseObject,
284     IShellBrowserImpl_GetViewStateStream,
285     IShellBrowserImpl_GetControlWindow,
286     IShellBrowserImpl_SendControlMsg,
287     IShellBrowserImpl_QueryActiveShellView,
288     IShellBrowserImpl_OnViewWindowActive,
289     IShellBrowserImpl_SetToolbarItems
290 };
291
292 static const struct message empty_seq[] = {
293     { 0 }
294 };
295
296 static const struct message folderview_getspacing_seq[] = {
297     { LVM_GETITEMSPACING, wparam|sent, FALSE },
298     { 0 }
299 };
300
301 static const struct message folderview_getselectionmarked_seq[] = {
302     { LVM_GETSELECTIONMARK, sent },
303     { 0 }
304 };
305
306 static const struct message folderview_getfocused_seq[] = {
307     { LVM_GETNEXTITEM, sent|wparam|lparam, -1, LVNI_FOCUSED },
308     { 0 }
309 };
310
311 static const struct message folderview_itemcount_seq[] = {
312     { LVM_GETITEMCOUNT, sent },
313     { 0 }
314 };
315
316 static void test_IShellView_CreateViewWindow(void)
317 {
318     IShellFolder *desktop;
319     FOLDERSETTINGS settings;
320     IShellView *view;
321     IDropTarget *dt;
322     HWND hwnd_view;
323     HRESULT hr;
324     RECT r = {0};
325
326     hr = SHGetDesktopFolder(&desktop);
327     ok(hr == S_OK, "got (0x%08x)\n", hr);
328
329     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
330     ok(hr == S_OK, "got (0x%08x)\n", hr);
331
332 if (0)
333 {
334     /* crashes on native */
335     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
336 }
337
338     settings.ViewMode = FVM_ICON;
339     settings.fFlags = 0;
340     hwnd_view = (HWND)0xdeadbeef;
341     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
342     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
343     ok(hwnd_view == 0, "got %p\n", hwnd_view);
344
345     hwnd_view = (HWND)0xdeadbeef;
346     hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
347     ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
348     ok(hwnd_view == 0, "got %p\n", hwnd_view);
349
350     /* ::DragLeave without drag operation */
351     hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
352     ok(hr == S_OK, "got (0x%08x)\n", hr);
353     hr = IDropTarget_DragLeave(dt);
354     ok(hr == S_OK, "got (0x%08x)\n", hr);
355     IDropTarget_Release(dt);
356
357     IShellView_Release(view);
358     IShellFolder_Release(desktop);
359 }
360
361 static void test_IFolderView(void)
362 {
363     IShellFolder *desktop, *folder;
364     FOLDERSETTINGS settings;
365     IShellView *view;
366     IShellBrowser *browser;
367     IFolderView *fv;
368     HWND hwnd_view, hwnd_list;
369     HRESULT hr;
370     INT ret;
371     POINT pt;
372     LONG ref1, ref2;
373     RECT r;
374
375     hr = SHGetDesktopFolder(&desktop);
376     ok(hr == S_OK, "got (0x%08x)\n", hr);
377
378     hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
379     ok(hr == S_OK, "got (0x%08x)\n", hr);
380
381     hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
382     if (hr != S_OK)
383     {
384         win_skip("IFolderView not supported by desktop folder\n");
385         IShellView_Release(view);
386         IShellFolder_Release(desktop);
387         return;
388     }
389
390     /* call methods before window creation */
391     hr = IFolderView_GetSpacing(fv, NULL);
392     ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
393
394 if (0)
395 {
396     /* crashes on Vista and Win2k8 - List not created yet case */
397     hr = IFolderView_GetSpacing(fv, &pt);
398
399     /* crashes on XP */
400     hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
401     hr = IFolderView_GetFocusedItem(fv, NULL);
402 }
403
404     browser = IShellBrowserImpl_Construct();
405
406     settings.ViewMode = FVM_ICON;
407     settings.fFlags = 0;
408     hwnd_view = (HWND)0xdeadbeef;
409     r.left = r.top = 0;
410     r.right = r.bottom = 100;
411     hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
412     ok(hr == S_OK, "got (0x%08x)\n", hr);
413     ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
414
415     hwnd_list = subclass_listview(hwnd_view);
416     if (!hwnd_list)
417     {
418         win_skip("Failed to subclass ListView control\n");
419         IShellBrowser_Release(browser);
420         IFolderView_Release(fv);
421         IShellView_Release(view);
422         IShellFolder_Release(desktop);
423         return;
424     }
425
426     /* IFolderView::GetSpacing */
427     flush_sequences(sequences, NUM_MSG_SEQUENCES);
428     hr = IFolderView_GetSpacing(fv, NULL);
429     ok(hr == S_OK, "got (0x%08x)\n", hr);
430     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
431
432     flush_sequences(sequences, NUM_MSG_SEQUENCES);
433     hr = IFolderView_GetSpacing(fv, &pt);
434     ok(hr == S_OK, "got (0x%08x)\n", hr);
435     /* fails with empty sequence on win7 for unknown reason */
436     if (sequences[LISTVIEW_SEQ_INDEX]->count)
437     {
438         ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
439         ok(pt.x > 0, "got %d\n", pt.x);
440         ok(pt.y > 0, "got %d\n", pt.y);
441         ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
442         ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
443     }
444
445     /* IFolderView::GetSelectionMarkedItem */
446 if (0)
447 {
448     /* crashes on XP */
449     hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
450 }
451
452     flush_sequences(sequences, NUM_MSG_SEQUENCES);
453     hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
454     ok(hr == S_OK, "got (0x%08x)\n", hr);
455     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
456                                   "IFolderView::GetSelectionMarkedItem", FALSE);
457
458     /* IFolderView::GetFocusedItem */
459     flush_sequences(sequences, NUM_MSG_SEQUENCES);
460     hr = IFolderView_GetFocusedItem(fv, &ret);
461     ok(hr == S_OK, "got (0x%08x)\n", hr);
462     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
463                                   "IFolderView::GetFocusedItem", FALSE);
464
465     /* IFolderView::GetFolder, just return pointer */
466 if (0)
467 {
468     /* crashes on XP */
469     hr = IFolderView_GetFolder(fv, NULL, (void**)&folder);
470     hr = IFolderView_GetFolder(fv, NULL, NULL);
471 }
472
473     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
474     ok(hr == E_POINTER, "got (0x%08x)\n", hr);
475
476     ref1 = IShellFolder_AddRef(desktop);
477     IShellFolder_Release(desktop);
478     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
479     ok(hr == S_OK, "got (0x%08x)\n", hr);
480     ref2 = IShellFolder_AddRef(desktop);
481     IShellFolder_Release(desktop);
482     ok(ref1 == ref2, "expected same refcount, got %d\n", ref2);
483     ok(desktop == folder, "\n");
484
485     /* IFolderView::ItemCount */
486 if (0)
487 {
488     /* crashes on XP */
489     hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
490 }
491
492     flush_sequences(sequences, NUM_MSG_SEQUENCES);
493     hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &ret);
494     ok(hr == S_OK, "got (0x%08x)\n", hr);
495     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_itemcount_seq,
496                                   "IFolderView::ItemCount", FALSE);
497
498     IShellBrowser_Release(browser);
499     IFolderView_Release(fv);
500     IShellView_Release(view);
501     IShellFolder_Release(desktop);
502 }
503
504 START_TEST(shlview)
505 {
506     OleInitialize(NULL);
507
508     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
509
510     test_IShellView_CreateViewWindow();
511     test_IFolderView();
512
513     OleUninitialize();
514 }