[PATCH 7/8] explorerframe/nstc: Add/remove roots.

David Hedberg david.hedberg at gmail.com
Thu Jul 29 14:26:06 CDT 2010


---
 dlls/explorerframe/nstc.c       |  316 +++++++++++++++++++++++++++++++++++++--
 dlls/explorerframe/tests/nstc.c |  160 ++++++++++++++++++++
 2 files changed, 466 insertions(+), 10 deletions(-)

diff --git a/dlls/explorerframe/nstc.c b/dlls/explorerframe/nstc.c
index ca8595d..a6793b0 100644
--- a/dlls/explorerframe/nstc.c
+++ b/dlls/explorerframe/nstc.c
@@ -25,13 +25,25 @@
 #include "winerror.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
+#include "shellapi.h"
 
+#include "wine/list.h"
 #include "wine/debug.h"
 
 #include "explorerframe_main.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(nstc);
 
+typedef struct nstc_root {
+    IShellItem *psi;
+    HTREEITEM htreeitem;
+    SHCONTF enum_flags;
+    NSTCROOTSTYLE root_style;
+    IShellItemFilter *pif;
+    struct list entry;
+} nstc_root;
+
 typedef struct {
     const INameSpaceTreeControl2Vtbl *lpVtbl;
     const IOleWindowVtbl *lpowVtbl;
@@ -42,6 +54,7 @@ typedef struct {
 
     NSTCSTYLE style;
     NSTCSTYLE2 style2;
+    struct list roots;
 
     INameSpaceTreeControlEvents *pnstce;
 } NSTC2Impl;
@@ -55,6 +68,34 @@ static const DWORD unsupported_styles2 =
     NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
 
 /*************************************************************************
+* NamespaceTree Event Wrappers
+*/
+static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi,
+                                            int *piDefaultIcon, int *piOpenIcon)
+{
+    if(!This->pnstce)
+        return E_NOTIMPL;
+    return INameSpaceTreeControlEvents_OnGetDefaultIconIndex(
+        This->pnstce, psi, piDefaultIcon, piOpenIcon);
+}
+
+static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
+{
+    if(!This->pnstce)
+        return S_OK;
+    return INameSpaceTreeControlEvents_OnItemAdded(
+        This->pnstce, psi, fIsRoot);
+}
+
+static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
+{
+    if(!This->pnstce)
+        return S_OK;
+    return INameSpaceTreeControlEvents_OnItemDeleted(
+        This->pnstce, psi, fIsRoot);
+}
+
+/*************************************************************************
  * NamespaceTree helper functions
  */
 static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
@@ -102,6 +143,85 @@ static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
     return old_style^*new_style;
 }
 
