/* * 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 #include #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/heap.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; struct message msg = { 0 }; LRESULT ret; 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 = heap_alloc(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->IDataObject_iface; } if(*ppvObj) { IDataObject_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) heap_free(This); 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 = heap_alloc(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->IShellBrowser_iface; } if(*ppvObj) { IShellBrowser_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) heap_free(This); 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 HRESULT WINAPI shellbrowser_QueryInterface(IShellBrowser *iface, REFIID riid, void **ppv) { *ppv = NULL; if (IsEqualGUID(&IID_IShellBrowser, riid) || IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IUnknown, riid)) { *ppv = iface; } if (*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI shellbrowser_AddRef(IShellBrowser *iface) { return 2; } static ULONG WINAPI shellbrowser_Release(IShellBrowser *iface) { return 1; } static HRESULT WINAPI shellbrowser_GetWindow(IShellBrowser *iface, HWND *phwnd) { *phwnd = GetDesktopWindow(); return S_OK; } static HRESULT WINAPI shellbrowser_ContextSensitiveHelp(IShellBrowser *iface, BOOL mode) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_InsertMenusSB(IShellBrowser *iface, HMENU hmenuShared, OLEMENUGROUPWIDTHS *menuwidths) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetMenuSB(IShellBrowser *iface, HMENU hmenuShared, HOLEMENU holemenuReserved, HWND hwndActiveObject) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_RemoveMenusSB(IShellBrowser *iface, HMENU hmenuShared) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetStatusTextSB(IShellBrowser *iface, LPCOLESTR text) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_EnableModelessSB(IShellBrowser *iface, BOOL enable) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_TranslateAcceleratorSB(IShellBrowser *iface, MSG *pmsg, WORD wID) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_BrowseObject(IShellBrowser *iface, LPCITEMIDLIST pidl, UINT flags) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_GetViewStateStream(IShellBrowser *iface, DWORD mode, IStream **stream) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_GetControlWindow(IShellBrowser *iface, UINT id, HWND *phwnd) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SendControlMsg(IShellBrowser *iface, UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) { return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_QueryActiveShellView(IShellBrowser *iface, IShellView **view) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_OnViewWindowActive(IShellBrowser *iface, IShellView *view) { ok(0, "unexpected\n"); return E_NOTIMPL; } static HRESULT WINAPI shellbrowser_SetToolbarItems(IShellBrowser *iface, LPTBBUTTONSB buttons, UINT count, UINT flags) { return E_NOTIMPL; } static const IShellBrowserVtbl shellbrowservtbl = { shellbrowser_QueryInterface, shellbrowser_AddRef, shellbrowser_Release, shellbrowser_GetWindow, shellbrowser_ContextSensitiveHelp, shellbrowser_InsertMenusSB, shellbrowser_SetMenuSB, shellbrowser_RemoveMenusSB, shellbrowser_SetStatusTextSB, shellbrowser_EnableModelessSB, shellbrowser_TranslateAcceleratorSB, shellbrowser_BrowseObject, shellbrowser_GetViewStateStream, shellbrowser_GetControlWindow, shellbrowser_SendControlMsg, shellbrowser_QueryActiveShellView, shellbrowser_OnViewWindowActive, shellbrowser_SetToolbarItems }; static IShellBrowser test_shellbrowser = { &shellbrowservtbl }; static void test_CreateViewWindow(void) { IShellFolder *desktop; HWND hwnd_view, hwnd2; FOLDERSETTINGS settings; IShellView *view; IDropTarget *dt; HRESULT hr; RECT r = {0}; ULONG ref1, ref2; IUnknown *unk; 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_CDefView, (void **)&unk); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(unk == (IUnknown *)view, "got %p\n", unk); IUnknown_Release(unk); 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); hwnd_view = NULL; hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd_view); ok(hr == S_OK || broken(hr == S_FALSE), "got (0x%08x)\n", hr); ok(hwnd_view != 0, "got %p\n", hwnd_view); hwnd2 = (HWND)0xdeadbeef; hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd2); ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr); ok(hwnd2 == NULL, "got %p\n", hwnd2); /* ::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_AddRef(view); ref1 = IShellView_Release(view); hr = IShellView_DestroyViewWindow(view); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(!IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view); ref2 = IShellView_Release(view); ok(ref1 > ref2, "expected %u > %u\n", ref1, ref2); ref1 = ref2; /* Show that releasing the shell view does not destroy the window */ hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&view); ok(hr == S_OK, "got (0x%08x)\n", hr); hwnd_view = NULL; hr = IShellView_CreateViewWindow(view, NULL, &settings, &test_shellbrowser, &r, &hwnd_view); ok(hr == S_OK || broken(hr == S_FALSE), "got (0x%08x)\n", hr); ok(hwnd_view != NULL, "got %p\n", hwnd_view); ok(IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view); ref2 = IShellView_Release(view); ok(ref2 != 0, "ref2 = %u\n", ref2); ok(ref2 > ref1, "expected %u > %u\n", ref2, ref1); ok(IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view); DestroyWindow(hwnd_view); IShellFolder_Release(desktop); } static void test_IFolderView(void) { IShellFolder *desktop, *folder; FOLDERSETTINGS settings; IShellView *view; IShellBrowser *browser; IFolderView2 *fv2; IFolderView *fv; IUnknown *unk; HWND hwnd_view, hwnd_list; PITEMID_CHILD pidl; HRESULT hr; INT ret, count; POINT pt; 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; SetRect(&r, 0, 0, 100, 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); hr = IFolderView_GetFolder(fv, &IID_IShellFolder, (void**)&folder); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(desktop == folder, "\n"); if (folder) IShellFolder_Release(folder); hr = IFolderView_GetFolder(fv, &IID_IUnknown, (void**)&unk); ok(hr == S_OK, "got (0x%08x)\n", hr); if (unk) IUnknown_Release(unk); hr = IFolderView_QueryInterface(fv, &IID_IFolderView2, (void**)&fv2); if (hr != S_OK) win_skip("IFolderView2 is not supported.\n"); if (fv2) IFolderView2_Release(fv2); hr = IShellView_DestroyViewWindow(view); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(!IsWindow(hwnd_view), "hwnd %p still valid\n", hwnd_view); 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); 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; IOleWindow *wnd; 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_IOleWindow, (void**)&wnd); ok(hr == E_NOINTERFACE, "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); } static void test_SHCreateShellFolderView(void) { IShellFolder *desktop; IShellView *psv; SFV_CREATE sfvc; ULONG refCount; IUnknown *unk; HRESULT hr; hr = SHGetDesktopFolder(&desktop); ok(hr == S_OK, "got (0x%08x)\n", hr); if (0) { /* crash on win7 */ SHCreateShellFolderView(NULL, NULL); } psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(NULL, &psv); ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); memset(&sfvc, 0, sizeof(sfvc)); psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); memset(&sfvc, 0, sizeof(sfvc)); sfvc.cbSize = sizeof(sfvc) - 1; psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); memset(&sfvc, 0, sizeof(sfvc)); sfvc.cbSize = sizeof(sfvc) + 1; psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); if (0) { /* Crashes on NULL 'pshf' on XP/2k3 */ memset(&sfvc, 0, sizeof(sfvc)); sfvc.cbSize = sizeof(sfvc); psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == E_UNEXPECTED, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); } memset(&sfvc, 0, sizeof(sfvc)); sfvc.cbSize = sizeof(sfvc) - 1; sfvc.pshf = desktop; psv = (void *)0xdeadbeef; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); memset(&sfvc, 0, sizeof(sfvc)); sfvc.cbSize = sizeof(sfvc); sfvc.pshf = desktop; psv = NULL; hr = SHCreateShellFolderView(&sfvc, &psv); ok(hr == S_OK, "Got 0x%08x\n", hr); ok(psv != NULL, "psv = %p\n", psv); hr = IShellView_QueryInterface(psv, &IID_CDefView, (void **)&unk); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(unk == (IUnknown *)psv, "got %p\n", unk); IUnknown_Release(unk); refCount = IShellView_Release(psv); ok(refCount == 0, "refCount = %u\n", refCount); IShellFolder_Release(desktop); } static void test_SHCreateShellFolderViewEx(void) { IShellFolder *desktop; IShellView *psv; ULONG refCount; IUnknown *unk; HRESULT hr; CSFV csfv; hr = SHGetDesktopFolder(&desktop); ok(hr == S_OK, "got (0x%08x)\n", hr); if (0) { /* crash on win7 */ SHCreateShellFolderViewEx(NULL, NULL); SHCreateShellFolderViewEx(NULL, &psv); SHCreateShellFolderViewEx(&csfv, NULL); } memset(&csfv, 0, sizeof(csfv)); csfv.pshf = desktop; psv = NULL; hr = SHCreateShellFolderViewEx(&csfv, &psv); ok(hr == S_OK, "Got 0x%08x\n", hr); ok(psv != NULL, "psv = %p\n", psv); hr = IShellView_QueryInterface(psv, &IID_CDefView, (void **)&unk); ok(hr == S_OK, "got (0x%08x)\n", hr); ok(unk == (IUnknown *)psv, "got %p\n", unk); IUnknown_Release(unk); refCount = IShellView_Release(psv); ok(refCount == 0, "refCount = %u\n", refCount); if (0) { /* Crashes on null shellfolder, on XP/2k3 */ memset(&csfv, 0, sizeof(csfv)); csfv.pshf = NULL; psv = (void *)0xdeadbeef; hr = SHCreateShellFolderViewEx(&csfv, &psv); ok(hr == E_UNEXPECTED, "Got 0x%08x\n", hr); ok(psv == NULL, "psv = %p\n", psv); } memset(&csfv, 0, sizeof(csfv)); csfv.cbSize = sizeof(csfv); csfv.pshf = desktop; psv = NULL; hr = SHCreateShellFolderViewEx(&csfv, &psv); ok(hr == S_OK, "Got 0x%08x\n", hr); ok(psv != NULL, "psv = %p\n", psv); if (psv) { refCount = IShellView_Release(psv); ok(refCount == 0, "refCount = %u\n", refCount); } IShellFolder_Release(desktop); } static void test_newmenu(void) { IUnknown *unk, *unk2; HRESULT hr; hr = CoCreateInstance(&CLSID_NewMenu, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk); todo_wine ok(hr == S_OK, "Failed to create NewMenu object, hr %#x.\n", hr); if (hr != S_OK) { skip("NewMenu is not supported.\n"); return; } hr = IUnknown_QueryInterface(unk, &IID_IShellExtInit, (void **)&unk2); ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr); IUnknown_Release(unk2); hr = IUnknown_QueryInterface(unk, &IID_IContextMenu3, (void **)&unk2); ok(hr == S_OK, "Failed to get IContextMenu3, hr %#x.\n", hr); IUnknown_Release(unk2); hr = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void **)&unk2); ok(hr == S_OK, "Failed to get IObjectWithSite, hr %#x.\n", hr); IUnknown_Release(unk2); IUnknown_Release(unk); } START_TEST(shlview) { OleInitialize(NULL); init_msg_sequences(sequences, NUM_MSG_SEQUENCES); test_CreateViewWindow(); test_IFolderView(); test_GetItemObject(); test_IShellFolderView(); test_IOleWindow(); test_GetSetCurrentViewMode(); test_IOleCommandTarget(); test_SHCreateShellFolderView(); test_SHCreateShellFolderViewEx(); test_newmenu(); OleUninitialize(); }