wine/dlls/shell32/tests/shlview.c

1170 lines
36 KiB
C

/*
* Unit test of the IShellView
*
* Copyright 2010 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#define COBJMACROS
#define CONST_VTABLE
#include "windef.h"
#include "winbase.h"
#include "wtypes.h"
#include "shellapi.h"
#include "shlguid.h"
#include "shlobj.h"
#include "shobjidl.h"
#include "shlwapi.h"
#include "ocidl.h"
#include "oleauto.h"
#include "initguid.h"
#include "wine/test.h"
#include "msg.h"
#define LISTVIEW_SEQ_INDEX 0
#define NUM_MSG_SEQUENCES 1
DEFINE_GUID(IID_IPersistHistory, 0x91a565c1, 0xe38f, 0x11d0, 0x94, 0xbf, 0x00, 0xa0, 0xc9, 0x05, 0x5c, 0xbf);
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
defwndproc_counter++;
ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static HWND subclass_listview(HWND hwnd)
{
WNDPROC oldproc;
HWND listview;
/* listview is a first child */
listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
if(!listview)
{
/* .. except for some versions of Windows XP, where things
are slightly more complicated. */
HWND hwnd_tmp;
hwnd_tmp = FindWindowExA(hwnd, NULL, "DUIViewWndClassName", NULL);
hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "DirectUIHWND", NULL);
hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "CtrlNotifySink", NULL);
listview = FindWindowExA(hwnd_tmp, NULL, WC_LISTVIEWA, NULL);
}
oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
(LONG_PTR)listview_subclass_proc);
SetWindowLongPtrA(listview, GWLP_USERDATA, (LONG_PTR)oldproc);
return listview;
}
static UINT get_msg_count(struct msg_sequence **seq, int sequence_index, UINT message)
{
struct msg_sequence *msg_seq = seq[sequence_index];
UINT i, count = 0;
for(i = 0; i < msg_seq->count ; i++)
if(msg_seq->sequence[i].message == message)
count++;
return count;
}
/* Checks that every message in the sequence seq is also present in
* the UINT array msgs */
static void verify_msgs_in_(struct msg_sequence *seq, const UINT *msgs,
const char *file, int line)
{
UINT i, j, msg, failcount = 0;
for(i = 0; i < seq->count; i++)
{
BOOL found = FALSE;
msg = seq->sequence[i].message;
for(j = 0; msgs[j] != 0; j++)
if(msgs[j] == msg) found = TRUE;
if(!found)
{
failcount++;
trace("Unexpected message %d\n", msg);
}
}
ok_(file, line) (!failcount, "%d failures.\n", failcount);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
}
#define verify_msgs_in(seq, msgs) \
verify_msgs_in_(seq, msgs, __FILE__, __LINE__)
/* dummy IDataObject implementation */
typedef struct {
IDataObject IDataObject_iface;
LONG ref;
} IDataObjectImpl;
static const IDataObjectVtbl IDataObjectImpl_Vtbl;
static inline IDataObjectImpl *impl_from_IDataObject(IDataObject *iface)
{
return CONTAINING_RECORD(iface, IDataObjectImpl, IDataObject_iface);
}
static IDataObject* IDataObjectImpl_Construct(void)
{
IDataObjectImpl *obj;
obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
obj->IDataObject_iface.lpVtbl = &IDataObjectImpl_Vtbl;
obj->ref = 1;
return &obj->IDataObject_iface;
}
static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
{
IDataObjectImpl *This = impl_from_IDataObject(iface);
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IDataObject))
{
*ppvObj = This;
}
if(*ppvObj)
{
IUnknown_AddRef(iface);
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
{
IDataObjectImpl *This = impl_from_IDataObject(iface);
return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
{
IDataObjectImpl *This = impl_from_IDataObject(iface);
ULONG ref = InterlockedDecrement(&This->ref);
if (!ref)
{
HeapFree(GetProcessHeap(), 0, This);
return 0;
}
return ref;
}
static HRESULT WINAPI IDataObjectImpl_GetData(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_GetDataHere(IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_QueryGetData(IDataObject *iface, FORMATETC *pformat)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_GetCanonicalFormatEtc(
IDataObject *iface, FORMATETC *pformatIn, FORMATETC *pformatOut)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_SetData(
IDataObject *iface, FORMATETC *pformat, STGMEDIUM *pmedium, BOOL release)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_EnumFormatEtc(
IDataObject *iface, DWORD direction, IEnumFORMATETC **ppenumFormatEtc)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_DAdvise(
IDataObject *iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pSink, DWORD *pConnection)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_DUnadvise(IDataObject *iface, DWORD connection)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IDataObjectImpl_EnumDAdvise(IDataObject *iface, IEnumSTATDATA **ppenumAdvise)
{
return E_NOTIMPL;
}
static const IDataObjectVtbl IDataObjectImpl_Vtbl =
{
IDataObjectImpl_QueryInterface,
IDataObjectImpl_AddRef,
IDataObjectImpl_Release,
IDataObjectImpl_GetData,
IDataObjectImpl_GetDataHere,
IDataObjectImpl_QueryGetData,
IDataObjectImpl_GetCanonicalFormatEtc,
IDataObjectImpl_SetData,
IDataObjectImpl_EnumFormatEtc,
IDataObjectImpl_DAdvise,
IDataObjectImpl_DUnadvise,
IDataObjectImpl_EnumDAdvise
};
/* dummy IShellBrowser implementation */
typedef struct {
IShellBrowser IShellBrowser_iface;
LONG ref;
} IShellBrowserImpl;
static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
static inline IShellBrowserImpl *impl_from_IShellBrowser(IShellBrowser *iface)
{
return CONTAINING_RECORD(iface, IShellBrowserImpl, IShellBrowser_iface);
}
static IShellBrowser* IShellBrowserImpl_Construct(void)
{
IShellBrowserImpl *browser;
browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
browser->IShellBrowser_iface.lpVtbl = &IShellBrowserImpl_Vtbl;
browser->ref = 1;
return &browser->IShellBrowser_iface;
}
static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
REFIID riid,
LPVOID *ppvObj)
{
IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
*ppvObj = NULL;
if(IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IOleWindow) ||
IsEqualIID(riid, &IID_IShellBrowser))
{
*ppvObj = This;
}
if(*ppvObj)
{
IUnknown_AddRef(iface);
return S_OK;
}
return E_NOINTERFACE;
}
static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
{
IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
{
IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
ULONG ref = InterlockedDecrement(&This->ref);
if (!ref)
{
HeapFree(GetProcessHeap(), 0, This);
return 0;
}
return ref;
}
static HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser *iface,
HWND *phwnd)
{
if (phwnd) *phwnd = GetDesktopWindow();
return S_OK;
}
static HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser *iface,
BOOL fEnterMode)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface,
LPCITEMIDLIST pidl,
UINT wFlags)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface,
BOOL fEnable)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface,
UINT id,
HWND *lphwnd)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface,
DWORD mode,
LPSTREAM *pStrm)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface,
HMENU hmenuShared,
LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface,
IShellView *ppshv)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface,
IShellView **ppshv)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface,
HMENU hmenuShared)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface,
UINT id,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
LRESULT *pret)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface,
HMENU hmenuShared,
HOLEMENU holemenuReserved,
HWND hwndActiveObject)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface,
LPCOLESTR lpszStatusText)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface,
LPTBBUTTON lpButtons,
UINT nButtons,
UINT uFlags)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface,
LPMSG lpmsg,
WORD wID)
{
return E_NOTIMPL;
}
static const IShellBrowserVtbl IShellBrowserImpl_Vtbl =
{
IShellBrowserImpl_QueryInterface,
IShellBrowserImpl_AddRef,
IShellBrowserImpl_Release,
IShellBrowserImpl_GetWindow,
IShellBrowserImpl_ContextSensitiveHelp,
IShellBrowserImpl_InsertMenusSB,
IShellBrowserImpl_SetMenuSB,
IShellBrowserImpl_RemoveMenusSB,
IShellBrowserImpl_SetStatusTextSB,
IShellBrowserImpl_EnableModelessSB,
IShellBrowserImpl_TranslateAcceleratorSB,
IShellBrowserImpl_BrowseObject,
IShellBrowserImpl_GetViewStateStream,
IShellBrowserImpl_GetControlWindow,
IShellBrowserImpl_SendControlMsg,
IShellBrowserImpl_QueryActiveShellView,
IShellBrowserImpl_OnViewWindowActive,
IShellBrowserImpl_SetToolbarItems
};
static const struct message empty_seq[] = {
{ 0 }
};
static const struct message folderview_getspacing_seq[] = {
{ LVM_GETITEMSPACING, wparam|sent, FALSE },
{ 0 }
};
static const struct message folderview_getselectionmarked_seq[] = {
{ LVM_GETSELECTIONMARK, sent },
{ 0 }
};
static const struct message folderview_getfocused_seq[] = {
{ LVM_GETNEXTITEM, sent|wparam|lparam|optional, -1, LVNI_FOCUSED },
{ 0 }
};
static const struct message folderview_itemcount_seq[] = {
{ LVM_GETITEMCOUNT, sent },
{ 0 }
};
static void test_IShellView_CreateViewWindow(void)
{
IShellFolder *desktop;
FOLDERSETTINGS settings;
IShellView *view;
IDropTarget *dt;
HWND hwnd_view;
HRESULT hr;
RECT r = {0};
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
if (0)
{
/* crashes on native */
IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
}
settings.ViewMode = FVM_ICON;
settings.fFlags = 0;
hwnd_view = (HWND)0xdeadbeef;
hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, &hwnd_view);
ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
ok(hwnd_view == 0, "got %p\n", hwnd_view);
hwnd_view = (HWND)0xdeadbeef;
hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, &r, &hwnd_view);
ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
ok(hwnd_view == 0, "got %p\n", hwnd_view);
/* ::DragLeave without drag operation */
hr = IShellView_QueryInterface(view, &IID_IDropTarget, (void**)&dt);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IDropTarget_DragLeave(dt);
ok(hr == S_OK, "got (0x%08x)\n", hr);
IDropTarget_Release(dt);
IShellView_Release(view);
IShellFolder_Release(desktop);
}
static void test_IFolderView(void)
{
IShellFolder *desktop, *folder;
FOLDERSETTINGS settings;
IShellView *view;
IShellBrowser *browser;
IFolderView *fv;
HWND hwnd_view, hwnd_list;
PITEMID_CHILD pidl;
HRESULT hr;
INT ret, count;
POINT pt;
LONG ref1, ref2;
RECT r;
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellView_QueryInterface(view, &IID_IFolderView, (void**)&fv);
if (hr != S_OK)
{
win_skip("IFolderView not supported by desktop folder\n");
IShellView_Release(view);
IShellFolder_Release(desktop);
return;
}
/* call methods before window creation */
hr = IFolderView_GetSpacing(fv, NULL);
ok(hr == S_FALSE || broken(hr == S_OK) /* win7 */, "got (0x%08x)\n", hr);
pidl = (void*)0xdeadbeef;
hr = IFolderView_Item(fv, 0, &pidl);
ok(hr == E_INVALIDARG || broken(hr == E_FAIL) /* < Vista */, "got (0x%08x)\n", hr);
ok(pidl == 0 || broken(pidl == (void*)0xdeadbeef) /* < Vista */, "got %p\n", pidl);
if (0)
{
/* crashes on Vista and Win2k8 - List not created yet case */
IFolderView_GetSpacing(fv, &pt);
/* crashes on XP */
IFolderView_GetSelectionMarkedItem(fv, NULL);
IFolderView_GetFocusedItem(fv, NULL);
/* crashes on Vista+ */
IFolderView_Item(fv, 0, NULL);
}
browser = IShellBrowserImpl_Construct();
settings.ViewMode = FVM_ICON;
settings.fFlags = 0;
hwnd_view = (HWND)0xdeadbeef;
r.left = r.top = 0;
r.right = r.bottom = 100;
hr = IShellView_CreateViewWindow(view, NULL, &settings, browser, &r, &hwnd_view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
ok(IsWindow(hwnd_view), "got %p\n", hwnd_view);
hwnd_list = subclass_listview(hwnd_view);
if (!hwnd_list)
{
win_skip("Failed to subclass ListView control\n");
IShellBrowser_Release(browser);
IFolderView_Release(fv);
IShellView_Release(view);
IShellFolder_Release(desktop);
return;
}
/* IFolderView::GetSpacing */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = IFolderView_GetSpacing(fv, NULL);
ok(hr == S_OK, "got (0x%08x)\n", hr);
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq, "IFolderView::GetSpacing, empty", FALSE);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = IFolderView_GetSpacing(fv, &pt);
ok(hr == S_OK, "got (0x%08x)\n", hr);
/* fails with empty sequence on win7 for unknown reason */
if (sequences[LISTVIEW_SEQ_INDEX]->count)
{
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getspacing_seq, "IFolderView::GetSpacing", FALSE);
ok(pt.x > 0, "got %d\n", pt.x);
ok(pt.y > 0, "got %d\n", pt.y);
ret = SendMessageA(hwnd_list, LVM_GETITEMSPACING, 0, 0);
ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
}
/* IFolderView::ItemCount */
if (0)
{
/* crashes on XP */
IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
}
flush_sequences(sequences, NUM_MSG_SEQUENCES);
IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &count);
/* IFolderView::GetSelectionMarkedItem */
if (0)
{
/* crashes on XP */
IFolderView_GetSelectionMarkedItem(fv, NULL);
}
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
if (count)
ok(hr == S_OK, "got (0x%08x)\n", hr);
else
ok(hr == S_FALSE, "got (0x%08x)\n", hr);
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
"IFolderView::GetSelectionMarkedItem", FALSE);
/* IFolderView::GetFocusedItem */
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = IFolderView_GetFocusedItem(fv, &ret);
if (count)
ok(hr == S_OK, "got (0x%08x)\n", hr);
else
ok(hr == S_FALSE, "got (0x%08x)\n", hr);
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
"IFolderView::GetFocusedItem", FALSE);
/* IFolderView::GetFolder, just return pointer */
if (0)
{
/* crashes on XP */
IFolderView_GetFolder(fv, NULL, (void**)&folder);
IFolderView_GetFolder(fv, NULL, NULL);
}
hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
ok(hr == E_POINTER, "got (0x%08x)\n", hr);
ref1 = IShellFolder_AddRef(desktop);
IShellFolder_Release(desktop);
hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder);
ok(hr == S_OK, "got (0x%08x)\n", hr);
ref2 = IShellFolder_AddRef(desktop);
IShellFolder_Release(desktop);
ok(ref1 == ref2 || ref1 + 1 == ref2, /* >= vista */
"expected same refcount, got %d\n", ref2);
ok(desktop == folder, "\n");
IShellBrowser_Release(browser);
IFolderView_Release(fv);
IShellView_Release(view);
IShellFolder_Release(desktop);
}
static void test_GetItemObject(void)
{
IShellFolder *desktop;
IShellView *view;
IUnknown *unk;
HRESULT hr;
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
/* from documentation three interfaces are supported for SVGIO_BACKGROUND:
IContextMenu, IDispatch, IPersistHistory */
hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IContextMenu, (void**)&unk);
ok(hr == S_OK, "got (0x%08x)\n", hr);
IUnknown_Release(unk);
unk = NULL;
hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IDispatch, (void**)&unk);
todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* NT4 */, "got (0x%08x)\n", hr);
if (unk) IUnknown_Release(unk);
unk = NULL;
hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersistHistory, (void**)&unk);
todo_wine ok(hr == S_OK || broken(hr == E_NOTIMPL) /* W9x, NT4 */, "got (0x%08x)\n", hr);
if (unk) IUnknown_Release(unk);
/* example of unsupported interface, base for IPersistHistory */
hr = IShellView_GetItemObject(view, SVGIO_BACKGROUND, &IID_IPersist, (void**)&unk);
ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL) /* W2K */, "got (0x%08x)\n", hr);
IShellView_Release(view);
IShellFolder_Release(desktop);
}
static void test_IShellFolderView(void)
{
IShellFolderView *folderview;
IShellFolder *desktop;
IShellView *view;
IDataObject *obj;
UINT i;
HRESULT hr;
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellView_QueryInterface(view, &IID_IShellFolderView, (void**)&folderview);
if (hr != S_OK)
{
win_skip("IShellView doesn't provide IShellFolderView on this platform\n");
IShellView_Release(view);
IShellFolder_Release(desktop);
return;
}
/* ::MoveIcons */
obj = IDataObjectImpl_Construct();
hr = IShellFolderView_MoveIcons(folderview, obj);
ok(hr == E_NOTIMPL || broken(hr == S_OK) /* W98 */, "got (0x%08x)\n", hr);
IDataObject_Release(obj);
/* ::SetRedraw without list created */
hr = IShellFolderView_SetRedraw(folderview, TRUE);
ok(hr == S_OK, "got (0x%08x)\n", hr);
/* ::QuerySupport */
hr = IShellFolderView_QuerySupport(folderview, NULL);
ok(hr == S_OK, "got (0x%08x)\n", hr);
i = 0xdeadbeef;
hr = IShellFolderView_QuerySupport(folderview, &i);
ok(hr == S_OK, "got (0x%08x)\n", hr);
ok(i == 0xdeadbeef, "got %d\n", i);
/* ::RemoveObject */
i = 0xdeadbeef;
hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
ok(hr == S_OK || hr == E_FAIL, "got (0x%08x)\n", hr);
if (hr == S_OK) ok(i == 0 || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
"got %d\n", i);
IShellFolderView_Release(folderview);
IShellView_Release(view);
IShellFolder_Release(desktop);
}
static void test_IOleWindow(void)
{
IShellFolder *desktop;
IShellView *view;
HRESULT hr;
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view);
ok(hr == S_OK, "got (0x%08x)\n", hr);
/* IShellView::ContextSensitiveHelp */
hr = IShellView_ContextSensitiveHelp(view, TRUE);
ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
hr = IShellView_ContextSensitiveHelp(view, FALSE);
ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
IShellView_Release(view);
IShellFolder_Release(desktop);
}
static const struct message folderview_setcurrentviewmode1_2_prevista[] = {
{ LVM_SETVIEW, sent|wparam, LV_VIEW_ICON},
{ LVM_SETIMAGELIST, sent|wparam, 0},
{ LVM_SETIMAGELIST, sent|wparam, 1},
{ 0x105a, sent},
{ LVM_SETBKIMAGEW, sent|optional}, /* w2k3 */
{ LVM_GETBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTCOLOR, sent|optional}, /* w2k3 */
{ LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
{ LVM_ARRANGE, sent },
{ LVM_ARRANGE, sent|optional }, /* WinXP */
{ 0 }
};
static const struct message folderview_setcurrentviewmode3_prevista[] = {
{ LVM_SETVIEW, sent|wparam, LV_VIEW_LIST},
{ LVM_SETIMAGELIST, sent|wparam, 0},
{ LVM_SETIMAGELIST, sent|wparam, 1},
{ 0x105a, sent},
{ LVM_SETBKIMAGEW, sent|optional}, /* w2k3 */
{ LVM_GETBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTCOLOR, sent|optional}, /* w2k3 */
{ LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
{ 0 }
};
static const struct message folderview_setcurrentviewmode4_prevista[] = {
{ LVM_GETHEADER, sent},
{ LVM_GETITEMCOUNT, sent|optional },
{ LVM_SETSELECTEDCOLUMN, sent},
{ WM_NOTIFY, sent },
{ WM_NOTIFY, sent },
{ WM_NOTIFY, sent },
{ WM_NOTIFY, sent },
{ LVM_SETVIEW, sent|wparam, LV_VIEW_DETAILS},
{ LVM_SETIMAGELIST, sent|wparam, 0},
{ LVM_SETIMAGELIST, sent|wparam, 1},
{ 0x105a, sent},
{ LVM_SETBKIMAGEW, sent|optional}, /* w2k3 */
{ LVM_GETBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
{ LVM_GETTEXTCOLOR, sent|optional}, /* w2k3 */
{ LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
{ 0 }
};
/* XP, SetCurrentViewMode(5)
108e - LVM_SETVIEW (LV_VIEW_ICON);
1036 - LVM_SETEXTEDEDLISTVIEWSTYLE (0x8000, 0)
100c/104c repeated X times
1003 - LVM_SETIMAGELIST
1035 - LVM_SETICONSPACING
1004 - LVM_GETITEMCOUNT
105a - ?
1016 - LVM_ARRANGE
1016 - LVM_ARRANGE
*/
/* XP, SetCurrentViewMode(6)
1036 - LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0)
1035 - LVM_SETICONSPACING
1003 - LVM_SETIMAGELIST
1003 - LVM_SETIMAGELIST
100c/104c repeated X times
10a2 - LVM_SETTILEVIEWINFO
108e - LVM_SETVIEW (LV_VIEW_TILE)
1003 - LVM_SETIMAGELIST
105a - ?
1016 - LVM_ARRANGE
1016 - LVM_ARRANGE
*/
/* XP, SetCurrentViewMode (7)
10a2 - LVM_SETTILEVIEWINFO
108e - LVM_SETVIEW (LV_VIEW_ICON)
1004/10a4 (LVM_GETITEMCOUNT/LVM_SETTILEINFO) X times
1016 - LVM_ARRANGE
1016 - LVM_ARRANGE
...
LVM_SETEXTENDEDLISTVIEWSTYLE (0x40000, 0x40000)
...
LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0x8000)
*/
static void test_GetSetCurrentViewMode(void)
{
IShellFolder *desktop;
IShellView *sview;
IFolderView *fview;
IShellBrowser *browser;
FOLDERSETTINGS fs;
UINT viewmode;
HWND hwnd;
RECT rc = {0, 0, 10, 10};
HRESULT hr;
UINT i;
static const int winxp_res[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
static const int win2k3_res[11] = {0, 1, 2, 3, 4, 5, 6, 5, 8, 0, 0};
static const int vista_res[11] = {0, 1, 5, 3, 4, 5, 6, 7, 7, 0, 0};
static const int win7_res[11] = {1, 1, 1, 3, 4, 1, 6, 1, 8, 8, 8};
hr = SHGetDesktopFolder(&desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&sview);
ok(hr == S_OK, "got (0x%08x)\n", hr);
fs.ViewMode = 1;
fs.fFlags = 0;
browser = IShellBrowserImpl_Construct();
hr = IShellView_CreateViewWindow(sview, NULL, &fs, browser, &rc, &hwnd);
ok(hr == S_OK || broken(hr == S_FALSE /*Win2k*/ ), "got (0x%08x)\n", hr);
hr = IShellView_QueryInterface(sview, &IID_IFolderView, (void**)&fview);
ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got (0x%08x)\n", hr);
if(SUCCEEDED(hr))
{
HWND hwnd_lv;
UINT count;
if (0)
{
/* Crashes under Win7/WinXP */
IFolderView_GetCurrentViewMode(fview, NULL);
}
hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
ok(hr == S_OK, "got (0x%08x)\n", hr);
ok(viewmode == 1, "ViewMode was %d\n", viewmode);
hr = IFolderView_SetCurrentViewMode(fview, FVM_AUTO);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IFolderView_SetCurrentViewMode(fview, 0);
ok(hr == E_INVALIDARG || broken(hr == S_OK),
"got (0x%08x)\n", hr);
hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
ok(hr == S_OK, "got (0x%08x)\n", hr);
for(i = 1; i < 9; i++)
{
hr = IFolderView_SetCurrentViewMode(fview, i);
ok(hr == S_OK || (i == 8 && hr == E_INVALIDARG /*Vista*/),
"(%d) got (0x%08x)\n", i, hr);
hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
ok(hr == S_OK, "(%d) got (0x%08x)\n", i, hr);
/* Wine currently behaves like winxp here. */
ok((viewmode == win7_res[i]) || (viewmode == vista_res[i]) ||
(viewmode == win2k3_res[i]) || (viewmode == winxp_res[i]),
"(%d) got %d\n",i , viewmode);
}
hr = IFolderView_SetCurrentViewMode(fview, 9);
ok(hr == E_INVALIDARG || broken(hr == S_OK),
"got (0x%08x)\n", hr);
/* Test messages */
hwnd_lv = subclass_listview(hwnd);
ok(hwnd_lv != NULL, "Failed to subclass listview\n");
if(hwnd_lv)
{
/* Vista seems to set the viewmode by other means than
sending messages. At least no related messages are
captured by subclassing.
*/
BOOL vista_plus = FALSE;
static const UINT vista_plus_msgs[] = {
WM_SETREDRAW, WM_NOTIFY, WM_NOTIFYFORMAT, WM_QUERYUISTATE,
WM_MENUCHAR, WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, WM_WINDOWPOSCHANGED,
WM_PARENTNOTIFY, LVM_GETHEADER, 0 };
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = IFolderView_SetCurrentViewMode(fview, 1);
ok(hr == S_OK, "got 0x%08x\n", hr);
/* WM_SETREDRAW is not sent in versions before Vista. */
vista_plus = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, WM_SETREDRAW);
if(vista_plus)
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
else
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
"IFolderView::SetCurrentViewMode(1)", TRUE);
hr = IFolderView_SetCurrentViewMode(fview, 2);
ok(hr == S_OK, "got 0x%08x\n", hr);
if(vista_plus)
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
else
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
"IFolderView::SetCurrentViewMode(2)", TRUE);
hr = IFolderView_SetCurrentViewMode(fview, 3);
ok(hr == S_OK, "got 0x%08x\n", hr);
if(vista_plus)
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
else
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode3_prevista,
"IFolderView::SetCurrentViewMode(3)", TRUE);
hr = IFolderView_SetCurrentViewMode(fview, 4);
ok(hr == S_OK, "got 0x%08x\n", hr);
if(vista_plus)
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
else
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode4_prevista,
"IFolderView::SetCurrentViewMode(4)", TRUE);
hr = IFolderView_SetCurrentViewMode(fview, 5);
ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
{
if(vista_plus)
{
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
}
else
{
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
}
}
hr = IFolderView_SetCurrentViewMode(fview, 6);
ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
{
if(vista_plus)
{
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
}
else
{
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
}
}
hr = IFolderView_SetCurrentViewMode(fview, 7);
ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
{
if(vista_plus)
{
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
}
else
{
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
}
}
hr = IFolderView_SetCurrentViewMode(fview, 8);
ok(hr == S_OK || broken(hr == E_INVALIDARG /* Vista */), "got 0x%08x\n", hr);
todo_wine
{
if(vista_plus)
{
verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
}
else
{
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
}
}
hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
ok(hr == S_OK, "Failed to get current viewmode.\n");
ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq,
"IFolderView::GetCurrentViewMode", FALSE);
}
IFolderView_Release(fview);
}
else
{
skip("No IFolderView for the desktop folder.\n");
}
IShellBrowser_Release(browser);
IShellView_DestroyViewWindow(sview);
IShellView_Release(sview);
IShellFolder_Release(desktop);
}
static void test_IOleCommandTarget(void)
{
IShellFolder *psf_desktop;
IShellView *psv;
IOleCommandTarget *poct;
HRESULT hr;
hr = SHGetDesktopFolder(&psf_desktop);
ok(hr == S_OK, "got (0x%08x)\n", hr);
hr = IShellFolder_CreateViewObject(psf_desktop, NULL, &IID_IShellView, (void**)&psv);
ok(hr == S_OK, "got (0x%08x)\n", hr);
if(SUCCEEDED(hr))
{
hr = IShellView_QueryInterface(psv, &IID_IOleCommandTarget, (void**)&poct);
ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win95/NT4 */, "Got 0x%08x\n", hr);
if(SUCCEEDED(hr))
{
OLECMD oc;
hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, NULL, NULL);
ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
oc.cmdID = 1;
hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, &oc, NULL);
ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
oc.cmdID = 1;
hr = IOleCommandTarget_QueryStatus(poct, NULL, 1, &oc, NULL);
ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
hr = IOleCommandTarget_Exec(poct, NULL, 0, 0, NULL, NULL);
ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
IOleCommandTarget_Release(poct);
}
IShellView_Release(psv);
}
IShellFolder_Release(psf_desktop);
}
START_TEST(shlview)
{
OleInitialize(NULL);
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
test_IShellView_CreateViewWindow();
test_IFolderView();
test_GetItemObject();
test_IShellFolderView();
test_IOleWindow();
test_GetSetCurrentViewMode();
test_IOleCommandTarget();
OleUninitialize();
}