+static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem)
+{
+    TVITEMEXW tvi;
+
+    tvi.mask = TVIF_PARAM;
+    tvi.lParam = (LPARAM)NULL;
+    tvi.hItem = hitem;
+
+    SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi);
+
+    TRACE("ShellItem: %p\n", (void*)tvi.lParam);
+    return (IShellItem*)tvi.lParam;
+}
+
+/* From brsfolder.c */
+static int GetIcon(LPCITEMIDLIST lpi, UINT extra_flags)
+{
+    SHFILEINFOW sfi;
+    UINT flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
+    SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), flags | extra_flags);
+    return sfi.iIcon;
+}
+
+static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
+                                  HTREEITEM hParent, HTREEITEM hInsertAfter)
+{
+    TVINSERTSTRUCTW tvins;
+    TVITEMEXW tvi;
+    LPWSTR display_name;
+    HTREEITEM hinserted;
+    LPITEMIDLIST pidl;
+    TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
+
+    tvi.mask = TVIF_PARAM | TVIF_CHILDREN;
+    tvi.cChildren = I_CHILDRENCALLBACK;
+
+    if(SUCCEEDED(IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name)))
+    {
+        tvi.mask |= TVIF_TEXT;
+        tvi.pszText = display_name;
+    }
+    else
+        ERR("Failed to get display name from ShellItem.\n");
+
+    if(SUCCEEDED(events_OnGetDefaultIconIndex(This, psi, &tvi.iImage, &tvi.iSelectedImage)))
+    {
+        /* icons provided by the client */
+        tvi.iExpandedImage = tvi.iSelectedImage;
+    }
+    else
+    {
+        if(SUCCEEDED(SHGetIDListFromObject((IUnknown*)psi, &pidl)))
+        {
+            tvi.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_EXPANDEDIMAGE;
+            tvi.iImage = tvi.iSelectedImage = GetIcon(pidl, 0);
+            tvi.iExpandedImage = GetIcon(pidl,SHGFI_OPENICON);
+            ILFree(pidl);
+        }
+        else
+            ERR("Failed to get pidl from ShellItem.\n");
+    }
+
+    /* Add a pointer to the ShellItem */
+    tvi.lParam = (LPARAM)psi;
+    tvins.itemex = tvi;
+    tvins.hParent = hParent;
+    tvins.hInsertAfter = hInsertAfter;
+
+    /* Insert it. */
+    hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW,
+                                        0, (LPARAM)(LPTVINSERTSTRUCTW)&tvins);
+
+    if(hinserted)
+        IShellItem_AddRef(psi);
+
+    CoTaskMemFree(display_name);
+    return hinserted;
+}
+
 /*************************************************************************
  * NamespaceTree Window Functions
  */
@@ -178,20 +298,64 @@ static LRESULT destroy_namespacetree(NSTC2Impl *This)
 {
     TRACE("%p\n", This);
 
+    INameSpaceTreeControl_RemoveAllRoots((INameSpaceTreeControl*)This);
     INameSpaceTreeControl_Release((INameSpaceTreeControl*)This);
     return TRUE;
 }
 
+static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam)
+{
+    NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam;
+    TRACE("%p\n", This);
+
+    /* Release the associated shellitem */
+    IShellItem_Release((IShellItem*)nmtv->itemOld.lParam);
+    return TRUE;
+}
+
+static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam)
+{
+    NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam;
+    HRESULT hr;
+
+    TRACE("%p, %p (mask: %x)\n", This, dispinfo, dispinfo->item.mask);
+
+    if(dispinfo->item.mask & TVIF_CHILDREN)
+    {
+        IShellItem *psi = shellitem_from_treeitem(This, dispinfo->item.hItem);
+        SFGAOF sfgao;
+
+        hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao);
+        if(FAILED(hr))
+            dispinfo->item.cChildren = 1;
+        else
+            dispinfo->item.cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0;
+
+        dispinfo->item.mask |= TVIF_DI_SETITEM;
+    }
+    return FALSE;
+}
+
 static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
                                       WPARAM wParam, LPARAM lParam)
 {
     NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+    NMHDR *nmhdr;
 
     switch(uMessage)
     {
     case WM_NCCREATE:         return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
     case WM_SIZE:             return resize_namespacetree(This);
     case WM_DESTROY:          return destroy_namespacetree(This);
+    case WM_NOTIFY:
+        nmhdr = (NMHDR*)lParam;
+        switch(nmhdr->code)
+        {
+        case TVN_DELETEITEMW:     return on_tvn_deleteitemw(This, lParam);
+        case TVN_GETDISPINFOW:    return on_tvn_getdispinfow(This, lParam);
+        default:                  break;
+        }
+        break;
     default:                  return DefWindowProcW(hWnd, uMessage, wParam, lParam);
     }
     return 0;
@@ -371,9 +535,65 @@ static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
                                          IShellItemFilter *pif)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p, %p, %x, %x, %p\n",
+    nstc_root *new_root;
+    struct list *add_after;
+    HTREEITEM hti_add_after;
+    UINT i;
+
+    TRACE("%p, %p, %x, %x, %p\n",
           This, psiRoot, grfEnumFlags, grfRootStyle, pif);
