|  |  | 
|  | /* | 
|  | * file system folder | 
|  | * | 
|  | * Copyright 1997             Marcus Meissner | 
|  | * Copyright 1998, 1999, 2002 Juergen Schmied | 
|  | * | 
|  | * 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 "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #include "winerror.h" | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winreg.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  |  | 
|  | #include "ole2.h" | 
|  | #include "shlguid.h" | 
|  |  | 
|  | #include "enumidlist.h" | 
|  | #include "pidl.h" | 
|  | #include "undocshell.h" | 
|  | #include "shell32_main.h" | 
|  | #include "shresdef.h" | 
|  | #include "shlwapi.h" | 
|  | #include "shellfolder.h" | 
|  | #include "wine/debug.h" | 
|  | #include "debughlp.h" | 
|  | #include "shfldr.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL (shell); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *   IShellFolder implementation | 
|  | */ | 
|  |  | 
|  | typedef struct { | 
|  | const IUnknownVtbl        *lpVtbl; | 
|  | LONG                ref; | 
|  | const IShellFolder2Vtbl   *lpvtblShellFolder; | 
|  | const IPersistFolder3Vtbl *lpvtblPersistFolder3; | 
|  | const IDropTargetVtbl     *lpvtblDropTarget; | 
|  | const ISFHelperVtbl       *lpvtblSFHelper; | 
|  |  | 
|  | IUnknown *pUnkOuter; /* used for aggregation */ | 
|  |  | 
|  | CLSID *pclsid; | 
|  |  | 
|  | /* both paths are parsible from the desktop */ | 
|  | LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */ | 
|  |  | 
|  | LPITEMIDLIST pidlRoot; /* absolute pidl */ | 
|  |  | 
|  | UINT cfShellIDList;    /* clipboardformat for IDropTarget */ | 
|  | BOOL fAcceptFmt;       /* flag for pending Drop */ | 
|  | } IGenericSFImpl; | 
|  |  | 
|  | static const IUnknownVtbl unkvt; | 
|  | static const IShellFolder2Vtbl sfvt; | 
|  | static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */ | 
|  | static const IDropTargetVtbl dtvt; | 
|  | static const ISFHelperVtbl shvt; | 
|  |  | 
|  | static inline IGenericSFImpl *impl_from_IShellFolder2( IShellFolder2 *iface ) | 
|  | { | 
|  | return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblShellFolder)); | 
|  | } | 
|  |  | 
|  | static inline IGenericSFImpl *impl_from_IPersistFolder3( IPersistFolder3 *iface ) | 
|  | { | 
|  | return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblPersistFolder3)); | 
|  | } | 
|  |  | 
|  | static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface ) | 
|  | { | 
|  | return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget)); | 
|  | } | 
|  |  | 
|  | static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface ) | 
|  | { | 
|  | return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper)); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | converts This to an interface pointer | 
|  | */ | 
|  | #define _IUnknown_(This)        ((IUnknown*)&(This)->lpVtbl) | 
|  | #define _IShellFolder_(This)    ((IShellFolder*)&(This)->lpvtblShellFolder) | 
|  | #define _IShellFolder2_(This)   ((IShellFolder2*)&(This)->lpvtblShellFolder) | 
|  | #define _IPersist_(This)        (&(This)->lpvtblPersistFolder3) | 
|  | #define _IPersistFolder_(This)  (&(This)->lpvtblPersistFolder3) | 
|  | #define _IPersistFolder2_(This) (&(This)->lpvtblPersistFolder3) | 
|  | #define _IPersistFolder3_(This) (&(This)->lpvtblPersistFolder3) | 
|  | #define _IDropTarget_(This)     (&(This)->lpvtblDropTarget) | 
|  | #define _ISFHelper_(This)       (&(This)->lpvtblSFHelper) | 
|  |  | 
|  | /************************************************************************** | 
|  | * registers clipboardformat once | 
|  | */ | 
|  | static void SF_RegisterClipFmt (IGenericSFImpl * This) | 
|  | { | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | if (!This->cfShellIDList) { | 
|  | This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW); | 
|  | } | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * we need a separate IUnknown to handle aggregation | 
|  | * (inner IUnknown) | 
|  | */ | 
|  | static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj) | 
|  | { | 
|  | IGenericSFImpl *This = (IGenericSFImpl *)iface; | 
|  |  | 
|  | TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj); | 
|  |  | 
|  | *ppvObj = NULL; | 
|  |  | 
|  | if (IsEqualIID (riid, &IID_IUnknown)) | 
|  | *ppvObj = _IUnknown_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IShellFolder)) | 
|  | *ppvObj = _IShellFolder_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IShellFolder2)) | 
|  | *ppvObj = _IShellFolder_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IPersist)) | 
|  | *ppvObj = _IPersist_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IPersistFolder)) | 
|  | *ppvObj = _IPersistFolder_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IPersistFolder2)) | 
|  | *ppvObj = _IPersistFolder2_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IPersistFolder3)) | 
|  | *ppvObj = _IPersistFolder3_ (This); | 
|  | else if (IsEqualIID (riid, &IID_ISFHelper)) | 
|  | *ppvObj = _ISFHelper_ (This); | 
|  | else if (IsEqualIID (riid, &IID_IDropTarget)) { | 
|  | *ppvObj = _IDropTarget_ (This); | 
|  | SF_RegisterClipFmt (This); | 
|  | } | 
|  |  | 
|  | if (*ppvObj) { | 
|  | IUnknown_AddRef ((IUnknown *) (*ppvObj)); | 
|  | TRACE ("-- Interface = %p\n", *ppvObj); | 
|  | return S_OK; | 
|  | } | 
|  | TRACE ("-- Interface: E_NOINTERFACE\n"); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface) | 
|  | { | 
|  | IGenericSFImpl *This = (IGenericSFImpl *)iface; | 
|  | ULONG refCount = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, refCount - 1); | 
|  |  | 
|  | return refCount; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface) | 
|  | { | 
|  | IGenericSFImpl *This = (IGenericSFImpl *)iface; | 
|  | ULONG refCount = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, refCount + 1); | 
|  |  | 
|  | if (!refCount) { | 
|  | TRACE ("-- destroying IShellFolder(%p)\n", This); | 
|  |  | 
|  | SHFree (This->pidlRoot); | 
|  | SHFree (This->sPathTarget); | 
|  | LocalFree (This); | 
|  | } | 
|  | return refCount; | 
|  | } | 
|  |  | 
|  | static const IUnknownVtbl unkvt = | 
|  | { | 
|  | IUnknown_fnQueryInterface, | 
|  | IUnknown_fnAddRef, | 
|  | IUnknown_fnRelease, | 
|  | }; | 
|  |  | 
|  | static const shvheader GenericSFHeader[] = { | 
|  | {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, | 
|  | {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, | 
|  | {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, | 
|  | {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12}, | 
|  | {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5} | 
|  | }; | 
|  |  | 
|  | #define GENERICSHELLVIEWCOLUMNS 5 | 
|  |  | 
|  | /************************************************************************** | 
|  | * IFSFolder_Constructor | 
|  | * | 
|  | * NOTES | 
|  | *  creating undocumented ShellFS_Folder as part of an aggregation | 
|  | *  {F3364BA0-65B9-11CE-A9BA-00AA004AE837} | 
|  | * | 
|  | */ | 
|  | HRESULT WINAPI | 
|  | IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv) | 
|  | { | 
|  | IGenericSFImpl *sf; | 
|  |  | 
|  | TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid)); | 
|  |  | 
|  | if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown)) | 
|  | return CLASS_E_NOAGGREGATION; | 
|  | sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl)); | 
|  | if (!sf) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | sf->ref = 0; | 
|  | sf->lpVtbl = &unkvt; | 
|  | sf->lpvtblShellFolder = &sfvt; | 
|  | sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3; | 
|  | sf->lpvtblDropTarget = &dtvt; | 
|  | sf->lpvtblSFHelper = &shvt; | 
|  | sf->pclsid = (CLSID *) & CLSID_ShellFSFolder; | 
|  | sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf); | 
|  |  | 
|  | if (FAILED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) { | 
|  | IUnknown_Release (_IUnknown_ (sf)); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | TRACE ("--%p\n", *ppv); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnQueryInterface | 
|  | * | 
|  | * PARAMETERS | 
|  | *  REFIID riid       [in ] Requested InterfaceID | 
|  | *  LPVOID* ppvObject [out] Interface* to hold the result | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid, | 
|  | LPVOID * ppvObj) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj); | 
|  |  | 
|  | return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_AddRef | 
|  | */ | 
|  |  | 
|  | static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_AddRef (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnRelease | 
|  | */ | 
|  | static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_Release (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  SHELL32_CreatePidlFromBindCtx  [internal] | 
|  | * | 
|  | *  If the caller bound File System Bind Data, assume it is the | 
|  | *   find data for the path. | 
|  | *  This allows binding of paths that don't exist. | 
|  | */ | 
|  | LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path) | 
|  | { | 
|  | static WCHAR szfsbc[] = { | 
|  | 'F','i','l','e',' ','S','y','s','t','e','m',' ', | 
|  | 'B','i','n','d',' ','D','a','t','a',0 }; | 
|  | IFileSystemBindData *fsbd = NULL; | 
|  | LPITEMIDLIST pidl = NULL; | 
|  | IUnknown *param = NULL; | 
|  | WIN32_FIND_DATAW wfd; | 
|  | HRESULT r; | 
|  |  | 
|  | TRACE("%p %s\n", pbc, debugstr_w(path)); | 
|  |  | 
|  | if (!pbc) | 
|  | return NULL; | 
|  |  | 
|  | /* see if the caller bound File System Bind Data */ | 
|  | r = IBindCtx_GetObjectParam( pbc, szfsbc, ¶m ); | 
|  | if (FAILED(r)) | 
|  | return NULL; | 
|  |  | 
|  | r = IUnknown_QueryInterface( param, &IID_IFileSystemBindData, | 
|  | (LPVOID*) &fsbd ); | 
|  | if (SUCCEEDED(r)) | 
|  | { | 
|  | r = IFileSystemBindData_GetFindData( fsbd, &wfd ); | 
|  | if (SUCCEEDED(r)) | 
|  | { | 
|  | lstrcpynW( &wfd.cFileName[0], path, MAX_PATH ); | 
|  | pidl = _ILCreateFromFindDataW( &wfd ); | 
|  | } | 
|  | IFileSystemBindData_Release( fsbd ); | 
|  | } | 
|  |  | 
|  | return pidl; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IShellFolder_ParseDisplayName {SHELL32} | 
|  | * | 
|  | * Parse a display name. | 
|  | * | 
|  | * PARAMS | 
|  | *  hwndOwner       [in]  Parent window for any message's | 
|  | *  pbc             [in]  optional FileSystemBindData context | 
|  | *  lpszDisplayName [in]  Unicode displayname. | 
|  | *  pchEaten        [out] (unicode) characters processed | 
|  | *  ppidl           [out] complex pidl to item | 
|  | *  pdwAttributes   [out] items attributes | 
|  | * | 
|  | * NOTES | 
|  | *  Every folder tries to parse only its own (the leftmost) pidl and creates a | 
|  | *  subfolder to evaluate the remaining parts. | 
|  | *  Now we can parse into namespaces implemented by shell extensions | 
|  | * | 
|  | *  Behaviour on win98: lpszDisplayName=NULL -> crash | 
|  | *                      lpszDisplayName="" -> returns mycoputer-pidl | 
|  | * | 
|  | * FIXME | 
|  | *    pdwAttributes is not set | 
|  | *    pchEaten is not set like in windows | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnParseDisplayName (IShellFolder2 * iface, | 
|  | HWND hwndOwner, | 
|  | LPBC pbc, | 
|  | LPOLESTR lpszDisplayName, | 
|  | DWORD * pchEaten, LPITEMIDLIST * ppidl, | 
|  | DWORD * pdwAttributes) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | HRESULT hr = E_INVALIDARG; | 
|  | LPCWSTR szNext = NULL; | 
|  | WCHAR szElement[MAX_PATH]; | 
|  | WCHAR szPath[MAX_PATH]; | 
|  | LPITEMIDLIST pidlTemp = NULL; | 
|  | DWORD len; | 
|  |  | 
|  | TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", | 
|  | This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName), | 
|  | pchEaten, ppidl, pdwAttributes); | 
|  |  | 
|  | if (!lpszDisplayName || !ppidl) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (pchEaten) | 
|  | *pchEaten = 0; /* strange but like the original */ | 
|  |  | 
|  | pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName); | 
|  | if (!pidlTemp && *lpszDisplayName) | 
|  | { | 
|  | /* get the next element */ | 
|  | szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH); | 
|  |  | 
|  | /* build the full pathname to the element */ | 
|  | lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1); | 
|  | PathAddBackslashW(szPath); | 
|  | len = lstrlenW(szPath); | 
|  | lstrcpynW(szPath + len, szElement, MAX_PATH - len); | 
|  |  | 
|  | /* get the pidl */ | 
|  | hr = _ILCreateFromPathW(szPath, &pidlTemp); | 
|  |  | 
|  | if (SUCCEEDED(hr)) { | 
|  | if (szNext && *szNext) { | 
|  | /* try to analyse the next element */ | 
|  | hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc, | 
|  | &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); | 
|  | } else { | 
|  | /* it's the last element */ | 
|  | if (pdwAttributes && *pdwAttributes) { | 
|  | hr = SHELL32_GetItemAttributes (_IShellFolder_ (This), | 
|  | pidlTemp, pdwAttributes); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (SUCCEEDED(hr)) | 
|  | *ppidl = pidlTemp; | 
|  | else | 
|  | *ppidl = NULL; | 
|  |  | 
|  | TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", This, ppidl ? *ppidl : 0, hr); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IShellFolder_fnEnumObjects | 
|  | * PARAMETERS | 
|  | *  HWND          hwndOwner,    //[in ] Parent Window | 
|  | *  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask | 
|  | *  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner, | 
|  | DWORD dwFlags, LPENUMIDLIST * ppEnumIDList) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner, | 
|  | dwFlags, ppEnumIDList); | 
|  |  | 
|  | *ppEnumIDList = IEnumIDList_Constructor(); | 
|  | if (*ppEnumIDList) | 
|  | CreateFolderEnumList(*ppEnumIDList, This->sPathTarget, dwFlags); | 
|  |  | 
|  | TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList); | 
|  |  | 
|  | return *ppEnumIDList ? S_OK : E_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IShellFolder_fnBindToObject | 
|  | * PARAMETERS | 
|  | *  LPCITEMIDLIST pidl,       //[in ] relative pidl to open | 
|  | *  LPBC          pbc,        //[in ] optional FileSystemBindData context | 
|  | *  REFIID        riid,       //[in ] Initial Interface | 
|  | *  LPVOID*       ppvObject   //[out] Interface* | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl, | 
|  | LPBC pbc, REFIID riid, LPVOID * ppvOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc, | 
|  | shdebugstr_guid (riid), ppvOut); | 
|  |  | 
|  | return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid, | 
|  | ppvOut); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnBindToStorage | 
|  | * PARAMETERS | 
|  | *  LPCITEMIDLIST pidl,       //[in ] complex pidl to store | 
|  | *  LPBC          pbc,        //[in ] reserved | 
|  | *  REFIID        riid,       //[in ] Initial storage interface | 
|  | *  LPVOID*       ppvObject   //[out] Interface* returned | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl, | 
|  | LPBC pbcReserved, REFIID riid, LPVOID * ppvOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved, | 
|  | shdebugstr_guid (riid), ppvOut); | 
|  |  | 
|  | *ppvOut = NULL; | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnCompareIDs | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam, | 
|  | LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | int nReturn; | 
|  |  | 
|  | TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2); | 
|  | nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2); | 
|  | TRACE ("-- %i\n", nReturn); | 
|  | return nReturn; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IShellFolder_fnCreateViewObject | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner, | 
|  | REFIID riid, LPVOID * ppvOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | LPSHELLVIEW pShellView; | 
|  | HRESULT hr = E_INVALIDARG; | 
|  |  | 
|  | TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid), | 
|  | ppvOut); | 
|  |  | 
|  | if (ppvOut) { | 
|  | *ppvOut = NULL; | 
|  |  | 
|  | if (IsEqualIID (riid, &IID_IDropTarget)) { | 
|  | hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, ppvOut); | 
|  | } else if (IsEqualIID (riid, &IID_IContextMenu)) { | 
|  | FIXME ("IContextMenu not implemented\n"); | 
|  | hr = E_NOTIMPL; | 
|  | } else if (IsEqualIID (riid, &IID_IShellView)) { | 
|  | pShellView = IShellView_Constructor ((IShellFolder *) iface); | 
|  | if (pShellView) { | 
|  | hr = IShellView_QueryInterface (pShellView, riid, ppvOut); | 
|  | IShellView_Release (pShellView); | 
|  | } | 
|  | } | 
|  | } | 
|  | TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnGetAttributesOf | 
|  | * | 
|  | * PARAMETERS | 
|  | *  UINT            cidl,     //[in ] num elements in pidl array | 
|  | *  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array | 
|  | *  ULONG*          rgfInOut) //[out] result array | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl, | 
|  | LPCITEMIDLIST * apidl, DWORD * rgfInOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", This, cidl, apidl, | 
|  | rgfInOut, rgfInOut ? *rgfInOut : 0); | 
|  |  | 
|  | if (!rgfInOut) | 
|  | return E_INVALIDARG; | 
|  | if (cidl && !apidl) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (*rgfInOut == 0) | 
|  | *rgfInOut = ~0; | 
|  |  | 
|  | if(cidl == 0){ | 
|  | IShellFolder *psfParent = NULL; | 
|  | LPCITEMIDLIST rpidl = NULL; | 
|  |  | 
|  | hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl); | 
|  | if(SUCCEEDED(hr)) { | 
|  | SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut); | 
|  | IShellFolder_Release(psfParent); | 
|  | } | 
|  | } | 
|  | else { | 
|  | while (cidl > 0 && *apidl) { | 
|  | pdump (*apidl); | 
|  | SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut); | 
|  | apidl++; | 
|  | cidl--; | 
|  | } | 
|  | } | 
|  | /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ | 
|  | *rgfInOut &= ~SFGAO_VALIDATE; | 
|  |  | 
|  | TRACE ("-- result=0x%08x\n", *rgfInOut); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnGetUIObjectOf | 
|  | * | 
|  | * PARAMETERS | 
|  | *  HWND           hwndOwner, //[in ] Parent window for any output | 
|  | *  UINT           cidl,      //[in ] array size | 
|  | *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array | 
|  | *  REFIID         riid,      //[in ] Requested Interface | 
|  | *  UINT*          prgfInOut, //[   ] reserved | 
|  | *  LPVOID*        ppvObject) //[out] Resulting Interface | 
|  | * | 
|  | * NOTES | 
|  | *  This function gets asked to return "view objects" for one or more (multiple | 
|  | *  select) items: | 
|  | *  The viewobject typically is an COM object with one of the following | 
|  | *  interfaces: | 
|  | *  IExtractIcon,IDataObject,IContextMenu | 
|  | *  In order to support icon positions in the default Listview your DataObject | 
|  | *  must implement the SetData method (in addition to GetData :) - the shell | 
|  | *  passes a barely documented "Icon positions" structure to SetData when the | 
|  | *  drag starts, and GetData's it if the drop is in another explorer window that | 
|  | *  needs the positions. | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface, | 
|  | HWND hwndOwner, | 
|  | UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, | 
|  | UINT * prgfInOut, LPVOID * ppvOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | LPITEMIDLIST pidl; | 
|  | IUnknown *pObj = NULL; | 
|  | HRESULT hr = E_INVALIDARG; | 
|  |  | 
|  | TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", | 
|  | This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut); | 
|  |  | 
|  | if (ppvOut) { | 
|  | *ppvOut = NULL; | 
|  |  | 
|  | if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) { | 
|  | pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface, | 
|  | This->pidlRoot, apidl, cidl); | 
|  | hr = S_OK; | 
|  | } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) { | 
|  | pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner, | 
|  | This->pidlRoot, apidl, cidl); | 
|  | hr = S_OK; | 
|  | } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) { | 
|  | pidl = ILCombine (This->pidlRoot, apidl[0]); | 
|  | pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl); | 
|  | SHFree (pidl); | 
|  | hr = S_OK; | 
|  | } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) { | 
|  | pidl = ILCombine (This->pidlRoot, apidl[0]); | 
|  | pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl); | 
|  | SHFree (pidl); | 
|  | hr = S_OK; | 
|  | } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) { | 
|  | hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, | 
|  | (LPVOID *) & pObj); | 
|  | } else if ((IsEqualIID(riid,&IID_IShellLinkW) || | 
|  | IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) { | 
|  | pidl = ILCombine (This->pidlRoot, apidl[0]); | 
|  | hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj); | 
|  | SHFree (pidl); | 
|  | } else { | 
|  | hr = E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | if (SUCCEEDED(hr) && !pObj) | 
|  | hr = E_OUTOFMEMORY; | 
|  |  | 
|  | *ppvOut = pObj; | 
|  | } | 
|  | TRACE ("(%p)->hr=0x%08x\n", This, hr); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E', | 
|  | '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', | 
|  | 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l', | 
|  | 'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 }; | 
|  | static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x', | 
|  | 't',0 }; | 
|  | static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E', | 
|  | 'x','t',0 }; | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SHELL_FS_HideExtension [Internal] | 
|  | * | 
|  | * Query the registry if the filename extension of a given path should be | 
|  | * hidden. | 
|  | * | 
|  | * PARAMS | 
|  | *  szPath [I] Relative or absolute path of a file | 
|  | * | 
|  | * RETURNS | 
|  | *  TRUE, if the filename's extension should be hidden | 
|  | *  FALSE, otherwise. | 
|  | */ | 
|  | BOOL SHELL_FS_HideExtension(LPCWSTR szPath) | 
|  | { | 
|  | HKEY hKey; | 
|  | DWORD dwData; | 
|  | DWORD dwDataSize = sizeof (DWORD); | 
|  | BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */ | 
|  |  | 
|  | if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) { | 
|  | if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize)) | 
|  | doHide = dwData; | 
|  | RegCloseKey (hKey); | 
|  | } | 
|  |  | 
|  | if (!doHide) { | 
|  | LPWSTR ext = PathFindExtensionW(szPath); | 
|  |  | 
|  | if (*ext != '\0') { | 
|  | WCHAR classname[MAX_PATH]; | 
|  | LONG classlen = sizeof(classname); | 
|  |  | 
|  | if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen)) | 
|  | if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) { | 
|  | if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL)) | 
|  | doHide = TRUE; | 
|  | RegCloseKey(hKey); | 
|  | } | 
|  | } | 
|  | } | 
|  | return doHide; | 
|  | } | 
|  |  | 
|  | void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags) | 
|  | { | 
|  | /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */ | 
|  | if (!(dwFlags & SHGDN_FORPARSING) && | 
|  | ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) { | 
|  | if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.') | 
|  | PathRemoveExtensionW(szPath); | 
|  | } | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnGetDisplayNameOf | 
|  | *  Retrieves the display name for the specified file object or subfolder | 
|  | * | 
|  | * PARAMETERS | 
|  | *  LPCITEMIDLIST pidl,    //[in ] complex pidl to item | 
|  | *  DWORD         dwFlags, //[in ] SHGNO formatting flags | 
|  | *  LPSTRRET      lpName)  //[out] Returned display name | 
|  | * | 
|  | * FIXME | 
|  | *  if the name is in the pidl the ret value should be a STRRET_OFFSET | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, | 
|  | DWORD dwFlags, LPSTRRET strRet) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | LPWSTR pszPath; | 
|  |  | 
|  | HRESULT hr = S_OK; | 
|  | int len = 0; | 
|  |  | 
|  | TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet); | 
|  | pdump (pidl); | 
|  |  | 
|  | if (!pidl || !strRet) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR)); | 
|  | if (!pszPath) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | if (_ILIsDesktop(pidl)) { /* empty pidl */ | 
|  | if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && | 
|  | (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) | 
|  | { | 
|  | if (This->sPathTarget) | 
|  | lstrcpynW(pszPath, This->sPathTarget, MAX_PATH); | 
|  | } else { | 
|  | /* pidl has to contain exactly one non null SHITEMID */ | 
|  | hr = E_INVALIDARG; | 
|  | } | 
|  | } else if (_ILIsPidlSimple(pidl)) { | 
|  | if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && | 
|  | (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && | 
|  | This->sPathTarget) | 
|  | { | 
|  | lstrcpynW(pszPath, This->sPathTarget, MAX_PATH); | 
|  | PathAddBackslashW(pszPath); | 
|  | len = lstrlenW(pszPath); | 
|  | } | 
|  | _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len); | 
|  | if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); | 
|  | } else { | 
|  | hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH); | 
|  | } | 
|  |  | 
|  | if (SUCCEEDED(hr)) { | 
|  | /* Win9x always returns ANSI strings, NT always returns Unicode strings */ | 
|  | if (GetVersion() & 0x80000000) { | 
|  | strRet->uType = STRRET_CSTR; | 
|  | if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH, | 
|  | NULL, NULL)) | 
|  | strRet->u.cStr[0] = '\0'; | 
|  | CoTaskMemFree(pszPath); | 
|  | } else { | 
|  | strRet->uType = STRRET_WSTR; | 
|  | strRet->u.pOleStr = pszPath; | 
|  | } | 
|  | } else | 
|  | CoTaskMemFree(pszPath); | 
|  |  | 
|  | TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr)); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  IShellFolder_fnSetNameOf | 
|  | *  Changes the name of a file object or subfolder, possibly changing its item | 
|  | *  identifier in the process. | 
|  | * | 
|  | * PARAMETERS | 
|  | *  HWND          hwndOwner,  //[in ] Owner window for output | 
|  | *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change | 
|  | *  LPCOLESTR     lpszName,   //[in ] the items new display name | 
|  | *  DWORD         dwFlags,    //[in ] SHGNO formatting flags | 
|  | *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned | 
|  | */ | 
|  | static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface, | 
|  | HWND hwndOwner, | 
|  | LPCITEMIDLIST pidl, | 
|  | LPCOLESTR lpName, | 
|  | DWORD dwFlags, | 
|  | LPITEMIDLIST * pPidlOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1]; | 
|  | LPWSTR ptr; | 
|  | BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); | 
|  |  | 
|  | TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl, | 
|  | debugstr_w (lpName), dwFlags, pPidlOut); | 
|  |  | 
|  | /* build source path */ | 
|  | lstrcpynW(szSrc, This->sPathTarget, MAX_PATH); | 
|  | ptr = PathAddBackslashW (szSrc); | 
|  | if (ptr) | 
|  | _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc)); | 
|  |  | 
|  | /* build destination path */ | 
|  | if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) { | 
|  | lstrcpynW(szDest, This->sPathTarget, MAX_PATH); | 
|  | ptr = PathAddBackslashW (szDest); | 
|  | if (ptr) | 
|  | lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest)); | 
|  | } else | 
|  | lstrcpynW(szDest, lpName, MAX_PATH); | 
|  |  | 
|  | if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) { | 
|  | WCHAR *ext = PathFindExtensionW(szSrc); | 
|  | if(*ext != '\0') { | 
|  | INT len = strlenW(szDest); | 
|  | lstrcpynW(szDest + len, ext, MAX_PATH - len); | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest)); | 
|  |  | 
|  | if (MoveFileW (szSrc, szDest)) { | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | if (pPidlOut) | 
|  | hr = _ILCreateFromPathW(szDest, pPidlOut); | 
|  |  | 
|  | SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, | 
|  | SHCNF_PATHW, szSrc, szDest); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface, | 
|  | GUID * pguid) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | FIXME ("(%p)\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  | static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface, | 
|  | IEnumExtraSearch ** ppenum) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | FIXME ("(%p)\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes, | 
|  | ULONG * pSort, ULONG * pDisplay) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | if (pSort) | 
|  | *pSort = 0; | 
|  | if (pDisplay) | 
|  | *pDisplay = 0; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn, | 
|  | DWORD * pcsFlags) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *pcsFlags = GenericSFHeader[iColumn].pcsFlags; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl, | 
|  | const SHCOLUMNID * pscid, VARIANT * pv) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | FIXME ("(%p)\n", This); | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, | 
|  | UINT iColumn, SHELLDETAILS * psd) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | HRESULT hr = E_FAIL; | 
|  |  | 
|  | TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd); | 
|  |  | 
|  | if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (!pidl) { | 
|  | /* the header titles */ | 
|  | psd->fmt = GenericSFHeader[iColumn].fmt; | 
|  | psd->cxChar = GenericSFHeader[iColumn].cxChar; | 
|  | psd->str.uType = STRRET_CSTR; | 
|  | LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid, | 
|  | psd->str.u.cStr, MAX_PATH); | 
|  | return S_OK; | 
|  | } else { | 
|  | hr = S_OK; | 
|  | psd->str.uType = STRRET_CSTR; | 
|  | /* the data from the pidl */ | 
|  | switch (iColumn) { | 
|  | case 0:                /* name */ | 
|  | hr = IShellFolder_GetDisplayNameOf (iface, pidl, | 
|  | SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); | 
|  | break; | 
|  | case 1:                /* size */ | 
|  | _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH); | 
|  | break; | 
|  | case 2:                /* type */ | 
|  | _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH); | 
|  | break; | 
|  | case 3:                /* date */ | 
|  | _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH); | 
|  | break; | 
|  | case 4:                /* attributes */ | 
|  | _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column, | 
|  | SHCOLUMNID * pscid) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IShellFolder2(iface); | 
|  | FIXME ("(%p)\n", This); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IShellFolder2Vtbl sfvt = | 
|  | { | 
|  | IShellFolder_fnQueryInterface, | 
|  | IShellFolder_fnAddRef, | 
|  | IShellFolder_fnRelease, | 
|  | IShellFolder_fnParseDisplayName, | 
|  | IShellFolder_fnEnumObjects, | 
|  | IShellFolder_fnBindToObject, | 
|  | IShellFolder_fnBindToStorage, | 
|  | IShellFolder_fnCompareIDs, | 
|  | IShellFolder_fnCreateViewObject, | 
|  | IShellFolder_fnGetAttributesOf, | 
|  | IShellFolder_fnGetUIObjectOf, | 
|  | IShellFolder_fnGetDisplayNameOf, | 
|  | IShellFolder_fnSetNameOf, | 
|  | /* ShellFolder2 */ | 
|  | IShellFolder_fnGetDefaultSearchGUID, | 
|  | IShellFolder_fnEnumSearches, | 
|  | IShellFolder_fnGetDefaultColumn, | 
|  | IShellFolder_fnGetDefaultColumnState, | 
|  | IShellFolder_fnGetDetailsEx, | 
|  | IShellFolder_fnGetDetailsOf, | 
|  | IShellFolder_fnMapColumnToSCID | 
|  | }; | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFHelper for IShellFolder implementation | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_AddRef (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | return IUnknown_Release (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFHelper_fnAddFolder | 
|  | * | 
|  | * creates a unique folder name | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  | IEnumIDList *penum; | 
|  | HRESULT hr; | 
|  | WCHAR wszText[MAX_PATH]; | 
|  | WCHAR wszNewFolder[25]; | 
|  | const WCHAR wszFormat[] = {'%','s',' ','%','d',0 }; | 
|  |  | 
|  | TRACE ("(%p)(%p %u)\n", This, pwszName, uLen); | 
|  |  | 
|  | LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder,  sizeof(wszNewFolder)/sizeof(WCHAR)); | 
|  | if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3) | 
|  | return E_POINTER; | 
|  |  | 
|  | lstrcpynW (pwszName, wszNewFolder, uLen); | 
|  |  | 
|  | hr = IShellFolder_fnEnumObjects (_IShellFolder2_ (This), 0, | 
|  | SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum); | 
|  | if (penum) { | 
|  | LPITEMIDLIST pidl; | 
|  | DWORD dwFetched; | 
|  | int i = 1; | 
|  |  | 
|  | next: | 
|  | IEnumIDList_Reset (penum); | 
|  | while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) && | 
|  | dwFetched) { | 
|  | _ILSimpleGetTextW (pidl, wszText, MAX_PATH); | 
|  | if (0 == lstrcmpiW (wszText, pwszName)) { | 
|  | snprintfW (pwszName, uLen, wszFormat, wszNewFolder, i++); | 
|  | if (i > 99) { | 
|  | hr = E_FAIL; | 
|  | break; | 
|  | } | 
|  | goto next; | 
|  | } | 
|  | } | 
|  |  | 
|  | IEnumIDList_Release (penum); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFHelper_fnAddFolder | 
|  | * | 
|  | * adds a new folder. | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName, | 
|  | LPITEMIDLIST * ppidlOut) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  | WCHAR wszNewDir[MAX_PATH]; | 
|  | DWORD bRes; | 
|  | HRESULT hres = E_FAIL; | 
|  |  | 
|  | TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut); | 
|  |  | 
|  | wszNewDir[0] = 0; | 
|  | if (This->sPathTarget) | 
|  | lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH); | 
|  | PathAppendW(wszNewDir, pwszName); | 
|  |  | 
|  | bRes = CreateDirectoryW (wszNewDir, NULL); | 
|  | if (bRes) { | 
|  | SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL); | 
|  |  | 
|  | hres = S_OK; | 
|  |  | 
|  | if (ppidlOut) | 
|  | hres = _ILCreateFromPathW(wszNewDir, ppidlOut); | 
|  | } else { | 
|  | WCHAR wszText[128 + MAX_PATH]; | 
|  | WCHAR wszTempText[128]; | 
|  | WCHAR wszCaption[256]; | 
|  |  | 
|  | /* Cannot Create folder because of permissions */ | 
|  | LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText, | 
|  | sizeof (wszTempText)/sizeof (wszTempText[0])); | 
|  | LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption, | 
|  | sizeof (wszCaption)/sizeof (wszCaption[0])); | 
|  | sprintfW (wszText, wszTempText, wszNewDir); | 
|  | MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION); | 
|  | } | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * build_paths_list | 
|  | * | 
|  | * Builds a list of paths like the one used in SHFileOperation from a table of | 
|  | * PIDLs relative to the given base folder | 
|  | */ | 
|  | static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls) | 
|  | { | 
|  | WCHAR *wszPathsList; | 
|  | WCHAR *wszListPos; | 
|  | int iPathLen; | 
|  | int i; | 
|  |  | 
|  | iPathLen = lstrlenW(wszBasePath); | 
|  | wszPathsList = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1); | 
|  | wszListPos = wszPathsList; | 
|  |  | 
|  | for (i = 0; i < cidl; i++) { | 
|  | if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i])) | 
|  | continue; | 
|  |  | 
|  | lstrcpynW(wszListPos, wszBasePath, MAX_PATH); | 
|  | /* FIXME: abort if path too long */ | 
|  | _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen); | 
|  | wszListPos += lstrlenW(wszListPos)+1; | 
|  | } | 
|  | *wszListPos=0; | 
|  | return wszPathsList; | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFHelper_fnDeleteItems | 
|  | * | 
|  | * deletes items in folder | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  | UINT i; | 
|  | SHFILEOPSTRUCTW op; | 
|  | WCHAR wszPath[MAX_PATH]; | 
|  | WCHAR *wszPathsList; | 
|  | HRESULT ret; | 
|  | WCHAR *wszCurrentPath; | 
|  |  | 
|  | TRACE ("(%p)(%u %p)\n", This, cidl, apidl); | 
|  | if (cidl==0) return S_OK; | 
|  |  | 
|  | if (This->sPathTarget) | 
|  | lstrcpynW(wszPath, This->sPathTarget, MAX_PATH); | 
|  | else | 
|  | wszPath[0] = '\0'; | 
|  | PathAddBackslashW(wszPath); | 
|  | wszPathsList = build_paths_list(wszPath, cidl, apidl); | 
|  |  | 
|  | ZeroMemory(&op, sizeof(op)); | 
|  | op.hwnd = GetActiveWindow(); | 
|  | op.wFunc = FO_DELETE; | 
|  | op.pFrom = wszPathsList; | 
|  | op.fFlags = FOF_ALLOWUNDO; | 
|  | if (SHFileOperationW(&op)) | 
|  | { | 
|  | WARN("SHFileOperation failed\n"); | 
|  | ret = E_FAIL; | 
|  | } | 
|  | else | 
|  | ret = S_OK; | 
|  |  | 
|  | /* we currently need to manually send the notifies */ | 
|  | wszCurrentPath = wszPathsList; | 
|  | for (i = 0; i < cidl; i++) | 
|  | { | 
|  | LONG wEventId; | 
|  |  | 
|  | if (_ILIsFolder(apidl[i])) | 
|  | wEventId = SHCNE_RMDIR; | 
|  | else if (_ILIsValue(apidl[i])) | 
|  | wEventId = SHCNE_DELETE; | 
|  | else | 
|  | continue; | 
|  |  | 
|  | /* check if file exists */ | 
|  | if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES) | 
|  | { | 
|  | LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]); | 
|  | SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL); | 
|  | SHFree(pidl); | 
|  | } | 
|  |  | 
|  | wszCurrentPath += lstrlenW(wszCurrentPath)+1; | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, wszPathsList); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFHelper_fnCopyItems | 
|  | * | 
|  | * copies items to this folder | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl, | 
|  | LPCITEMIDLIST * apidl) | 
|  | { | 
|  | UINT i; | 
|  | IPersistFolder2 *ppf2 = NULL; | 
|  | char szSrcPath[MAX_PATH], | 
|  | szDstPath[MAX_PATH]; | 
|  |  | 
|  | IGenericSFImpl *This = impl_from_ISFHelper(iface); | 
|  |  | 
|  | TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl); | 
|  |  | 
|  | IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2, | 
|  | (LPVOID *) & ppf2); | 
|  | if (ppf2) { | 
|  | LPITEMIDLIST pidl; | 
|  |  | 
|  | if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) { | 
|  | for (i = 0; i < cidl; i++) { | 
|  | SHGetPathFromIDListA (pidl, szSrcPath); | 
|  | PathAddBackslashA (szSrcPath); | 
|  | _ILSimpleGetText (apidl[i], szSrcPath + strlen (szSrcPath), | 
|  | MAX_PATH); | 
|  |  | 
|  | if (!WideCharToMultiByte(CP_ACP, 0, This->sPathTarget, -1, szDstPath, MAX_PATH, NULL, NULL)) | 
|  | szDstPath[0] = '\0'; | 
|  | PathAddBackslashA (szDstPath); | 
|  | _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath), | 
|  | MAX_PATH); | 
|  | MESSAGE ("would copy %s to %s\n", szSrcPath, szDstPath); | 
|  | } | 
|  | SHFree (pidl); | 
|  | } | 
|  | IPersistFolder2_Release (ppf2); | 
|  | } | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const ISFHelperVtbl shvt = | 
|  | { | 
|  | ISFHelper_fnQueryInterface, | 
|  | ISFHelper_fnAddRef, | 
|  | ISFHelper_fnRelease, | 
|  | ISFHelper_fnGetUniqueName, | 
|  | ISFHelper_fnAddFolder, | 
|  | ISFHelper_fnDeleteItems, | 
|  | ISFHelper_fnCopyItems | 
|  | }; | 
|  |  | 
|  | /************************************************************************ | 
|  | * IFSFldr_PersistFolder3_QueryInterface | 
|  | * | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_QueryInterface (IPersistFolder3 * iface, REFIID iid, | 
|  | LPVOID * ppvObj) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj); | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * IFSFldr_PersistFolder3_AddRef | 
|  | * | 
|  | */ | 
|  | static ULONG WINAPI | 
|  | IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_AddRef (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * IFSFldr_PersistFolder3_Release | 
|  | * | 
|  | */ | 
|  | static ULONG WINAPI | 
|  | IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)->(count=%u)\n", This, This->ref); | 
|  |  | 
|  | return IUnknown_Release (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * IFSFldr_PersistFolder3_GetClassID | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | if (!lpClassId) | 
|  | return E_POINTER; | 
|  | *lpClassId = *This->pclsid; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * IFSFldr_PersistFolder3_Initialize | 
|  | * | 
|  | * NOTES | 
|  | *  sPathTarget is not set. Don't know how to handle in a non rooted environment. | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl) | 
|  | { | 
|  | WCHAR wszTemp[MAX_PATH]; | 
|  |  | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)->(%p)\n", This, pidl); | 
|  |  | 
|  | SHFree (This->pidlRoot);     /* free the old pidl */ | 
|  | This->pidlRoot = ILClone (pidl); /* set my pidl */ | 
|  |  | 
|  | SHFree (This->sPathTarget); | 
|  | This->sPathTarget = NULL; | 
|  |  | 
|  | /* set my path */ | 
|  | if (SHGetPathFromIDListW (pidl, wszTemp)) { | 
|  | int len = strlenW(wszTemp); | 
|  | This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR)); | 
|  | if (!This->sPathTarget) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); | 
|  | } | 
|  |  | 
|  | TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget)); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IFSFldr_PersistFolder3_GetCurFolder | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface, | 
|  | LPITEMIDLIST * pidl) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)->(%p)\n", This, pidl); | 
|  |  | 
|  | if (!pidl) return E_POINTER; | 
|  | *pidl = ILClone (This->pidlRoot); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | * IFSFldr_PersistFolder3_InitializeEx | 
|  | * | 
|  | * FIXME: error handling | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface, | 
|  | IBindCtx * pbc, LPCITEMIDLIST pidlRoot, | 
|  | const PERSIST_FOLDER_TARGET_INFO * ppfti) | 
|  | { | 
|  | WCHAR wszTemp[MAX_PATH]; | 
|  |  | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  |  | 
|  | TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti); | 
|  | if (ppfti) | 
|  | TRACE ("--%p %s %s 0x%08x 0x%08x\n", | 
|  | ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName), | 
|  | debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes, | 
|  | ppfti->csidl); | 
|  |  | 
|  | pdump (pidlRoot); | 
|  | if (ppfti && ppfti->pidlTargetFolder) | 
|  | pdump (ppfti->pidlTargetFolder); | 
|  |  | 
|  | if (This->pidlRoot) | 
|  | __SHFreeAndNil (&This->pidlRoot);    /* free the old */ | 
|  | if (This->sPathTarget) | 
|  | __SHFreeAndNil (&This->sPathTarget); | 
|  |  | 
|  | /* | 
|  | * Root path and pidl | 
|  | */ | 
|  | This->pidlRoot = ILClone (pidlRoot); | 
|  |  | 
|  | /* | 
|  | *  the target folder is specified in csidl OR pidlTargetFolder OR | 
|  | *  szTargetParsingName | 
|  | */ | 
|  | if (ppfti) { | 
|  | if (ppfti->csidl != -1) { | 
|  | if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl, | 
|  | ppfti->csidl & CSIDL_FLAG_CREATE)) { | 
|  | int len = strlenW(wszTemp); | 
|  | This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR)); | 
|  | if (!This->sPathTarget) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); | 
|  | } | 
|  | } else if (ppfti->szTargetParsingName[0]) { | 
|  | int len = strlenW(ppfti->szTargetParsingName); | 
|  | This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR)); | 
|  | if (!This->sPathTarget) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy(This->sPathTarget, ppfti->szTargetParsingName, | 
|  | (len + 1) * sizeof(WCHAR)); | 
|  | } else if (ppfti->pidlTargetFolder) { | 
|  | if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) { | 
|  | int len = strlenW(wszTemp); | 
|  | This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR)); | 
|  | if (!This->sPathTarget) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget)); | 
|  | pdump (This->pidlRoot); | 
|  | return (This->sPathTarget) ? S_OK : E_FAIL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface, | 
|  | PERSIST_FOLDER_TARGET_INFO * ppfti) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IPersistFolder3(iface); | 
|  | FIXME ("(%p)->(%p)\n", This, ppfti); | 
|  | ZeroMemory (ppfti, sizeof (ppfti)); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3 = | 
|  | { | 
|  | IFSFldr_PersistFolder3_QueryInterface, | 
|  | IFSFldr_PersistFolder3_AddRef, | 
|  | IFSFldr_PersistFolder3_Release, | 
|  | IFSFldr_PersistFolder3_GetClassID, | 
|  | IFSFldr_PersistFolder3_Initialize, | 
|  | IFSFldr_PersistFolder3_fnGetCurFolder, | 
|  | IFSFldr_PersistFolder3_InitializeEx, | 
|  | IFSFldr_PersistFolder3_GetFolderTargetInfo | 
|  | }; | 
|  |  | 
|  | /**************************************************************************** | 
|  | * ISFDropTarget implementation | 
|  | */ | 
|  | static BOOL | 
|  | ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState, | 
|  | LPDWORD pdwEffect) | 
|  | { | 
|  | DWORD dwEffect = *pdwEffect; | 
|  |  | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | *pdwEffect = DROPEFFECT_NONE; | 
|  |  | 
|  | if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */ | 
|  | *pdwEffect = KeyStateToDropEffect (dwKeyState); | 
|  |  | 
|  | /* ... matches the desired effect ? */ | 
|  | if (dwEffect & *pdwEffect) { | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | return IUnknown_AddRef (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | return IUnknown_Release (This->pUnkOuter); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject, | 
|  | DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) | 
|  | { | 
|  | FORMATETC fmt; | 
|  |  | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject); | 
|  |  | 
|  | InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL); | 
|  |  | 
|  | This->fAcceptFmt = (S_OK == IDataObject_QueryGetData (pDataObject, &fmt)) ? | 
|  | TRUE : FALSE; | 
|  |  | 
|  | ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt, | 
|  | DWORD * pdwEffect) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | if (!pdwEffect) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | TRACE ("(%p)\n", This); | 
|  |  | 
|  | This->fAcceptFmt = FALSE; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject, | 
|  | DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) | 
|  | { | 
|  | IGenericSFImpl *This = impl_from_IDropTarget(iface); | 
|  |  | 
|  | FIXME ("(%p) object dropped\n", This); | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IDropTargetVtbl dtvt = { | 
|  | ISFDropTarget_QueryInterface, | 
|  | ISFDropTarget_AddRef, | 
|  | ISFDropTarget_Release, | 
|  | ISFDropTarget_DragEnter, | 
|  | ISFDropTarget_DragOver, | 
|  | ISFDropTarget_DragLeave, | 
|  | ISFDropTarget_Drop | 
|  | }; |