shell32: Implement Set/GetCurrentViewMode in the default shellview. (try 3)

David Hedberg david.hedberg at gmail.com
Thu Jul 22 15:08:07 CDT 2010


Replaced the macro in the tests with a function.

---
 dlls/shell32/shlview.c       |   71 +++++++---
 dlls/shell32/tests/shlview.c |  341 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 393 insertions(+), 19 deletions(-)

diff --git a/dlls/shell32/shlview.c b/dlls/shell32/shlview.c
index 01fee47..73671c1 100644
--- a/dlls/shell32/shlview.c
+++ b/dlls/shell32/shlview.c
@@ -312,6 +312,29 @@ static void SetStyle(IShellViewImpl * This, DWORD dwAdd, DWORD dwRemove)
 	SetWindowLongW(This->hWndList, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
 }
 
+static DWORD ViewModeToListStyle(UINT ViewMode)
+{
+	DWORD dwStyle;
+
+	TRACE("%d\n", ViewMode);
+
+	switch (ViewMode)
+	{
+	  case FVM_ICON:	dwStyle = LVS_ICON;		break;
+	  case FVM_DETAILS:	dwStyle = LVS_REPORT;		break;
+	  case FVM_SMALLICON:	dwStyle = LVS_SMALLICON;	break;
+	  case FVM_LIST:	dwStyle = LVS_LIST;		break;
+	  default:
+	  {
+		FIXME("ViewMode %d not implemented\n", ViewMode);
+		dwStyle = LVS_LIST;
+		break;
+	  }
+	}
+
+	return dwStyle;
+}
+
 /**********************************************************
 * ShellView_CreateList()
 *
@@ -326,19 +349,7 @@ static BOOL ShellView_CreateList (IShellViewImpl * This)
 		  LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_AUTOARRANGE;
         dwExStyle = WS_EX_CLIENTEDGE;
 
-	switch (This->FolderSettings.ViewMode)
-	{
-	  case FVM_ICON:	dwStyle |= LVS_ICON;		break;
-	  case FVM_DETAILS: 	dwStyle |= LVS_REPORT;		break;
-	  case FVM_SMALLICON: 	dwStyle |= LVS_SMALLICON;	break;
-	  case FVM_LIST: 	dwStyle |= LVS_LIST;		break;
-	  default:
-	  {
-		FIXME("ViewMode %d not implemented\n", This->FolderSettings.ViewMode);
-		dwStyle |= LVS_LIST;
-		break;
-	  }
-	}
+        dwStyle |= ViewModeToListStyle(This->FolderSettings.ViewMode);
 
 	if (This->FolderSettings.fFlags & FWF_AUTOARRANGE)	dwStyle |= LVS_AUTOARRANGE;
 	if (This->FolderSettings.fFlags & FWF_DESKTOP)
@@ -2732,16 +2743,38 @@ static ULONG WINAPI IFView_Release( IFolderView *iface)
 
 static HRESULT WINAPI IFView_GetCurrentViewMode(IFolderView *iface, UINT *mode)
 {
-	IShellViewImpl *This = impl_from_IFolderView(iface);
-	FIXME("(%p)->(%p), stub\n", This, mode);
-	return E_NOTIMPL;
+    IShellViewImpl *This = impl_from_IFolderView(iface);
+    TRACE("(%p)->(%p), stub\n", This, mode);
+
+    if(!mode)
+        return E_INVALIDARG;
+
+    *mode = This->FolderSettings.ViewMode;
+    return S_OK;
 }
 
 static HRESULT WINAPI IFView_SetCurrentViewMode(IFolderView *iface, UINT mode)
 {
-	IShellViewImpl *This = impl_from_IFolderView(iface);
-	FIXME("(%p)->(%u), stub\n", This, mode);
-	return E_NOTIMPL;
+    IShellViewImpl *This = impl_from_IFolderView(iface);
+    DWORD dwStyle;
+    TRACE("(%p)->(%u), stub\n", This, mode);
+
+    if((mode < FVM_FIRST || mode > FVM_LAST) &&
+       (mode != FVM_AUTO))
+        return E_INVALIDARG;
+
+    /* Windows before Vista uses LVM_SETVIEW and possibly
+       LVM_SETEXTENDEDLISTVIEWSTYLE to set the style of the listview,
+       while later versions seem to accomplish this through other
+       means. */
+    dwStyle = ViewModeToListStyle(mode);
+    SetStyle(This, dwStyle, LVS_TYPEMASK);
+
+    /* This will not necessarily be the actual mode set above.
+       This mimics the behavior of Windows XP. */
+    This->FolderSettings.ViewMode = mode;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IFView_GetFolder(IFolderView *iface, REFIID riid, void **ppv)
diff --git a/dlls/shell32/tests/shlview.c b/dlls/shell32/tests/shlview.c
index e86518d..0992252 100644
--- a/dlls/shell32/tests/shlview.c
+++ b/dlls/shell32/tests/shlview.c
@@ -96,6 +96,44 @@ static HWND subclass_listview(HWND hwnd)
     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 {
     const IDataObjectVtbl *lpVtbl;
@@ -753,6 +791,308 @@ static void test_IOleWindow(void)
     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},
+    { 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 */
+            hr = 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");
+    }
+
+    IShellView_DestroyViewWindow(sview);
+    IShellView_Release(sview);
+    IShellFolder_Release(desktop);
+}
+
 START_TEST(shlview)
 {
     OleInitialize(NULL);
@@ -764,6 +1104,7 @@ START_TEST(shlview)
     test_GetItemObject();
     test_IShellFolderView();
     test_IOleWindow();
+    test_GetSetCurrentViewMode();
 
     OleUninitialize();
 }
-- 
1.7.1.1




More information about the wine-patches mailing list