-    return E_NOTIMPL;
+
+    new_root = HeapAlloc(GetProcessHeap(), 0, sizeof(nstc_root));
+    if(!new_root)
+        return E_OUTOFMEMORY;
+
+    new_root->psi = psiRoot;
+    new_root->enum_flags = grfEnumFlags;
+    new_root->root_style = grfRootStyle;
+    new_root->pif = pif;
+
+    /* Find the right place in the list of roots. */
+    for(i = 0, add_after = &This->roots;
+        (add_after->next != &This->roots) && (i < iIndex);
+        add_after = add_after->next, i++) {}
+
+    /* Insert the root into the treeview */
+    if(add_after != &This->roots)
+    {
+        nstc_root *root_add_after = LIST_ENTRY(add_after, nstc_root, entry);
+        hti_add_after = root_add_after->htreeitem;
+    }
+    else
+        hti_add_after = TVI_FIRST;
+
+    new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT,
+                                           hti_add_after);
+    if(!new_root->htreeitem)
+    {
+        ERR("Failed to add the root.\n");
+        HeapFree(GetProcessHeap(), 0, new_root);
+        return E_FAIL;
+    }
+
+    list_add_after(add_after, &new_root->entry);
+    events_OnItemAdded(This, psiRoot, TRUE);
+
+    if(grfRootStyle & NSTCRS_HIDDEN)
+    {
+        TVITEMEXW tvi;
+        tvi.mask = TVIF_STATEEX;
+        tvi.uStateEx = TVIS_EX_FLAT;
+        tvi.hItem = new_root->htreeitem;
+
+        SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi);
+    }
+
+    if(grfRootStyle & NSTCRS_EXPANDED)
+        SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_EXPAND,
+                     (LPARAM)new_root->htreeitem);
+
+
+    return S_OK;
 }
 
 static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
@@ -383,32 +603,106 @@ static HRESULT WINAPI NSTC2_fnAppendRoot(INameSpaceTreeControl2* iface,
                                          IShellItemFilter *pif)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p, %p, %x, %x, %p\n",
+    UINT root_count;
+    TRACE("%p, %p, %x, %x, %p\n",
           This, psiRoot, grfEnumFlags, grfRootStyle, pif);
-    return E_NOTIMPL;
+
+    root_count = list_count(&This->roots);
+
+    return NSTC2_fnInsertRoot(iface, root_count, psiRoot, grfEnumFlags, grfRootStyle, pif);
 }
 
 static HRESULT WINAPI NSTC2_fnRemoveRoot(INameSpaceTreeControl2* iface,
                                          IShellItem *psiRoot)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p (%p)\n", This, psiRoot);
-    return E_NOTIMPL;
+    nstc_root *cursor, *root = NULL;
+    TRACE("%p (%p)\n", This, psiRoot);
+
+    if(!psiRoot)
+        return E_NOINTERFACE;
+
+    LIST_FOR_EACH_ENTRY(cursor, &This->roots, nstc_root, entry)
+    {
+        HRESULT hr;
+        int order;
+        TRACE("cursor->psi is %p\n", cursor->psi);
+        hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order);
+        if(hr == S_OK)
+        {
+            root = cursor;
+            break;
+        }
+    }
+
+    TRACE("root %p\n", root);
+    if(root)
+    {
+        SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem);
+        events_OnItemDeleted(This, root->psi, TRUE);
+        list_remove(&root->entry);
+        HeapFree(GetProcessHeap(), 0, root);
+        return S_OK;
+    }
+    else
+    {
+        ERR("No matching root found.\n");
+        return E_FAIL;
+    }
 }
 
 static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p\n", This);
