explorerframe: Implement InsertRoot and AppendRoot.
This commit is contained in:
parent
94dfbcaad5
commit
f87891c362
|
@ -4,7 +4,7 @@ TOPOBJDIR = ../..
|
|||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = explorerframe.dll
|
||||
IMPORTS = uuid shell32 user32
|
||||
IMPORTS = uuid ole32 shell32 user32
|
||||
|
||||
C_SRCS = \
|
||||
explorerframe_main.c \
|
||||
|
|
|
@ -27,13 +27,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;
|
||||
|
@ -44,6 +56,7 @@ typedef struct {
|
|||
|
||||
NSTCSTYLE style;
|
||||
NSTCSTYLE2 style2;
|
||||
struct list roots;
|
||||
|
||||
INameSpaceTreeControlEvents *pnstce;
|
||||
} NSTC2Impl;
|
||||
|
@ -56,6 +69,22 @@ static const DWORD unsupported_styles2 =
|
|||
NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING |
|
||||
NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED;
|
||||
|
||||
/*************************************************************************
|
||||
* NamespaceTree event wrappers
|
||||
*/
|
||||
static HRESULT events_OnItemAdded(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot)
|
||||
{
|
||||
HRESULT ret;
|
||||
LONG refcount;
|
||||
if(!This->pnstce) return S_OK;
|
||||
|
||||
refcount = IShellItem_AddRef(psi);
|
||||
ret = INameSpaceTreeControlEvents_OnItemAdded(This->pnstce, psi, fIsRoot);
|
||||
if(IShellItem_Release(psi) < refcount - 1)
|
||||
ERR("ShellItem was released by client - please file a bug.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* NamespaceTree helper functions
|
||||
*/
|
||||
|
@ -106,6 +135,34 @@ static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
|
|||
return old_style^*new_style;
|
||||
}
|
||||
|
||||
/* Insert a shellitem into the given place in the tree and return the
|
||||
resulting treeitem. */
|
||||
static HTREEITEM insert_shellitem(NSTC2Impl *This, IShellItem *psi,
|
||||
HTREEITEM hParent, HTREEITEM hInsertAfter)
|
||||
{
|
||||
TVINSERTSTRUCTW tvins;
|
||||
TVITEMEXW *tvi = &tvins.u.itemex;
|
||||
HTREEITEM hinserted;
|
||||
TRACE("%p (%p, %p)\n", psi, hParent, hInsertAfter);
|
||||
|
||||
tvi->mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
|
||||
tvi->cChildren = I_CHILDRENCALLBACK;
|
||||
tvi->iImage = tvi->iSelectedImage = I_IMAGECALLBACK;
|
||||
tvi->pszText = LPSTR_TEXTCALLBACKW;
|
||||
|
||||
/* Every treeitem contains a pointer to the corresponding ShellItem. */
|
||||
tvi->lParam = (LPARAM)psi;
|
||||
tvins.hParent = hParent;
|
||||
tvins.hInsertAfter = hInsertAfter;
|
||||
|
||||
hinserted = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_INSERTITEMW, 0,
|
||||
(LPARAM)(LPTVINSERTSTRUCTW)&tvins);
|
||||
if(hinserted)
|
||||
IShellItem_AddRef(psi);
|
||||
|
||||
return hinserted;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* NamespaceTree window functions
|
||||
*/
|
||||
|
@ -365,8 +422,59 @@ static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface,
|
|||
IShellItemFilter *pif)
|
||||
{
|
||||
NSTC2Impl *This = (NSTC2Impl*)iface;
|
||||
FIXME("stub, %p, %p, %x, %x, %p\n", This, psiRoot, grfEnumFlags, grfRootStyle, pif);
|
||||
return E_NOTIMPL;
|
||||
nstc_root *new_root;
|
||||
struct list *add_after_entry;
|
||||
HTREEITEM add_after_hitem;
|
||||
UINT i;
|
||||
|
||||
TRACE("%p, %d, %p, %x, %x, %p\n", This, iIndex, psiRoot, grfEnumFlags, grfRootStyle, pif);
|
||||
|
||||
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;
|
||||
|
||||
/* We want to keep the roots in the internal list and in the
|
||||
* treeview in the same order. */
|
||||
add_after_entry = &This->roots;
|
||||
for(i = 0; i < max(0, iIndex) && list_next(&This->roots, add_after_entry); i++)
|
||||
add_after_entry = list_next(&This->roots, add_after_entry);
|
||||
|
||||
if(add_after_entry == &This->roots)
|
||||
add_after_hitem = TVI_FIRST;
|
||||
else
|
||||
add_after_hitem = LIST_ENTRY(add_after_entry, nstc_root, entry)->htreeitem;
|
||||
|
||||
new_root->htreeitem = insert_shellitem(This, psiRoot, TVI_ROOT, add_after_hitem);
|
||||
if(!new_root->htreeitem)
|
||||
{
|
||||
WARN("Failed to add the root.\n");
|
||||
HeapFree(GetProcessHeap(), 0, new_root);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
list_add_after(add_after_entry, &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,
|
||||
|
@ -376,9 +484,13 @@ 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,
|
||||
|
@ -702,6 +814,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);
|
||||
|
||||
|
|
|
@ -315,6 +315,35 @@ static INameSpaceTreeControlEventsImpl *create_nstc_events(void)
|
|||
return This;
|
||||
}
|
||||
|
||||
/* 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 seem to be a timer that sometimes fires after about
|
||||
500ms, we need to wait for it. Failing to wait can result in
|
||||
seemingly sporadic selection change events. (Timer ID is 87,
|
||||
sending WM_TIMER manually does not seem to help us.) */
|
||||
Sleep(500);
|
||||
|
||||
while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns FALSE if the NamespaceTreeControl failed to be instantiated. */
|
||||
static BOOL test_initialization(void)
|
||||
{
|
||||
|
@ -470,15 +499,52 @@ static void test_basics(void)
|
|||
{
|
||||
INameSpaceTreeControl *pnstc;
|
||||
INameSpaceTreeControl2 *pnstc2;
|
||||
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);
|
||||
if(SUCCEEDED(hr))
|
||||
{
|
||||
hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psidesktop2);
|
||||
ok(hr == S_OK, "Got 0x%08x\n", hr);
|
||||
if(FAILED(hr)) IShellItem_Release(psidesktop);
|
||||
}
|
||||
ILFree(pidl_desktop);
|
||||
}
|
||||
ok(psidesktop != psidesktop2, "psidesktop == psidesktop2\n");
|
||||
IShellFolder_Release(psfdesktop);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
win_skip("Test setup failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
@ -697,6 +763,37 @@ static void test_basics(void)
|
|||
skip("INameSpaceTreeControl2 missing.\n");
|
||||
}
|
||||
|
||||
/* Append / Insert root */
|
||||
if(0)
|
||||
{
|
||||
/* Crashes under Windows 7 */
|
||||
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_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);
|
||||
|
||||
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))
|
||||
|
|
Loading…
Reference in New Issue