Index: boot/bootdata/hivecls.inf =================================================================== --- boot/bootdata/hivecls.inf (revision 58725) +++ boot/bootdata/hivecls.inf (working copy) @@ -311,6 +311,13 @@ HKCR,"CLSID\{A65B8071-3BFE-4213-9A5B-491DA4461CA7}\ProgID","",0x00000000,"DxDiag.DxDiagProvider.1" HKCR,"CLSID\{A65B8071-3BFE-4213-9A5B-491DA4461CA7}\VersionIndependentProgID","",0x00000000,"DxDiag.DxDiagProvider" +; For explorerframe.dll +HKCR,"CLSID\{AE054212-3535-4430-83ED-D501AA6680E6}","",0x00000000,"Shell Name Space ListView" +HKCR,"CLSID\{AE054212-3535-4430-83ED-D501AA6680E6}\InProcServer32","",0x00000000,"explorerframe.dll" +HKCR,"CLSID\{AE054212-3535-4430-83ED-D501AA6680E6}\InProcServer32","ThreadingModel",0x00000000,"Both" +HKCR,"CLSID\{56FDF344-FD6D-11D0-958A-006097C9A090}","",0x00000000,"Task Bar Communication" +HKCR,"CLSID\{56FDF344-FD6D-11D0-958A-006097C9A090}\InProcServer32","",0x00000000,"explorerframe.dll" +HKCR,"CLSID\{56FDF344-FD6D-11D0-958A-006097C9A090}\InProcServer32","ThreadingModel",0x00000000,"Both" HKCR,"NDS\Clsid","",0x00000002,"{323991f0-7bad-11cf-b03d-00aa006e0975}" Index: dll/win32/CMakeLists.txt =================================================================== --- dll/win32/CMakeLists.txt (revision 58725) +++ dll/win32/CMakeLists.txt (working copy) @@ -37,6 +37,7 @@ add_subdirectory(dhcpcsvc) add_subdirectory(dnsapi) add_subdirectory(dwmapi) +add_subdirectory(explorerframe) add_subdirectory(faultrep) add_subdirectory(fmifs) add_subdirectory(fusion) Index: dll/win32/explorerframe =================================================================== --- dll/win32/explorerframe (revision 0) +++ dll/win32/explorerframe (working copy) Property changes on: dll/win32/explorerframe ___________________________________________________________________ Added: bugtraq:logregex ## -0,0 +1,2 ## +([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))? +(\d+) \ No newline at end of property Added: bugtraq:url ## -0,0 +1 ## +http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID% \ No newline at end of property Added: bugtraq:message ## -0,0 +1 ## +See issue #%BUGID% for more details. \ No newline at end of property Added: tsvn:logminsize ## -0,0 +1 ## +10 \ No newline at end of property Index: dll/win32/explorerframe/CMakeLists.txt =================================================================== --- dll/win32/explorerframe/CMakeLists.txt (revision 0) +++ dll/win32/explorerframe/CMakeLists.txt (working copy) @@ -0,0 +1,32 @@ +add_definitions(-D__WINESRC__) + +add_idl_headers(explorerframe_idlheader explorerframe_local.idl) + +include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine) + +spec2def(explorerframe.dll explorerframe.spec) + +list(APPEND SOURCE + explorerframe_main.c + nstc.c + taskbarlist.c + version.rc + ${CMAKE_CURRENT_BINARY_DIR}/explorerframe.def) + +add_library(explorerframe SHARED ${SOURCE}) +set_module_type(explorerframe win32dll UNICODE) +target_link_libraries(explorerframe uuid wine) + +add_importlibs(explorerframe + user32 + comctl32 + advapi32 + ole32 + shell32 + shlwapi + msvcrt + kernel32 + ntdll) + +add_cd_file(TARGET explorerframe DESTINATION reactos/system32 FOR all) +add_dependencies(explorerframe explorerframe_idlheader) Index: dll/win32/explorerframe/explorerframe.spec =================================================================== --- dll/win32/explorerframe/explorerframe.spec (revision 0) +++ dll/win32/explorerframe/explorerframe.spec (working copy) @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() Index: dll/win32/explorerframe/explorerframe_local.idl =================================================================== --- dll/win32/explorerframe/explorerframe_local.idl (revision 0) +++ dll/win32/explorerframe/explorerframe_local.idl (working copy) @@ -0,0 +1,37 @@ +/* + * COM Classes for explorerframe + * + * Copyright 2010 Alexandre Julliard + * + * 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 "shobjidl.idl" + +/* + [ + helpstring("Shell Name Space ListView"), + threading(apartment), + uuid(ae054212-3535-4430-83ed-d501aa6680e6) + ] + coclass NamespaceTreeControl { interface INameSpaceTreeControl2; } + + [ + helpstring("Task Bar Communication"), + threading(apartment), + uuid(56fdf344-fd6d-11d0-958a-006097c9a090) + ] + coclass TaskbarList { interface ITaskbarList; } + */ Index: dll/win32/explorerframe/explorerframe_main.c =================================================================== --- dll/win32/explorerframe/explorerframe_main.c (revision 0) +++ dll/win32/explorerframe/explorerframe_main.c (working copy) @@ -0,0 +1,227 @@ +/* + * ExplorerFrame main functions + * + * Copyright 2010 David Hedberg + * + * 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 NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "shlwapi.h" +#include "shobjidl.h" +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "explorerframe_main.h" + +WINE_DEFAULT_DEBUG_CHANNEL(explorerframe); + +HINSTANCE explorerframe_hinstance; +LONG EFRAME_refCount = 0; + +/************************************************************************* + * DllMain (ExplorerFrame.@) + */ +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p, 0x%x, %p\n", hinst, fdwReason, fImpLoad); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinst); + explorerframe_hinstance = hinst; + break; + } + return TRUE; +} + +/************************************************************************* + * DllCanUnloadNow (ExplorerFrame.@) + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + TRACE("refCount is %d\n", EFRAME_refCount); + return EFRAME_refCount ? S_FALSE : S_OK; +} + +/************************************************************************* + * DllGetVersion (ExplorerFrame.@) + */ +HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *info) +{ + TRACE("%p\n", info); + if(info->cbSize == sizeof(DLLVERSIONINFO) || + info->cbSize == sizeof(DLLVERSIONINFO2)) + { + /* Windows 7 */ + info->dwMajorVersion = 6; + info->dwMinorVersion = 1; + info->dwBuildNumber = 7600; + info->dwPlatformID = DLLVER_PLATFORM_WINDOWS; + if(info->cbSize == sizeof(DLLVERSIONINFO2)) + { + DLLVERSIONINFO2 *info2 = (DLLVERSIONINFO2*)info; + info2->dwFlags = 0; + info2->ullVersion = MAKEDLLVERULL(info->dwMajorVersion, + info->dwMinorVersion, + info->dwBuildNumber, + 16385); /* "hotfix number" */ + } + return S_OK; + } + + WARN("wrong DLLVERSIONINFO size from app.\n"); + return E_INVALIDARG; +} + +/************************************************************************* + * Implement the ExplorerFrame class factory + */ + +typedef struct +{ + IClassFactory IClassFactory_iface; + HRESULT (*cf)(IUnknown*, REFIID, void**); + LONG ref; +} IClassFactoryImpl; + +static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) +{ + return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); +} + +/************************************************************************* + * EFCF_QueryInterface + */ +static HRESULT WINAPI EFCF_QueryInterface(IClassFactory* iface, + REFIID riid, void **ppobj) +{ + TRACE("%p (%s %p)\n", iface, debugstr_guid(riid), ppobj); + + if(!ppobj) + return E_POINTER; + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) + { + *ppobj = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + + WARN("Interface not supported.\n"); + + *ppobj = NULL; + return E_NOINTERFACE; +} + +/************************************************************************* + * EFCF_AddRef + */ +static ULONG WINAPI EFCF_AddRef(IClassFactory *iface) +{ + EFRAME_LockModule(); + + return 2; /* non-heap based object */ +} + +/************************************************************************* + * EFCF_Release + */ +static ULONG WINAPI EFCF_Release(IClassFactory *iface) +{ + EFRAME_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/************************************************************************* + * EFCF_CreateInstance (IClassFactory) + */ +static HRESULT WINAPI EFCF_CreateInstance(IClassFactory *iface, IUnknown *pOuter, + REFIID riid, void **ppobj) +{ + IClassFactoryImpl *This = impl_from_IClassFactory(iface); + return This->cf(pOuter, riid, ppobj); +} + +/************************************************************************* + * EFCF_LockServer (IClassFactory) + */ +static HRESULT WINAPI EFCF_LockServer(IClassFactory *iface, BOOL dolock) +{ + TRACE("%p (%d)\n", iface, dolock); + + if (dolock) + EFRAME_LockModule(); + else + EFRAME_UnlockModule(); + + return S_OK; +} + +static const IClassFactoryVtbl EFCF_Vtbl = +{ + EFCF_QueryInterface, + EFCF_AddRef, + EFCF_Release, + EFCF_CreateInstance, + EFCF_LockServer +}; + +/************************************************************************* + * DllGetClassObject (ExplorerFrame.@) + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) +{ + static IClassFactoryImpl NSTCClassFactory = {{&EFCF_Vtbl}, NamespaceTreeControl_Constructor}; + static IClassFactoryImpl TaskbarListFactory = {{&EFCF_Vtbl}, TaskbarList_Constructor}; + + TRACE("%s, %s, %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if(IsEqualGUID(&CLSID_NamespaceTreeControl, rclsid)) + return IClassFactory_QueryInterface(&NSTCClassFactory.IClassFactory_iface, riid, ppv); + + if(IsEqualGUID(&CLSID_TaskbarList, rclsid)) + return IClassFactory_QueryInterface(&TaskbarListFactory.IClassFactory_iface, riid, ppv); + + return CLASS_E_CLASSNOTAVAILABLE; +} + +/************************************************************************* + * DllRegisterServer (ExplorerFrame.@) + */ +HRESULT WINAPI DllRegisterServer(void) +{ + return __wine_register_resources( explorerframe_hinstance ); +} + +/************************************************************************* + * DllUnregisterServer (ExplorerFrame.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + return __wine_unregister_resources( explorerframe_hinstance ); +} Index: dll/win32/explorerframe/explorerframe_main.h =================================================================== --- dll/win32/explorerframe/explorerframe_main.h (revision 0) +++ dll/win32/explorerframe/explorerframe_main.h (working copy) @@ -0,0 +1,50 @@ +/* + * ExplorerFrame main include + * + * Copyright 2010 David Hedberg + * + * 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 + */ + +#ifndef __WINE_EXPLORERFRAME_H +#define __WINE_EXPLORERFRAME_H + +#define COBJMACROS + +#include "shlobj.h" + +/* Not declared in commctrl.h ("for internal use (msdn)") */ +#define TVS_EX_NOSINGLECOLLAPSE 0x0001 + +extern HINSTANCE explorerframe_hinstance DECLSPEC_HIDDEN; + +extern LONG EFRAME_refCount DECLSPEC_HIDDEN; +static inline void EFRAME_LockModule(void) { InterlockedIncrement( &EFRAME_refCount ); } +static inline void EFRAME_UnlockModule(void) { InterlockedDecrement( &EFRAME_refCount ); } + +HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) DECLSPEC_HIDDEN; +HRESULT TaskbarList_Constructor(IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; + +static inline void *heap_alloc(size_t len) +{ + return HeapAlloc(GetProcessHeap(), 0, len); +} + +static inline BOOL heap_free(void *mem) +{ + return HeapFree(GetProcessHeap(), 0, mem); +} + +#endif /* __WINE_EXPLORERFRAME_H */ Index: dll/win32/explorerframe/nstc.c =================================================================== --- dll/win32/explorerframe/nstc.c (revision 0) +++ dll/win32/explorerframe/nstc.c (working copy) @@ -0,0 +1,1621 @@ +/* + * NamespaceTreeControl implementation. + * + * Copyright 2010 David Hedberg + * + * 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 + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#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 { + INameSpaceTreeControl2 INameSpaceTreeControl2_iface; + IOleWindow IOleWindow_iface; + LONG ref; + + HWND hwnd_main; + HWND hwnd_tv; + + WNDPROC tv_oldwndproc; + + NSTCSTYLE style; + NSTCSTYLE2 style2; + struct list roots; + + INameSpaceTreeControlEvents *pnstce; +} NSTC2Impl; + +static const DWORD unsupported_styles = + NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE | + NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | + NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS; +static const DWORD unsupported_styles2 = + NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING | + NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED; + +static inline NSTC2Impl *impl_from_INameSpaceTreeControl2(INameSpaceTreeControl2 *iface) +{ + return CONTAINING_RECORD(iface, NSTC2Impl, INameSpaceTreeControl2_iface); +} + +static inline NSTC2Impl *impl_from_IOleWindow(IOleWindow *iface) +{ + return CONTAINING_RECORD(iface, NSTC2Impl, IOleWindow_iface); +} + +/* Forward declarations */ +static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam); + +/************************************************************************* +* NamespaceTree event wrappers +*/ +static HRESULT events_OnGetDefaultIconIndex(NSTC2Impl *This, IShellItem *psi, + int *piDefaultIcon, int *piOpenIcon) +{ + HRESULT ret; + LONG refcount; + if(!This->pnstce) return E_NOTIMPL; + + refcount = IShellItem_AddRef(psi); + ret = INameSpaceTreeControlEvents_OnGetDefaultIconIndex(This->pnstce, psi, piDefaultIcon, piOpenIcon); + if(IShellItem_Release(psi) < refcount - 1) + ERR("ShellItem was released by client - please file a bug.\n"); + return ret; +} + +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; +} + +static HRESULT events_OnItemDeleted(NSTC2Impl *This, IShellItem *psi, BOOL fIsRoot) +{ + HRESULT ret; + LONG refcount; + if(!This->pnstce) return S_OK; + + refcount = IShellItem_AddRef(psi); + ret = INameSpaceTreeControlEvents_OnItemDeleted(This->pnstce, psi, fIsRoot); + if(IShellItem_Release(psi) < refcount - 1) + ERR("ShellItem was released by client - please file a bug.\n"); + return ret; +} + +static HRESULT events_OnBeforeExpand(NSTC2Impl *This, IShellItem *psi) +{ + HRESULT ret; + LONG refcount; + if(!This->pnstce) return S_OK; + + refcount = IShellItem_AddRef(psi); + ret = INameSpaceTreeControlEvents_OnBeforeExpand(This->pnstce, psi); + if(IShellItem_Release(psi) < refcount - 1) + ERR("ShellItem was released by client - please file a bug.\n"); + return ret; +} + +static HRESULT events_OnAfterExpand(NSTC2Impl *This, IShellItem *psi) +{ + HRESULT ret; + LONG refcount; + if(!This->pnstce) return S_OK; + + refcount = IShellItem_AddRef(psi); + ret = INameSpaceTreeControlEvents_OnAfterExpand(This->pnstce, psi); + if(IShellItem_Release(psi) < refcount - 1) + ERR("ShellItem was released by client - please file a bug.\n"); + return ret; +} + +static HRESULT events_OnItemClick(NSTC2Impl *This, IShellItem *psi, + NSTCEHITTEST nstceHitTest, NSTCECLICKTYPE nstceClickType) +{ + HRESULT ret; + LONG refcount; + if(!This->pnstce) return S_OK; + + refcount = IShellItem_AddRef(psi); + ret = INameSpaceTreeControlEvents_OnItemClick(This->pnstce, psi, nstceHitTest, nstceClickType); + if(IShellItem_Release(psi) < refcount - 1) + ERR("ShellItem was released by client - please file a bug.\n"); + return ret; +} + +static HRESULT events_OnSelectionChanged(NSTC2Impl *This, IShellItemArray *psia) +{ + if(!This->pnstce) return S_OK; + + return INameSpaceTreeControlEvents_OnSelectionChanged(This->pnstce, psia); +} + +static HRESULT events_OnKeyboardInput(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if(!This->pnstce) return S_OK; + + return INameSpaceTreeControlEvents_OnKeyboardInput(This->pnstce, uMsg, wParam, lParam); +} + +/************************************************************************* + * NamespaceTree helper functions + */ +static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs, + NSTCSTYLE nstcs_mask, DWORD *new_style) +{ + DWORD old_style, tv_mask = 0; + TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style); + + if(This->hwnd_tv) + old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE); + else + old_style = /* The default */ + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | + WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP | + TVS_EDITLABELS | TVS_TRACKSELECT; + + if(nstcs_mask & NSTCS_HASEXPANDOS) tv_mask |= TVS_HASBUTTONS; + if(nstcs_mask & NSTCS_HASLINES) tv_mask |= TVS_HASLINES; + if(nstcs_mask & NSTCS_FULLROWSELECT) tv_mask |= TVS_FULLROWSELECT; + if(nstcs_mask & NSTCS_HORIZONTALSCROLL) tv_mask |= TVS_NOHSCROLL; + if(nstcs_mask & NSTCS_ROOTHASEXPANDO) tv_mask |= TVS_LINESATROOT; + if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS; + if(nstcs_mask & NSTCS_NOINFOTIP) tv_mask |= TVS_INFOTIP; + if(nstcs_mask & NSTCS_EVENHEIGHT) tv_mask |= TVS_NONEVENHEIGHT; + if(nstcs_mask & NSTCS_DISABLEDRAGDROP) tv_mask |= TVS_DISABLEDRAGDROP; + if(nstcs_mask & NSTCS_NOEDITLABELS) tv_mask |= TVS_EDITLABELS; + if(nstcs_mask & NSTCS_CHECKBOXES) tv_mask |= TVS_CHECKBOXES; + + *new_style = 0; + + if(nstcs & NSTCS_HASEXPANDOS) *new_style |= TVS_HASBUTTONS; + if(nstcs & NSTCS_HASLINES) *new_style |= TVS_HASLINES; + if(nstcs & NSTCS_FULLROWSELECT) *new_style |= TVS_FULLROWSELECT; + if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL; + if(nstcs & NSTCS_ROOTHASEXPANDO) *new_style |= TVS_LINESATROOT; + if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS; + if(!(nstcs & NSTCS_NOINFOTIP)) *new_style |= TVS_INFOTIP; + if(!(nstcs & NSTCS_EVENHEIGHT)) *new_style |= TVS_NONEVENHEIGHT; + if(nstcs & NSTCS_DISABLEDRAGDROP) *new_style |= TVS_DISABLEDRAGDROP; + if(!(nstcs & NSTCS_NOEDITLABELS)) *new_style |= TVS_EDITLABELS; + if(nstcs & NSTCS_CHECKBOXES) *new_style |= TVS_CHECKBOXES; + + *new_style = (old_style & ~tv_mask) | (*new_style & tv_mask); + + TRACE("old: %08x, new: %08x\n", old_style, *new_style); + + return old_style^*new_style; +} + +static IShellItem *shellitem_from_treeitem(NSTC2Impl *This, HTREEITEM hitem) +{ + TVITEMEXW tvi; + + tvi.mask = TVIF_PARAM; + tvi.lParam = 0; + tvi.hItem = hitem; + + SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi); + + TRACE("ShellItem: %p\n", (void*)tvi.lParam); + return (IShellItem*)tvi.lParam; +} + +/* Returns the root that the given treeitem belongs to. */ +static nstc_root *root_for_treeitem(NSTC2Impl *This, HTREEITEM hitem) +{ + HTREEITEM tmp, hroot = hitem; + nstc_root *root; + + /* Work our way up the hierarchy */ + for(tmp = hitem; tmp != NULL; hroot = tmp?tmp:hroot) + tmp = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hroot); + + /* Search through the list of roots for a match */ + LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry) + if(root->htreeitem == hroot) + break; + + TRACE("root is %p\n", root); + return root; +} + +/* Find a shellitem in the tree, starting from the given node. */ +static HTREEITEM search_for_shellitem(NSTC2Impl *This, HTREEITEM node, + IShellItem *psi) +{ + IShellItem *psi_node; + HTREEITEM next, result = NULL; + HRESULT hr; + int cmpo; + TRACE("%p, %p, %p\n", This, node, psi); + + /* Check this node */ + psi_node = shellitem_from_treeitem(This, node); + hr = IShellItem_Compare(psi, psi_node, SICHINT_DISPLAY, &cmpo); + if(hr == S_OK) + return node; + + /* Any children? */ + next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, + TVGN_CHILD, (LPARAM)node); + if(next) + { + result = search_for_shellitem(This, next, psi); + if(result) return result; + } + + /* Try our next sibling. */ + next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, + TVGN_NEXT, (LPARAM)node); + if(next) + result = search_for_shellitem(This, next, psi); + + return result; +} + +static HTREEITEM treeitem_from_shellitem(NSTC2Impl *This, IShellItem *psi) +{ + HTREEITEM root; + TRACE("%p, %p\n", This, psi); + + root = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, + TVGN_ROOT, 0); + if(!root) + return NULL; + + return search_for_shellitem(This, root, psi); +} + +static int get_icon(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; +} + +/* 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; +} + +/* Enumerates the children of the folder represented by hitem + * according to the settings for the root, and adds them to the + * treeview. Returns the number of children added. */ +static UINT fill_sublevel(NSTC2Impl *This, HTREEITEM hitem) +{ + IShellItem *psiParent = shellitem_from_treeitem(This, hitem); + nstc_root *root = root_for_treeitem(This, hitem); + LPITEMIDLIST pidl_parent; + IShellFolder *psf; + IEnumIDList *peidl; + UINT added = 0; + HRESULT hr; + + hr = SHGetIDListFromObject((IUnknown*)psiParent, &pidl_parent); + if(SUCCEEDED(hr)) + { + hr = IShellItem_BindToHandler(psiParent, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&psf); + if(SUCCEEDED(hr)) + { + hr = IShellFolder_EnumObjects(psf, NULL, root->enum_flags, &peidl); + if(SUCCEEDED(hr)) + { + LPITEMIDLIST pidl; + IShellItem *psi; + ULONG fetched; + + while( S_OK == IEnumIDList_Next(peidl, 1, &pidl, &fetched) ) + { + hr = SHCreateShellItem(NULL, psf , pidl, &psi); + ILFree(pidl); + if(SUCCEEDED(hr)) + { + if(insert_shellitem(This, psi, hitem, NULL)) + { + events_OnItemAdded(This, psi, FALSE); + added++; + } + + IShellItem_Release(psi); + } + else + ERR("SHCreateShellItem failed with 0x%08x\n", hr); + } + IEnumIDList_Release(peidl); + } + else + ERR("EnumObjects failed with 0x%08x\n", hr); + + IShellFolder_Release(psf); + } + else + ERR("BindToHandler failed with 0x%08x\n", hr); + + ILFree(pidl_parent); + } + else + ERR("SHGetIDListFromObject failed with 0x%08x\n", hr); + + return added; +} + +static HTREEITEM get_selected_treeitem(NSTC2Impl *This) +{ + return (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CARET, 0); +} + +static IShellItem *get_selected_shellitem(NSTC2Impl *This) +{ + return shellitem_from_treeitem(This, get_selected_treeitem(This)); +} + +static void collapse_all(NSTC2Impl *This, HTREEITEM node) +{ + HTREEITEM next; + + /* Collapse this node first, and then first child/next sibling. */ + SendMessageW(This->hwnd_tv, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)node); + + next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node); + if(next) collapse_all(This, next); + + next = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)node); + if(next) collapse_all(This, next); +} + +static HTREEITEM treeitem_from_point(NSTC2Impl *This, const POINT *pt, UINT *hitflag) +{ + TVHITTESTINFO tviht; + tviht.pt.x = pt->x; + tviht.pt.y = pt->y; + tviht.hItem = NULL; + + SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tviht); + if(hitflag) *hitflag = tviht.flags; + return tviht.hItem; +} + +/************************************************************************* + * NamespaceTree window functions + */ +static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs) +{ + NSTC2Impl *This = crs->lpCreateParams; + HIMAGELIST ShellSmallIconList; + DWORD treeview_style, treeview_ex_style; + WCHAR szWinDir[MAX_PATH]; + SHFILEINFOW shfi; + + TRACE("%p (%p)\n", This, crs); + SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This); + This->hwnd_main = hWnd; + + treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style); + + This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style, + 0, 0, crs->cx, crs->cy, + hWnd, NULL, explorerframe_hinstance, NULL); + + if(!This->hwnd_tv) + { + ERR("Failed to create treeview!\n"); + return HRESULT_FROM_WIN32(GetLastError()); + } + + treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP | + TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE; + + if(This->style & NSTCS_AUTOHSCROLL) + treeview_ex_style |= TVS_EX_AUTOHSCROLL; + if(This->style & NSTCS_FADEINOUTEXPANDOS) + treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS; + if(This->style & NSTCS_PARTIALCHECKBOXES) + treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES; + if(This->style & NSTCS_EXCLUSIONCHECKBOXES) + treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES; + if(This->style & NSTCS_DIMMEDCHECKBOXES) + treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES; + + SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff); + +#if 0 + if(Shell_GetImageLists(NULL, &ShellSmallIconList)) + { + SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST, + (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList); + } + else + { + ERR("Failed to get the System Image List.\n"); + } +#else + GetWindowsDirectoryW(szWinDir, MAX_PATH); + ShellSmallIconList = + (HIMAGELIST)SHGetFileInfoW(szWinDir, 0, &shfi, sizeof(shfi), + SHGFI_SYSICONINDEX | SHGFI_SMALLICON); + if (ShellSmallIconList == NULL) + { + ERR("Failed to get the System Image List.\n"); + } +#endif + + INameSpaceTreeControl2_AddRef(&This->INameSpaceTreeControl2_iface); + + /* Subclass the treeview to get the keybord events. */ + This->tv_oldwndproc = (WNDPROC)SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, + (ULONG_PTR)tv_wndproc); + if(This->tv_oldwndproc) + SetPropA(This->hwnd_tv, "PROP_THIS", This); + + return TRUE; +} + +static LRESULT resize_namespacetree(NSTC2Impl *This) +{ + RECT rc; + TRACE("%p\n", This); + + GetClientRect(This->hwnd_main, &rc); + MoveWindow(This->hwnd_tv, 0, 0, rc.right-rc.left, rc.bottom-rc.top, TRUE); + + return TRUE; +} + +static LRESULT destroy_namespacetree(NSTC2Impl *This) +{ + TRACE("%p\n", This); + + /* Undo the subclassing */ + if(This->tv_oldwndproc) + { + SetWindowLongPtrW(This->hwnd_tv, GWLP_WNDPROC, (ULONG_PTR)This->tv_oldwndproc); + RemovePropA(This->hwnd_tv, "PROP_THIS"); + } + + INameSpaceTreeControl2_RemoveAllRoots(&This->INameSpaceTreeControl2_iface); + + /* This reference was added in create_namespacetree */ + INameSpaceTreeControl2_Release(&This->INameSpaceTreeControl2_iface); + return TRUE; +} + +static LRESULT on_tvn_deleteitemw(NSTC2Impl *This, LPARAM lParam) +{ + NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam; + TRACE("%p\n", This); + + IShellItem_Release((IShellItem*)nmtv->itemOld.lParam); + return TRUE; +} + +static LRESULT on_tvn_getdispinfow(NSTC2Impl *This, LPARAM lParam) +{ + NMTVDISPINFOW *dispinfo = (NMTVDISPINFOW*)lParam; + TVITEMEXW *item = (TVITEMEXW*)&dispinfo->item; + IShellItem *psi = shellitem_from_treeitem(This, item->hItem); + HRESULT hr; + + TRACE("%p, %p (mask: %x)\n", This, dispinfo, item->mask); + + if(item->mask & TVIF_CHILDREN) + { + SFGAOF sfgao; + + hr = IShellItem_GetAttributes(psi, SFGAO_HASSUBFOLDER, &sfgao); + if(SUCCEEDED(hr)) + item->cChildren = (sfgao & SFGAO_HASSUBFOLDER)?1:0; + else + item->cChildren = 1; + + item->mask |= TVIF_DI_SETITEM; + } + + if(item->mask & (TVIF_IMAGE|TVIF_SELECTEDIMAGE)) + { + LPITEMIDLIST pidl; + + hr = events_OnGetDefaultIconIndex(This, psi, &item->iImage, &item->iSelectedImage); + if(FAILED(hr)) + { + hr = SHGetIDListFromObject((IUnknown*)psi, &pidl); + if(SUCCEEDED(hr)) + { + item->iImage = item->iSelectedImage = get_icon(pidl, 0); + item->mask |= TVIF_DI_SETITEM; + ILFree(pidl); + } + else + ERR("Failed to get IDList (%08x).\n", hr); + } + } + + if(item->mask & TVIF_TEXT) + { + LPWSTR display_name; + + hr = IShellItem_GetDisplayName(psi, SIGDN_NORMALDISPLAY, &display_name); + if(SUCCEEDED(hr)) + { + lstrcpynW(item->pszText, display_name, MAX_PATH); + item->mask |= TVIF_DI_SETITEM; + CoTaskMemFree(display_name); + } + else + ERR("Failed to get display name (%08x).\n", hr); + } + + return TRUE; +} + +static BOOL treenode_has_subfolders(NSTC2Impl *This, HTREEITEM node) +{ + return SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)node); +} + +static LRESULT on_tvn_itemexpandingw(NSTC2Impl *This, LPARAM lParam) +{ + NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam; + IShellItem *psi; + TRACE("%p\n", This); + + psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem); + events_OnBeforeExpand(This, psi); + + if(!treenode_has_subfolders(This, nmtv->itemNew.hItem)) + { + /* The node has no children, try to find some */ + if(!fill_sublevel(This, nmtv->itemNew.hItem)) + { + TVITEMEXW tvi; + /* Failed to enumerate any children, remove the expando + * (if any). */ + tvi.hItem = nmtv->itemNew.hItem; + tvi.mask = TVIF_CHILDREN; + tvi.cChildren = 0; + SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi); + + return TRUE; + } + } + return FALSE; +} + +static LRESULT on_tvn_itemexpandedw(NSTC2Impl *This, LPARAM lParam) +{ + NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam; + IShellItem *psi; + TRACE("%p\n", This); + + psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem); + events_OnAfterExpand(This, psi); + return TRUE; +} + +static LRESULT on_tvn_selchangedw(NSTC2Impl *This, LPARAM lParam) +{ + NMTREEVIEWW *nmtv = (NMTREEVIEWW*)lParam; + IShellItemArray *psia; + IShellItem *psi; + HRESULT hr; + TRACE("%p\n", This); + + /* Note: Only supports one selected item. */ + psi = shellitem_from_treeitem(This, nmtv->itemNew.hItem); + hr = SHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia); + if(SUCCEEDED(hr)) + { + events_OnSelectionChanged(This, psia); + IShellItemArray_Release(psia); + } + + return TRUE; +} + +static LRESULT on_nm_click(NSTC2Impl *This, NMHDR *nmhdr) +{ + TVHITTESTINFO tvhit; + IShellItem *psi; + HRESULT hr; + TRACE("%p (%p)\n", This, nmhdr); + + GetCursorPos(&tvhit.pt); + ScreenToClient(This->hwnd_tv, &tvhit.pt); + SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit); + + if(tvhit.flags & (TVHT_NOWHERE|TVHT_ABOVE|TVHT_BELOW)) + return TRUE; + + /* TVHT_ maps onto the corresponding NSTCEHT_ */ + psi = shellitem_from_treeitem(This, tvhit.hItem); + hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_LBUTTON); + + /* The expando should not be expanded unless + * double-clicked. */ + if(tvhit.flags == TVHT_ONITEMBUTTON) + return TRUE; + + if(SUCCEEDED(hr)) + return FALSE; + else + return TRUE; +} + +static LRESULT on_wm_mbuttonup(NSTC2Impl *This, WPARAM wParam, LPARAM lParam) +{ + TVHITTESTINFO tvhit; + IShellItem *psi; + HRESULT hr; + TRACE("%p (%lx, %lx)\n", This, wParam, lParam); + + tvhit.pt.x = (int)(short)LOWORD(lParam); + tvhit.pt.y = (int)(short)HIWORD(lParam); + + SendMessageW(This->hwnd_tv, TVM_HITTEST, 0, (LPARAM)&tvhit); + + /* Seems to generate only ONITEM and ONITEMICON */ + if( !(tvhit.flags & (TVHT_ONITEM|TVHT_ONITEMICON)) ) + return FALSE; + + psi = shellitem_from_treeitem(This, tvhit.hItem); + hr = events_OnItemClick(This, psi, tvhit.flags, NSTCECT_MBUTTON); + + if(SUCCEEDED(hr)) + return FALSE; + else + return TRUE; +} + +static LRESULT on_kbd_event(NSTC2Impl *This, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + IShellItem *psi; + HTREEITEM hitem; + TRACE("%p : %d, %lx, %lx\n", This, uMsg, wParam, lParam); + + /* Handled by the client? */ + if(FAILED(events_OnKeyboardInput(This, uMsg, wParam, lParam))) + return TRUE; + + if(uMsg == WM_KEYDOWN) + { + switch(wParam) + { + case VK_DELETE: + psi = get_selected_shellitem(This); + FIXME("Deletion of file requested (shellitem: %p).\n", psi); + return TRUE; + + case VK_F2: + hitem = get_selected_treeitem(This); + SendMessageW(This->hwnd_tv, TVM_EDITLABELW, 0, (LPARAM)hitem); + return TRUE; + } + } + + /* Let the TreeView handle the key */ + return FALSE; +} + +static LRESULT CALLBACK tv_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) +{ + NSTC2Impl *This = (NSTC2Impl*)GetPropA(hWnd, "PROP_THIS"); + + switch(uMessage) { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_SYSCHAR: + if(on_kbd_event(This, uMessage, wParam, lParam)) + return TRUE; + break; + + case WM_MBUTTONUP: return on_wm_mbuttonup(This, wParam, lParam); + } + + /* Pass the message on to the treeview */ + return CallWindowProcW(This->tv_oldwndproc, hWnd, uMessage, wParam, lParam); +} + +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 NM_CLICK: return on_nm_click(This, nmhdr); + case TVN_DELETEITEMW: return on_tvn_deleteitemw(This, lParam); + case TVN_GETDISPINFOW: return on_tvn_getdispinfow(This, lParam); + case TVN_ITEMEXPANDINGW: return on_tvn_itemexpandingw(This, lParam); + case TVN_ITEMEXPANDEDW: return on_tvn_itemexpandedw(This, lParam); + case TVN_SELCHANGEDW: return on_tvn_selchangedw(This, lParam); + default: break; + } + break; + default: return DefWindowProcW(hWnd, uMessage, wParam, lParam); + } + return 0; +} + +/************************************************************************** + * INameSpaceTreeControl2 Implementation + */ +static HRESULT WINAPI NSTC2_fnQueryInterface(INameSpaceTreeControl2* iface, + REFIID riid, + void **ppvObject) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TRACE("%p (%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + *ppvObject = NULL; + if(IsEqualIID(riid, &IID_INameSpaceTreeControl2) || + IsEqualIID(riid, &IID_INameSpaceTreeControl) || + IsEqualIID(riid, &IID_IUnknown)) + { + *ppvObject = This; + } + else if(IsEqualIID(riid, &IID_IOleWindow)) + { + *ppvObject = &This->IOleWindow_iface; + } + + if(*ppvObject) + { + IUnknown_AddRef((IUnknown*)*ppvObject); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI NSTC2_fnAddRef(INameSpaceTreeControl2* iface) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("%p - ref %d\n", This, ref); + + return ref; +} + +static ULONG WINAPI NSTC2_fnRelease(INameSpaceTreeControl2* iface) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("%p - ref: %d\n", This, ref); + + if(!ref) + { + TRACE("Freeing.\n"); + HeapFree(GetProcessHeap(), 0, This); + EFRAME_UnlockModule(); + return 0; + } + + return ref; +} + +static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface, + HWND hwndParent, + RECT *prc, + NSTCSTYLE nstcsFlags) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + WNDCLASSW wc; + DWORD window_style, window_ex_style; + RECT rc; + static const WCHAR NSTC2_CLASS_NAME[] = + {'N','a','m','e','s','p','a','c','e','T','r','e','e', + 'C','o','n','t','r','o','l',0}; + + TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags); + + if(nstcsFlags & unsupported_styles) + FIXME("0x%08x contains the unsupported style(s) 0x%08x\n", + nstcsFlags, nstcsFlags & unsupported_styles); + + This->style = nstcsFlags; + + if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc)) + { + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = NSTC2_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = explorerframe_hinstance; + wc.hIcon = 0; + wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = NSTC2_CLASS_NAME; + + if (!RegisterClassW(&wc)) return E_FAIL; + } + + /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */ + window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | + (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0); + window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0; + + if(prc) + CopyRect(&rc, prc); + else + rc.left = rc.right = rc.top = rc.bottom = 0; + + This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL, window_style, + rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + hwndParent, 0, explorerframe_hinstance, This); + + if(!This->hwnd_main) + { + ERR("Failed to create the window.\n"); + return HRESULT_FROM_WIN32(GetLastError()); + } + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface, + IUnknown *punk, + DWORD *pdwCookie) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HRESULT hr; + TRACE("%p (%p, %p)\n", This, punk, pdwCookie); + + *pdwCookie = 0; + + /* Only one client supported */ + if(This->pnstce) + return E_FAIL; + + hr = IUnknown_QueryInterface(punk, &IID_INameSpaceTreeControlEvents,(void**)&This->pnstce); + if(SUCCEEDED(hr)) + { + *pdwCookie = 1; + return hr; + } + + return E_FAIL; +} + +static HRESULT WINAPI NSTC2_fnTreeUnadvise(INameSpaceTreeControl2* iface, + DWORD dwCookie) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TRACE("%p (%x)\n", This, dwCookie); + + /* The cookie is ignored. */ + + if(This->pnstce) + { + INameSpaceTreeControlEvents_Release(This->pnstce); + This->pnstce = NULL; + } + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnInsertRoot(INameSpaceTreeControl2* iface, + int iIndex, + IShellItem *psiRoot, + SHCONTF grfEnumFlags, + NSTCROOTSTYLE grfRootStyle, + IShellItemFilter *pif) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + nstc_root *new_root; + struct list *add_after_entry; + HTREEITEM add_after_hitem; + int 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, + IShellItem *psiRoot, + SHCONTF grfEnumFlags, + NSTCROOTSTYLE grfRootStyle, + IShellItemFilter *pif) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + UINT root_count; + TRACE("%p, %p, %x, %x, %p\n", + This, psiRoot, grfEnumFlags, grfRootStyle, pif); + + 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 = impl_from_INameSpaceTreeControl2(iface); + 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; + hr = IShellItem_Compare(psiRoot, cursor->psi, SICHINT_DISPLAY, &order); + if(hr == S_OK) + { + root = cursor; + break; + } + } + + TRACE("root %p\n", root); + if(root) + { + events_OnItemDeleted(This, root->psi, TRUE); + SendMessageW(This->hwnd_tv, TVM_DELETEITEM, 0, (LPARAM)root->htreeitem); + list_remove(&root->entry); + HeapFree(GetProcessHeap(), 0, root); + return S_OK; + } + else + { + WARN("No matching root found.\n"); + return E_FAIL; + } +} + +static HRESULT WINAPI NSTC2_fnRemoveAllRoots(INameSpaceTreeControl2* iface) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + 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 = impl_from_INameSpaceTreeControl2(iface); + IShellFolder *psf; + LPITEMIDLIST *array; + nstc_root *root; + UINT count, i; + HRESULT hr; + 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); + hr = 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 hr; +} + +static HRESULT WINAPI NSTC2_fnSetItemState(INameSpaceTreeControl2* iface, + IShellItem *psi, + NSTCITEMSTATE nstcisMask, + NSTCITEMSTATE nstcisFlags) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TVITEMEXW tvi; + HTREEITEM hitem; + + TRACE("%p (%p, %x, %x)\n", This, psi, nstcisMask, nstcisFlags); + + hitem = treeitem_from_shellitem(This, psi); + if(!hitem) return E_INVALIDARG; + + /* Passing both NSTCIS_SELECTED and NSTCIS_SELECTEDNOEXPAND results + in two TVM_SETITEMW's */ + if((nstcisMask&nstcisFlags) & NSTCIS_SELECTED) + { + SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hitem); + SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (LPARAM)hitem); + } + if((nstcisMask&nstcisFlags) & NSTCIS_SELECTEDNOEXPAND) + { + SendMessageW(This->hwnd_tv, TVM_SELECTITEM, TVGN_CARET|TVSI_NOSINGLEEXPAND, (LPARAM)hitem); + } + + /* If NSTCIS_EXPANDED is among the flags, the mask is ignored. */ + if((nstcisMask|nstcisFlags) & NSTCIS_EXPANDED) + { + WPARAM arg = nstcisFlags&NSTCIS_EXPANDED ? TVE_EXPAND:TVE_COLLAPSE; + SendMessageW(This->hwnd_tv, TVM_EXPAND, arg, (LPARAM)hitem); + } + + if(nstcisMask & NSTCIS_DISABLED) + tvi.mask = TVIF_STATE | TVIF_STATEEX; + else if( ((nstcisMask^nstcisFlags) & (NSTCIS_SELECTED|NSTCIS_EXPANDED|NSTCIS_SELECTEDNOEXPAND)) || + ((nstcisMask|nstcisFlags) & NSTCIS_BOLD) || + (nstcisFlags & NSTCIS_DISABLED) ) + tvi.mask = TVIF_STATE; + else + tvi.mask = 0; + + if(tvi.mask) + { + tvi.stateMask = tvi.state = 0; + tvi.stateMask |= ((nstcisFlags^nstcisMask)&NSTCIS_SELECTED) ? TVIS_SELECTED : 0; + tvi.stateMask |= (nstcisMask|nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0; + tvi.state |= (nstcisMask&nstcisFlags)&NSTCIS_BOLD ? TVIS_BOLD:0; + + if((nstcisMask&NSTCIS_EXPANDED)^(nstcisFlags&NSTCIS_EXPANDED)) + { + tvi.stateMask = 0; + } + + tvi.uStateEx = (nstcisFlags&nstcisMask)&NSTCIS_DISABLED?TVIS_EX_DISABLED:0; + tvi.hItem = hitem; + + SendMessageW(This->hwnd_tv, TVM_SETITEMW, 0, (LPARAM)&tvi); + } + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnGetItemState(INameSpaceTreeControl2* iface, + IShellItem *psi, + NSTCITEMSTATE nstcisMask, + NSTCITEMSTATE *pnstcisFlags) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HTREEITEM hitem; + TVITEMEXW tvi; + TRACE("%p (%p, %x, %p)\n", This, psi, nstcisMask, pnstcisFlags); + + hitem = treeitem_from_shellitem(This, psi); + if(!hitem) + return E_INVALIDARG; + + *pnstcisFlags = 0; + + tvi.hItem = hitem; + tvi.mask = TVIF_STATE; + tvi.stateMask = TVIS_SELECTED|TVIS_EXPANDED|TVIS_BOLD; + + if(nstcisMask & NSTCIS_DISABLED) + tvi.mask |= TVIF_STATEEX; + + SendMessageW(This->hwnd_tv, TVM_GETITEMW, 0, (LPARAM)&tvi); + *pnstcisFlags |= (tvi.state & TVIS_SELECTED)?NSTCIS_SELECTED:0; + *pnstcisFlags |= (tvi.state & TVIS_EXPANDED)?NSTCIS_EXPANDED:0; + *pnstcisFlags |= (tvi.state & TVIS_BOLD)?NSTCIS_BOLD:0; + *pnstcisFlags |= (tvi.uStateEx & TVIS_EX_DISABLED)?NSTCIS_DISABLED:0; + + *pnstcisFlags &= nstcisMask; + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnGetSelectedItems(INameSpaceTreeControl2* iface, + IShellItemArray **psiaItems) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + IShellItem *psiselected; + HRESULT hr; + TRACE("%p (%p)\n", This, psiaItems); + + psiselected = get_selected_shellitem(This); + if(!psiselected) + { + *psiaItems = NULL; + return E_FAIL; + } + + hr = SHCreateShellItemArrayFromShellItem(psiselected, &IID_IShellItemArray, + (void**)psiaItems); + return hr; +} + +static HRESULT WINAPI NSTC2_fnGetItemCustomState(INameSpaceTreeControl2* iface, + IShellItem *psi, + int *piStateNumber) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + FIXME("stub, %p (%p, %p)\n", This, psi, piStateNumber); + return E_NOTIMPL; +} + +static HRESULT WINAPI NSTC2_fnSetItemCustomState(INameSpaceTreeControl2* iface, + IShellItem *psi, + int iStateNumber) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + FIXME("stub, %p (%p, %d)\n", This, psi, iStateNumber); + return E_NOTIMPL; +} + +static HRESULT WINAPI NSTC2_fnEnsureItemVisible(INameSpaceTreeControl2* iface, + IShellItem *psi) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HTREEITEM hitem; + + TRACE("%p (%p)\n", This, psi); + + hitem = treeitem_from_shellitem(This, psi); + if(hitem) + { + SendMessageW(This->hwnd_tv, TVM_ENSUREVISIBLE, 0, (WPARAM)hitem); + return S_OK; + } + + return E_INVALIDARG; +} + +static HRESULT WINAPI NSTC2_fnSetTheme(INameSpaceTreeControl2* iface, + LPCWSTR pszTheme) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + FIXME("stub, %p (%p)\n", This, pszTheme); + return E_NOTIMPL; +} + +static HRESULT WINAPI NSTC2_fnGetNextItem(INameSpaceTreeControl2* iface, + IShellItem *psi, + NSTCGNI nstcgi, + IShellItem **ppsiNext) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HTREEITEM hitem, hnext; + UINT tvgn; + TRACE("%p (%p, %x, %p)\n", This, psi, nstcgi, ppsiNext); + + if(!ppsiNext) return E_POINTER; + if(!psi) return E_FAIL; + + *ppsiNext = NULL; + + hitem = treeitem_from_shellitem(This, psi); + if(!hitem) + return E_INVALIDARG; + + switch(nstcgi) + { + case NSTCGNI_NEXT: tvgn = TVGN_NEXT; break; + case NSTCGNI_NEXTVISIBLE: tvgn = TVGN_NEXTVISIBLE; break; + case NSTCGNI_PREV: tvgn = TVGN_PREVIOUS; break; + case NSTCGNI_PREVVISIBLE: tvgn = TVGN_PREVIOUSVISIBLE; break; + case NSTCGNI_PARENT: tvgn = TVGN_PARENT; break; + case NSTCGNI_CHILD: tvgn = TVGN_CHILD; break; + case NSTCGNI_FIRSTVISIBLE: tvgn = TVGN_FIRSTVISIBLE; break; + case NSTCGNI_LASTVISIBLE: tvgn = TVGN_LASTVISIBLE; break; + default: + FIXME("Unknown nstcgi value %d\n", nstcgi); + return E_FAIL; + } + + hnext = (HTREEITEM)SendMessageW(This->hwnd_tv, TVM_GETNEXTITEM, tvgn, (WPARAM)hitem); + if(hnext) + { + *ppsiNext = shellitem_from_treeitem(This, hnext); + IShellItem_AddRef(*ppsiNext); + return S_OK; + } + + return E_FAIL; +} + +static HRESULT WINAPI NSTC2_fnHitTest(INameSpaceTreeControl2* iface, + POINT *ppt, + IShellItem **ppsiOut) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HTREEITEM hitem; + TRACE("%p (%p, %p)\n", This, ppsiOut, ppt); + + if(!ppt || !ppsiOut) + return E_POINTER; + + *ppsiOut = NULL; + + hitem = treeitem_from_point(This, ppt, NULL); + if(hitem) + *ppsiOut = shellitem_from_treeitem(This, hitem); + + if(*ppsiOut) + { + IShellItem_AddRef(*ppsiOut); + return S_OK; + } + + return S_FALSE; +} + +static HRESULT WINAPI NSTC2_fnGetItemRect(INameSpaceTreeControl2* iface, + IShellItem *psi, + RECT *prect) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + HTREEITEM hitem; + TRACE("%p (%p, %p)\n", This, psi, prect); + + if(!psi || !prect) + return E_POINTER; + + hitem = treeitem_from_shellitem(This, psi); + if(hitem) + { + *(HTREEITEM*)prect = hitem; + if(SendMessageW(This->hwnd_tv, TVM_GETITEMRECT, FALSE, (LPARAM)prect)) + { + MapWindowPoints(This->hwnd_tv, HWND_DESKTOP, (POINT*)prect, 2); + return S_OK; + } + } + + return E_INVALIDARG; +} + +static HRESULT WINAPI NSTC2_fnCollapseAll(INameSpaceTreeControl2* iface) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + nstc_root *root; + TRACE("%p\n", This); + + LIST_FOR_EACH_ENTRY(root, &This->roots, nstc_root, entry) + collapse_all(This, root->htreeitem); + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface, + NSTCSTYLE nstcsMask, + NSTCSTYLE nstcsStyle) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + static const DWORD tv_style_flags = + NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT | + NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO | + NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT | + NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES; + static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER; + static const DWORD nstc_flags = + NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | + NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | + NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON; + TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle); + + /* Fail if there is an attempt to set an unknown style. */ + if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags)) + return E_FAIL; + + if(nstcsMask & tv_style_flags) + { + DWORD new_style; + treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style); + SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style); + } + + /* Flags affecting the host window */ + if(nstcsMask & NSTCS_BORDER) + { + DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE); + new_style &= ~WS_BORDER; + new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0; + SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style); + } + if(nstcsMask & NSTCS_TABSTOP) + { + DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE); + new_style &= ~WS_EX_CONTROLPARENT; + new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0; + SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style); + } + + if((nstcsStyle & nstcsMask) & unsupported_styles) + FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n", + (nstcsStyle & nstcsMask), + (nstcsStyle & nstcsMask) & unsupported_styles); + + This->style &= ~nstcsMask; + This->style |= (nstcsStyle & nstcsMask); + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface, + NSTCSTYLE nstcsMask, + NSTCSTYLE *pnstcsStyle) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle); + + *pnstcsStyle = (This->style & nstcsMask); + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface, + NSTCSTYLE2 nstcsMask, + NSTCSTYLE2 nstcsStyle) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle); + + if((nstcsStyle & nstcsMask) & unsupported_styles2) + FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n", + (nstcsStyle & nstcsMask), + (nstcsStyle & nstcsMask) & unsupported_styles2); + + This->style2 &= ~nstcsMask; + This->style2 |= (nstcsStyle & nstcsMask); + + return S_OK; +} + +static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface, + NSTCSTYLE2 nstcsMask, + NSTCSTYLE2 *pnstcsStyle) +{ + NSTC2Impl *This = impl_from_INameSpaceTreeControl2(iface); + TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle); + + *pnstcsStyle = (This->style2 & nstcsMask); + + return S_OK; +} + +static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = { + NSTC2_fnQueryInterface, + NSTC2_fnAddRef, + NSTC2_fnRelease, + NSTC2_fnInitialize, + NSTC2_fnTreeAdvise, + NSTC2_fnTreeUnadvise, + NSTC2_fnAppendRoot, + NSTC2_fnInsertRoot, + NSTC2_fnRemoveRoot, + NSTC2_fnRemoveAllRoots, + NSTC2_fnGetRootItems, + NSTC2_fnSetItemState, + NSTC2_fnGetItemState, + NSTC2_fnGetSelectedItems, + NSTC2_fnGetItemCustomState, + NSTC2_fnSetItemCustomState, + NSTC2_fnEnsureItemVisible, + NSTC2_fnSetTheme, + NSTC2_fnGetNextItem, + NSTC2_fnHitTest, + NSTC2_fnGetItemRect, + NSTC2_fnCollapseAll, + NSTC2_fnSetControlStyle, + NSTC2_fnGetControlStyle, + NSTC2_fnSetControlStyle2, + NSTC2_fnGetControlStyle2 +}; + +/************************************************************************** + * IOleWindow Implementation + */ + +static HRESULT WINAPI IOW_fnQueryInterface(IOleWindow *iface, REFIID riid, void **ppvObject) +{ + NSTC2Impl *This = impl_from_IOleWindow(iface); + TRACE("%p\n", This); + return NSTC2_fnQueryInterface(&This->INameSpaceTreeControl2_iface, riid, ppvObject); +} + +static ULONG WINAPI IOW_fnAddRef(IOleWindow *iface) +{ + NSTC2Impl *This = impl_from_IOleWindow(iface); + TRACE("%p\n", This); + return NSTC2_fnAddRef(&This->INameSpaceTreeControl2_iface); +} + +static ULONG WINAPI IOW_fnRelease(IOleWindow *iface) +{ + NSTC2Impl *This = impl_from_IOleWindow(iface); + TRACE("%p\n", This); + return NSTC2_fnRelease(&This->INameSpaceTreeControl2_iface); +} + +static HRESULT WINAPI IOW_fnGetWindow(IOleWindow *iface, HWND *phwnd) +{ + NSTC2Impl *This = impl_from_IOleWindow(iface); + TRACE("%p (%p)\n", This, phwnd); + + *phwnd = This->hwnd_main; + return S_OK; +} + +static HRESULT WINAPI IOW_fnContextSensitiveHelp(IOleWindow *iface, BOOL fEnterMode) +{ + NSTC2Impl *This = impl_from_IOleWindow(iface); + TRACE("%p (%d)\n", This, fEnterMode); + + /* Not implemented */ + return E_NOTIMPL; +} + +static const IOleWindowVtbl vt_IOleWindow = { + IOW_fnQueryInterface, + IOW_fnAddRef, + IOW_fnRelease, + IOW_fnGetWindow, + IOW_fnContextSensitiveHelp +}; + +HRESULT NamespaceTreeControl_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + NSTC2Impl *nstc; + HRESULT ret; + + TRACE ("%p %s %p\n", pUnkOuter, debugstr_guid(riid), ppv); + + if(!ppv) + return E_POINTER; + if(pUnkOuter) + return CLASS_E_NOAGGREGATION; + + EFRAME_LockModule(); + + nstc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NSTC2Impl)); + nstc->ref = 1; + nstc->INameSpaceTreeControl2_iface.lpVtbl = &vt_INameSpaceTreeControl2; + nstc->IOleWindow_iface.lpVtbl = &vt_IOleWindow; + + list_init(&nstc->roots); + + ret = INameSpaceTreeControl2_QueryInterface(&nstc->INameSpaceTreeControl2_iface, riid, ppv); + INameSpaceTreeControl2_Release(&nstc->INameSpaceTreeControl2_iface); + + TRACE("--(%p)\n", ppv); + return ret; +} Index: dll/win32/explorerframe/taskbarlist.c =================================================================== --- dll/win32/explorerframe/taskbarlist.c (revision 0) +++ dll/win32/explorerframe/taskbarlist.c (working copy) @@ -0,0 +1,323 @@ +/* + * Copyright 2009 Henri Verbeet for CodeWeavers + * Copyright 2011 André Hentschel + * + * 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 "explorerframe_main.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ieframe); + +struct taskbar_list +{ + ITaskbarList4 ITaskbarList4_iface; + LONG refcount; +}; + +static inline struct taskbar_list *impl_from_ITaskbarList4(ITaskbarList4 *iface) +{ + return CONTAINING_RECORD(iface, struct taskbar_list, ITaskbarList4_iface); +} + +/* IUnknown methods */ + +static HRESULT STDMETHODCALLTYPE taskbar_list_QueryInterface(ITaskbarList4 *iface, REFIID riid, void **object) +{ + TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object); + + if (IsEqualGUID(riid, &IID_ITaskbarList) || + IsEqualGUID(riid, &IID_ITaskbarList2) || + IsEqualGUID(riid, &IID_ITaskbarList3) || + IsEqualGUID(riid, &IID_ITaskbarList4) || + IsEqualGUID(riid, &IID_IUnknown)) + { + ITaskbarList4_AddRef(iface); + *object = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid)); + + *object = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE taskbar_list_AddRef(ITaskbarList4 *iface) +{ + struct taskbar_list *This = impl_from_ITaskbarList4(iface); + ULONG refcount = InterlockedIncrement(&This->refcount); + + TRACE("%p increasing refcount to %u\n", This, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE taskbar_list_Release(ITaskbarList4 *iface) +{ + struct taskbar_list *This = impl_from_ITaskbarList4(iface); + ULONG refcount = InterlockedDecrement(&This->refcount); + + TRACE("%p decreasing refcount to %u\n", This, refcount); + + if (!refcount) + { + heap_free(This); + EFRAME_UnlockModule(); + } + + return refcount; +} + +/* ITaskbarList methods */ + +static HRESULT STDMETHODCALLTYPE taskbar_list_HrInit(ITaskbarList4 *iface) +{ + TRACE("iface %p\n", iface); + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_AddTab(ITaskbarList4 *iface, HWND hwnd) +{ + FIXME("iface %p, hwnd %p stub!\n", iface, hwnd); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_DeleteTab(ITaskbarList4 *iface, HWND hwnd) +{ + FIXME("iface %p, hwnd %p stub!\n", iface, hwnd); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_ActivateTab(ITaskbarList4 *iface, HWND hwnd) +{ + FIXME("iface %p, hwnd %p stub!\n", iface, hwnd); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetActiveAlt(ITaskbarList4 *iface, HWND hwnd) +{ + FIXME("iface %p, hwnd %p stub!\n", iface, hwnd); + + return E_NOTIMPL; +} + +/* ITaskbarList2 method */ + +static HRESULT STDMETHODCALLTYPE taskbar_list_MarkFullscreenWindow(ITaskbarList4 *iface, + HWND hwnd, + BOOL fullscreen) +{ + FIXME("iface %p, hwnd %p, fullscreen %s stub!\n", iface, hwnd, (fullscreen)?"true":"false"); + + return E_NOTIMPL; +} + +/* ITaskbarList3 methods */ + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetProgressValue(ITaskbarList4 *iface, + HWND hwnd, + ULONGLONG ullCompleted, + ULONGLONG ullTotal) +{ + static BOOL fixme_once; + if(!fixme_once++) FIXME("iface %p, hwnd %p, ullCompleted %s, ullTotal %s stub!\n", iface, hwnd, + wine_dbgstr_longlong(ullCompleted), wine_dbgstr_longlong(ullTotal)); + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetProgressState(ITaskbarList4 *iface, + HWND hwnd, + TBPFLAG tbpFlags) +{ + static BOOL fixme_once; + if(!fixme_once++) FIXME("iface %p, hwnd %p, flags %x stub!\n", iface, hwnd, tbpFlags); + + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_RegisterTab(ITaskbarList4 *iface, HWND hwndTab, HWND hwndMDI) +{ + FIXME("iface %p, hwndTab %p, hwndMDI %p stub!\n", iface, hwndTab, hwndMDI); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_UnregisterTab(ITaskbarList4 *iface, HWND hwndTab) +{ + FIXME("iface %p, hwndTab %p stub!\n", iface, hwndTab); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetTabOrder(ITaskbarList4 *iface, + HWND hwndTab, + HWND hwndInsertBefore) +{ + FIXME("iface %p, hwndTab %p, hwndInsertBefore %p stub!\n", iface, hwndTab, hwndInsertBefore); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetTabActive(ITaskbarList4 *iface, + HWND hwndTab, + HWND hwndMDI, + DWORD dwReserved) +{ + FIXME("iface %p, hwndTab %p, hwndMDI %p, dwReserved %x stub!\n", iface, hwndTab, hwndMDI, dwReserved); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_ThumbBarAddButtons(ITaskbarList4 *iface, + HWND hwnd, + UINT cButtons, + LPTHUMBBUTTON pButton) +{ + FIXME("iface %p, hwnd %p, cButtons %u, pButton %p stub!\n", iface, hwnd, cButtons, pButton); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_ThumbBarUpdateButtons(ITaskbarList4 *iface, + HWND hwnd, + UINT cButtons, + LPTHUMBBUTTON pButton) +{ + FIXME("iface %p, hwnd %p, cButtons %u, pButton %p stub!\n", iface, hwnd, cButtons, pButton); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_ThumbBarSetImageList(ITaskbarList4 *iface, + HWND hwnd, + HIMAGELIST himl) +{ + FIXME("iface %p, hwnd %p, himl %p stub!\n", iface, hwnd, himl); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetOverlayIcon(ITaskbarList4 *iface, + HWND hwnd, + HICON hIcon, + LPCWSTR pszDescription) +{ + FIXME("iface %p, hwnd %p, hIcon %p, pszDescription %s stub!\n", iface, hwnd, hIcon, + debugstr_w(pszDescription)); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetThumbnailTooltip(ITaskbarList4 *iface, + HWND hwnd, + LPCWSTR pszTip) +{ + FIXME("iface %p, hwnd %p, pszTip %s stub!\n", iface, hwnd, debugstr_w(pszTip)); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetThumbnailClip(ITaskbarList4 *iface, + HWND hwnd, + RECT *prcClip) +{ + FIXME("iface %p, hwnd %p, prcClip %s stub!\n", iface, hwnd, wine_dbgstr_rect(prcClip)); + + return E_NOTIMPL; +} + +/* ITaskbarList4 method */ + +static HRESULT STDMETHODCALLTYPE taskbar_list_SetTabProperties(ITaskbarList4 *iface, + HWND hwndTab, + STPFLAG stpFlags) +{ + FIXME("iface %p, hwndTab %p, stpFlags %u stub!\n", iface, hwndTab, stpFlags); + + return E_NOTIMPL; +} + +static const struct ITaskbarList4Vtbl taskbar_list_vtbl = +{ + /* IUnknown methods */ + taskbar_list_QueryInterface, + taskbar_list_AddRef, + taskbar_list_Release, + /* ITaskbarList methods */ + taskbar_list_HrInit, + taskbar_list_AddTab, + taskbar_list_DeleteTab, + taskbar_list_ActivateTab, + taskbar_list_SetActiveAlt, + /* ITaskbarList2 method */ + taskbar_list_MarkFullscreenWindow, + /* ITaskbarList3 methods */ + taskbar_list_SetProgressValue, + taskbar_list_SetProgressState, + taskbar_list_RegisterTab, + taskbar_list_UnregisterTab, + taskbar_list_SetTabOrder, + taskbar_list_SetTabActive, + taskbar_list_ThumbBarAddButtons, + taskbar_list_ThumbBarUpdateButtons, + taskbar_list_ThumbBarSetImageList, + taskbar_list_SetOverlayIcon, + taskbar_list_SetThumbnailTooltip, + taskbar_list_SetThumbnailClip, + /* ITaskbarList4 method */ + taskbar_list_SetTabProperties, +}; + +HRESULT TaskbarList_Constructor(IUnknown *outer, REFIID riid, void **taskbar_list) +{ + struct taskbar_list *object; + HRESULT hres; + + TRACE("outer %p, riid %s, taskbar_list %p\n", outer, debugstr_guid(riid), taskbar_list); + + if (outer) + { + WARN("Aggregation not supported\n"); + *taskbar_list = NULL; + return CLASS_E_NOAGGREGATION; + } + + object = heap_alloc(sizeof(*object)); + if (!object) + { + ERR("Failed to allocate taskbar list object memory\n"); + *taskbar_list = NULL; + return E_OUTOFMEMORY; + } + + object->ITaskbarList4_iface.lpVtbl = &taskbar_list_vtbl; + object->refcount = 1; + EFRAME_LockModule(); + + TRACE("Created ITaskbarList4 %p\n", object); + + hres = ITaskbarList4_QueryInterface(&object->ITaskbarList4_iface, riid, taskbar_list); + ITaskbarList4_Release(&object->ITaskbarList4_iface); + return hres; +} Index: dll/win32/explorerframe/version.rc =================================================================== --- dll/win32/explorerframe/version.rc (revision 0) +++ dll/win32/explorerframe/version.rc (working copy) @@ -0,0 +1,29 @@ +/* + * ExplorerFrame Version Resource + * + * Copyright 2010 David Hedberg + * + * 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 + */ + +#define WINE_FILEDESCRIPTION_STR "Wine ExplorerFrame" +#define WINE_FILENAME_STR "explorerframe.dll" +#define WINE_FILEVERSION 6,1,7601,16666 +#define WINE_FILEVERSION_STR "6.1.7601.16666" +#define WINE_PRODUCTVERSION 6,1,7601,16666 +#define WINE_PRODUCTVERSION_STR "6.1.7601.16666" +#define WINE_EXTRAVALUES VALUE "OLESelfRegister","" + +#include "wine/wine_common_ver.rc" Index: dll/win32/shell32/pidl.cpp =================================================================== --- dll/win32/shell32/pidl.cpp (revision 58725) +++ dll/win32/shell32/pidl.cpp (working copy) @@ -2420,3 +2420,79 @@ return dst; } + +/************************************************************************* + * SHGetIDListFromObject [SHELL32.@] + */ +HRESULT WINAPI SHGetIDListFromObject(IUnknown *punk, PIDLIST_ABSOLUTE *ppidl) +{ + IPersistIDList *ppersidl; + IPersistFolder2 *ppf2; + IDataObject *pdo; + IFolderView *pfv; + HRESULT ret; + + if (!punk) + return E_NOINTERFACE; + + *ppidl = NULL; + + /* Try IPersistIDList */ + ret = punk->QueryInterface(IID_IPersistIDList, (void**)&ppersidl); + if (SUCCEEDED(ret)) + { + TRACE("IPersistIDList (%p)\n", ppersidl); + ret = ppersidl->GetIDList(ppidl); + ppersidl->Release(); + if (SUCCEEDED(ret)) + return ret; + } + + /* Try IPersistFolder2 */ + ret = punk->QueryInterface(IID_IPersistFolder2, (void**)&ppf2); + if (SUCCEEDED(ret)) + { + TRACE("IPersistFolder2 (%p)\n", ppf2); + ret = ppf2->GetCurFolder(ppidl); + ppf2->Release(); + if (SUCCEEDED(ret)) + return ret; + } + + /* Try IDataObject */ + ret = punk->QueryInterface(IID_IDataObject, (void**)&pdo); + if (SUCCEEDED(ret)) + { + IShellItem *psi; + TRACE("IDataObject (%p)\n", pdo); + ret = SHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, + IID_IShellItem, (void**)&psi); + if (SUCCEEDED(ret)) + { + ret = SHGetIDListFromObject((IUnknown*)psi, ppidl); + psi->Release(); + } + pdo->Release(); + + if (SUCCEEDED(ret)) + return ret; + } + + /* Try IFolderView */ + ret = punk->QueryInterface(IID_IFolderView, (void**)&pfv); + if (SUCCEEDED(ret)) + { + IShellFolder *psf; + TRACE("IFolderView (%p)\n", pfv); + ret = pfv->GetFolder(IID_IShellFolder, (void**)&psf); + if(SUCCEEDED(ret)) + { + /* We might be able to get IPersistFolder2 from a shellfolder. */ + ret = SHGetIDListFromObject((IUnknown*)psf, ppidl); + } + pfv->Release(); + return ret; + } + + return ret; +} Index: dll/win32/shell32/shell32.spec =================================================================== --- dll/win32/shell32/shell32.spec (revision 58725) +++ dll/win32/shell32/shell32.spec (working copy) @@ -348,9 +348,13 @@ @ stdcall SHCreateDirectoryExA(long str ptr) @ stdcall SHCreateDirectoryExW(long wstr ptr) @ stub SHCreateLocalServerRunDll +@ stdcall SHCreateItemFromParsingName(wstr ptr ptr ptr) +@ stdcall SHCreateItemFromIDList(ptr ptr ptr) @ stdcall SHCreateProcessAsUserW(ptr) @ stdcall SHCreateQueryCancelAutoPlayMoniker(ptr) @ stdcall SHCreateShellItem(ptr ptr ptr ptr) +@ stdcall SHCreateShellItemArray(ptr ptr long ptr ptr) +@ stdcall SHCreateShellItemArrayFromShellItem(ptr ptr ptr) @ stdcall SHEmptyRecycleBinA(long str long) @ stdcall SHEmptyRecycleBinW(long wstr long) @ stub SHEnableServiceObject @@ -377,6 +381,8 @@ @ stdcall SHGetFolderPathW(long long long long ptr) @ stdcall SHGetIconOverlayIndexA(str long) @ stdcall SHGetIconOverlayIndexW(wstr long) +@ stdcall SHGetIDListFromObject(ptr ptr) +@ stdcall SHGetItemFromDataObject(ptr long ptr ptr) @ stdcall SHGetInstanceExplorer(long) @ stdcall SHGetMalloc(ptr) @ stdcall SHGetNewLinkInfo(str str ptr long long) SHGetNewLinkInfoA Index: dll/win32/shell32/shellitem.cpp =================================================================== --- dll/win32/shell32/shellitem.cpp (revision 58725) +++ dll/win32/shell32/shellitem.cpp (working copy) @@ -1,5 +1,5 @@ /* - * IShellItem implementation + * IShellItem and IShellItemArray implementation * * Copyright 2008 Vincent Povirk for CodeWeavers * Copyright 2009 Andrew Hill @@ -308,3 +308,377 @@ *ppsi = newShellItem; return hr; } + +HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv) +{ + CShellItem *This; + HRESULT ret; + + if (!pidl) + return E_INVALIDARG; + + ret = CShellItem::_CreatorClass::CreateInstance(NULL, riid, (void**)&ppv); + if (SUCCEEDED(ret)) + { + This = (CShellItem *)*ppv; + This->SetIDList(pidl); + } + + return ret; +} + +class CShellItemArray : public IShellItemArray +{ +public: + CShellItemArray(); + virtual ~CShellItemArray(); + + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID * ppvObj); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + + // IShellItemArray + virtual HRESULT STDMETHODCALLTYPE BindToHandler( + IBindCtx *pbc, + REFGUID bhid, + REFIID riid, + void **ppvOut); + + virtual HRESULT STDMETHODCALLTYPE GetPropertyStore( + GETPROPERTYSTOREFLAGS flags, + REFIID riid, + void **ppv); + + virtual HRESULT STDMETHODCALLTYPE GetPropertyDescriptionList( + REFPROPERTYKEY keyType, + REFIID riid, + void **ppv); + + virtual HRESULT STDMETHODCALLTYPE GetAttributes( + SIATTRIBFLAGS AttribFlags, + SFGAOF sfgaoMask, + SFGAOF *psfgaoAttribs); + + virtual HRESULT STDMETHODCALLTYPE GetCount( + DWORD *pdwNumItems); + + virtual HRESULT STDMETHODCALLTYPE GetItemAt( + DWORD dwIndex, + IShellItem **ppsi); + + virtual HRESULT STDMETHODCALLTYPE EnumItems( + IEnumShellItems **ppenumShellItems); + +public: + LONG m_ref; + IShellItem **m_array; + DWORD m_count; +}; + +CShellItemArray::CShellItemArray() +{ + m_ref = 1; + m_array = NULL; + m_count = 0; +} + +CShellItemArray::~CShellItemArray() +{ + for(DWORD i = 0; i < m_count; i++) + m_array[i]->Release(); + CoTaskMemFree(m_array); +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::QueryInterface(REFIID riid, LPVOID * ppvObj) +{ + *ppvObj = NULL; + if (IsEqualIID(riid, IID_IShellItemArray) || + IsEqualIID(riid, IID_IUnknown)) + { + *ppvObj = this; + AddRef(); + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE CShellItemArray::AddRef() +{ + return InterlockedIncrement(&m_ref); +} + +ULONG STDMETHODCALLTYPE CShellItemArray::Release() +{ + LONG ref = InterlockedDecrement(&m_ref); + if (!ref) + delete this; + return ref; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::BindToHandler( + IBindCtx *pbc, + REFGUID bhid, + REFIID riid, + void **ppvOut) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::GetPropertyStore( + GETPROPERTYSTOREFLAGS flags, + REFIID riid, + void **ppv) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::GetPropertyDescriptionList( + REFPROPERTYKEY keyType, + REFIID riid, + void **ppv) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::GetAttributes( + SIATTRIBFLAGS AttribFlags, + SFGAOF sfgaoMask, + SFGAOF *psfgaoAttribs) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::GetCount( + DWORD *pdwNumItems) +{ + if (pdwNumItems == NULL) + return E_POINTER; + *pdwNumItems = m_count; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::GetItemAt( + DWORD dwIndex, + IShellItem **ppsi) +{ + if (dwIndex >= m_count) + return E_FAIL; + if (ppsi == NULL) + return E_POINTER; + + ppsi[0] = m_array[dwIndex]; + ppsi[0]->AddRef(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CShellItemArray::EnumItems( + IEnumShellItems **ppenumShellItems) +{ + return E_NOTIMPL; +} + +EXTERN_C +HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent, + IShellFolder *psf, + UINT cidl, + PCUITEMID_CHILD_ARRAY ppidl, + IShellItemArray **ppsiItemArray) +{ + CShellItemArray *This; + IShellItem **array; + HRESULT ret = E_FAIL; + UINT i; + + TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray); + + if (!pidlParent && !psf) + return E_POINTER; + + if (!ppidl) + return E_INVALIDARG; + + array = (IShellItem **)CoTaskMemAlloc(cidl * sizeof(IShellItem*)); + if (!array) + return E_OUTOFMEMORY; + + for (i = 0; i < cidl; i++) + { + ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]); + if(FAILED(ret)) break; + } + + if (SUCCEEDED(ret)) + { + ATLTRY (This = new CShellItemArray); + if (This) + { + This->m_array = array; + This->m_count = cidl; + *ppsiItemArray = This; + return ret; + } + } + + /* Something failed, clean up. */ + for (i = 0; i < cidl; i++) + if (array[i]) array[i]->Release(); + CoTaskMemFree(array); + *ppsiItemArray = NULL; + return ret; +} + +EXTERN_C +HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv) +{ + CShellItemArray *This; + IShellItem **array; + HRESULT ret; + + TRACE("%p, %s, %p\n", psi, shdebugstr_guid(&riid), ppv); + + array = (IShellItem **)CoTaskMemAlloc(sizeof(IShellItem *)); + if (!array) + return E_OUTOFMEMORY; + + ATLTRY (This = new CShellItemArray); + if (This) + { + array[0] = psi; + psi->AddRef(); + This->m_array = array; + This->m_count = 1; + *ppv = This; + } + else + { + CoTaskMemFree(array); + *ppv = NULL; + } + + return ret; +} + +EXTERN_C +HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath, + IBindCtx *pbc, REFIID riid, void **ppv) +{ + LPITEMIDLIST pidl; + HRESULT ret; + + *ppv = NULL; + + ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL); + if(SUCCEEDED(ret)) + { + CShellItem *This; + ret = CShellItem::_CreatorClass::CreateInstance(NULL, riid, (void**)&This); + if (SUCCEEDED(ret)) + { + This->SetIDList(pidl); + *ppv = (void*)This; + } + ILFree(pidl); + } + return ret; +} + +EXTERN_C +HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj, + DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv) +{ + FORMATETC fmt; + STGMEDIUM medium; + HRESULT ret; + + TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(&riid), ppv); + + if (!pdtobj) + return E_INVALIDARG; + + fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_HGLOBAL; + + ret = pdtobj->GetData(&fmt, &medium); + if(SUCCEEDED(ret)) + { + LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal); + + if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) || + pida->cidl == 1) + { + LPITEMIDLIST pidl; + + /* Get the first pidl (parent + child1) */ + pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]), + (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1])); + + ret = SHCreateItemFromIDList(pidl, riid, ppv); + ILFree(pidl); + } + else + { + ret = E_FAIL; + } + + GlobalUnlock(medium.hGlobal); + GlobalFree(medium.hGlobal); + } + + if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP)) + { + TRACE("Attempting to fall back on CF_HDROP.\n"); + + fmt.cfFormat = CF_HDROP; + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_HGLOBAL; + + ret = pdtobj->GetData(&fmt, &medium); + if(SUCCEEDED(ret)) + { + DROPFILES *df = (DROPFILES *)GlobalLock(medium.hGlobal); + LPBYTE files = (LPBYTE)df + df->pFiles; + BOOL multiple_files = FALSE; + + ret = E_FAIL; + if(!df->fWide) + { + WCHAR filename[MAX_PATH]; + PCSTR first_file = (PCSTR)files; + if(*(files + lstrlenA(first_file) + 1) != 0) + multiple_files = TRUE; + + if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) ) + { + MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH); + ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv); + } + } + else + { + PCWSTR first_file = (PCWSTR)files; + if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0) + multiple_files = TRUE; + + if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) ) + ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv); + } + + GlobalUnlock(medium.hGlobal); + GlobalFree(medium.hGlobal); + } + } + + if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL)) + { + FIXME("Failed to create item, should try CF_URL.\n"); + } + + return ret; +} Index: include/psdk/commctrl.h =================================================================== --- include/psdk/commctrl.h (revision 58725) +++ include/psdk/commctrl.h (working copy) @@ -3043,6 +3043,25 @@ #define TVIS_FOCUSED 0x0001 +#define TVIS_EX_FLAT 0x0001 +#define TVIS_EX_DISABLED 0x0002 +/* TVIS_EX_HWND is listed on MSDN but apparently not in any header. */ +#define TVIS_EX_ALL 0x0002 + +#define TVS_SHAREDIMAGELISTS 0x0000 +#define TVS_PRIVATEIMAGELISTS 0x0400 + +#define TVS_EX_MULTISELECT 0x0002 +#define TVS_EX_DOUBLEBUFFER 0x0004 +#define TVS_EX_NOINDENTSTATE 0x0008 +#define TVS_EX_RICHTOOLTIP 0x0010 +#define TVS_EX_AUTOHSCROLL 0x0020 +#define TVS_EX_FADEINOUTEXPANDOS 0x0040 +#define TVS_EX_PARTIALCHECKBOXES 0x0080 +#define TVS_EX_EXCLUSIONCHECKBOXES 0x0100 +#define TVS_EX_DIMMEDCHECKBOXES 0x0200 +#define TVS_EX_DRAWIMAGEASYNC 0x0400 + #define I_CHILDRENCALLBACK (-1) #define LPTV_ITEMW LPTVITEMW @@ -3358,6 +3377,9 @@ #define TVM_MAPHTREEITEMTOACCID (TV_FIRST+43) #define TreeView_MapHTREEITEMToAccID(hwnd,htreeitem) (UINT)SNDMSG((hwnd),TVM_MAPHTREEITEMTOACCID,(WPARAM)htreeitem,0) +#define TVM_SETEXTENDEDSTYLE (TV_FIRST + 44) +#define TVM_GETEXTENDEDSTYLE (TV_FIRST + 45) + typedef int (CALLBACK *PFNTVCOMPARE)(LPARAM lParam1,LPARAM lParam2,LPARAM lParamSort); #define LPTV_SORTCB LPTVSORTCB