-    return E_NOTIMPL;
+    nstc_root *cur1, *cur2;
+    UINT removed = 0;
+    TRACE("%p\n", This);
+
+    LIST_FOR_EACH_ENTRY_SAFE(cur1, cur2, &This->roots, nstc_root, entry)
+    {
+        NSTC2_fnRemoveRoot(iface, cur1->psi);
+        removed++;
+    }
+
+    if(removed)
+        return S_OK;
+    else
+        return E_INVALIDARG;
 }
 
 static HRESULT WINAPI NSTC2_fnGetRootItems(INameSpaceTreeControl2* iface,
                                            IShellItemArray **ppsiaRootItems)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p (%p)\n", This, ppsiaRootItems);
-    return E_NOTIMPL;
+    IShellFolder *psf;
+    LPITEMIDLIST *array;
+    nstc_root *root;
+    UINT count, i;
+    HRESULT hres;
+    TRACE("%p (%p)\n", This, ppsiaRootItems);
+
+    count = list_count(&This->roots);
+
+    if(!count)
+        return E_INVALIDARG;
+
+    array = HeapAlloc(GetProcessHeap(), 0, sizeof(LPITEMIDLIST*)*count);
+
+    i = 0;
+    LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry)
+        SHGetIDListFromObject((IUnknown*)root->psi, &array[i++]);
+
+    SHGetDesktopFolder(&psf);
+    hres = SHCreateShellItemArray(NULL, psf, count, (PCUITEMID_CHILD_ARRAY)array,
+                                  ppsiaRootItems);
+    IShellFolder_Release(psf);
+
+    for(i = 0; i < count; i++)
+        ILFree(array[i]);
+
+    HeapFree(GetProcessHeap(), 0, array);
+
+    return hres;
 }
 
 static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface,
@@ -709,6 +1003,8 @@ HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void
     nstc->lpVtbl = &vt_INameSpaceTreeControl2;
     nstc->lpowVtbl = &vt_IOleWindow;
 
+    list_init(&nstc->roots);
+
     ret = INameSpaceTreeControl_QueryInterface((INameSpaceTreeControl*)nstc, riid, ppv);
     INameSpaceTreeControl_Release((INameSpaceTreeControl*)nstc);
 
diff --git a/dlls/explorerframe/tests/nstc.c b/dlls/explorerframe/tests/nstc.c
index a3999b1..67ed2a6 100644
--- a/dlls/explorerframe/tests/nstc.c
+++ b/dlls/explorerframe/tests/nstc.c
@@ -320,6 +320,35 @@ const INameSpaceTreeControlEventsVtbl vt_NSTCEvents = {
 };
 #undef NSTCE_IMPL
 
+/* Process some messages */
+static void process_msgs(void)
+{
+    MSG msg;
+    BOOL got_msg;
+    do {
+        got_msg = FALSE;
+        Sleep(100);
+        while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
+        {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+            got_msg = TRUE;
+        }
+    } while(got_msg);
+
+    /* There is a timer that sometimes fires after about 500ms, sadly
+       we need to wait for it (Timer ID is 87, sending WM_TIMER
+       manually does not seem to help us.). Failing to wait can
+       results in seemingly sporadic selection changes. */
+    Sleep(500);
+
+    while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+}
+
 static void test_initialization(void)
 {
     INameSpaceTreeControl2 *pnstc;
@@ -471,20 +500,148 @@ static void test_basics(void)
 {
     INameSpaceTreeControl *pnstc;
     INameSpaceTreeControl2 *pnstc2;
+    IShellItemArray *psia;
+    IShellFolder *psfdesktop;
+    IShellItem *psidesktop, *psidesktop2;
     IOleWindow *pow;
+    LPITEMIDLIST pidl_desktop;
     HRESULT hr;
     UINT i, res;
     RECT rc;
 
+    /* These should exist on platforms supporting the NSTC */
+    ok(pSHCreateShellItem != NULL, "No SHCreateShellItem.\n");
+    ok(pSHGetIDListFromObject != NULL, "No SHCreateShellItem.\n");
+
+    /* Create ShellItems for testing. */
+    SHGetDesktopFolder(&psfdesktop);
+    hr = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl_desktop);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr)) {
+        hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psidesktop);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psidesktop2);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        ILFree(pidl_desktop);
+    }
+    ok(psidesktop != psidesktop2, "psidesktop == psidesktop2\n");
+    IShellFolder_Release(psfdesktop);
+
     hr = CoCreateInstance(&CLSID_NamespaceTreeControl, NULL, CLSCTX_INPROC_SERVER,
                           &IID_INameSpaceTreeControl, (void**)&pnstc);
     ok(hr == S_OK, "Failed to initialize control (0x%08x)\n", hr);
 
+    /* Some tests on an uninitialized control */
+    hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
+    ok(hr == E_INVALIDARG, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, psidesktop);
+    ok(hr == E_FAIL, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, NULL);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_NONFOLDERS, 0, NULL);
+    ok(hr == E_FAIL, "Got (0x%08x)\n", hr);
+    process_msgs();
+
     /* Initialize the control */
     rc.top = rc.left = 0; rc.right = rc.bottom = 200;
     hr = INameSpaceTreeControl_Initialize(pnstc, hwnd, &rc, 0);
     ok(hr == S_OK, "Got (0x%08x)\n", hr);
 
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, NULL);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+
+    if(0)
+    {
+        /* Crashes with native */
+        hr = INameSpaceTreeControl_AppendRoot(pnstc, NULL, SHCONTF_FOLDERS, 0, NULL);
+        hr = INameSpaceTreeControl_InsertRoot(pnstc, 0, NULL, SHCONTF_FOLDERS, 0, NULL);
+
+    }
+
+    /* Note the usage of psidesktop and psidesktop2 */
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop2, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    process_msgs();
+
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, psidesktop);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, psidesktop);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, psidesktop);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_RemoveRoot(pnstc, psidesktop);
+    ok(hr == E_FAIL, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
+    ok(hr == E_INVALIDARG, "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_InsertRoot(pnstc, 0, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_InsertRoot(pnstc, -1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_InsertRoot(pnstc, -1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_InsertRoot(pnstc, 50, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_InsertRoot(pnstc, 1, psidesktop, SHCONTF_FOLDERS, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+
+    if(0)
+    {
+        /* Crashes on native. */
+        hr = INameSpaceTreeControl_GetRootItems(pnstc, NULL);
+    }
+
+    hr = INameSpaceTreeControl_GetRootItems(pnstc, &psia);
+    ok(hr == E_INVALIDARG, "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0x1234, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0xDEADBEEF, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0, 0, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0, 1234, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_AppendRoot(pnstc, psidesktop, 0, 0xDEADBEEF, NULL);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    process_msgs();
+
+    hr = INameSpaceTreeControl_GetRootItems(pnstc, &psia);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        DWORD count, i;
+        hr = IShellItemArray_GetCount(psia, &count);
+        ok(hr == S_OK, "Got (0x%08x)\n", hr);
+        ok(count == 6, "Got %d roots.\n", hr);
+        for(i = 0; i < count; i++)
+        {
+            IShellItem *psi;
+            hr = IShellItemArray_GetItemAt(psia, i, &psi);
+            ok(hr == S_OK, "Got (0x%08x)\n", hr);
+            if(SUCCEEDED(hr)) IShellItem_Release(psi);
+        }
+
+        IShellItemArray_Release(psia);
+    }
+
+    hr = INameSpaceTreeControl_RemoveAllRoots(pnstc);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
 
     /* Set/GetControlStyle(2) */
     hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_INameSpaceTreeControl2, (void**)&pnstc2);
@@ -696,6 +853,9 @@ static void test_basics(void)
         skip("INameSpaceTreeControl2 missing.\n");
     }
 
+    IShellItem_Release(psidesktop);
+    IShellItem_Release(psidesktop2);
+
     hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleWindow, (void**)&pow);
     ok(hr == S_OK, "Got 0x%08x\n", hr);
     if(SUCCEEDED(hr))
-- 
1.7.2




More information about the wine-patches mailing list