/* * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "wine/port.h" #include #include #include #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "winerror.h" #include "winbase.h" #include "winreg.h" #include "ole2.h" #include "shlguid.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 { ICOM_VFIELD (IUnknown); DWORD ref; ICOM_VTABLE (IShellFolder2) * lpvtblShellFolder; ICOM_VTABLE (IPersistFolder3) * lpvtblPersistFolder3; ICOM_VTABLE (IDropTarget) * lpvtblDropTarget; ICOM_VTABLE (ISFHelper) * lpvtblSFHelper; IUnknown *pUnkOuter; /* used for aggregation */ CLSID *pclsid; /* both paths are parsible from the desktop */ LPSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */ LPITEMIDLIST pidlRoot; /* absolute pidl */ int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */ UINT cfShellIDList; /* clipboardformat for IDropTarget */ BOOL fAcceptFmt; /* flag for pending Drop */ } IGenericSFImpl; static struct ICOM_VTABLE (IUnknown) unkvt; static struct ICOM_VTABLE (IShellFolder2) sfvt; static struct ICOM_VTABLE (IPersistFolder3) vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */ static struct ICOM_VTABLE (IDropTarget) dtvt; static struct ICOM_VTABLE (ISFHelper) shvt; #define _IShellFolder2_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblShellFolder))) #define _ICOM_THIS_From_IShellFolder2(class, name) class* This = (class*)(((char*)name)-_IShellFolder2_Offset); #define _IPersistFolder2_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder3))) #define _ICOM_THIS_From_IPersistFolder2(class, name) class* This = (class*)(((char*)name)-_IPersistFolder2_Offset); #define _IPersistFolder3_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder3))) #define _ICOM_THIS_From_IPersistFolder3(class, name) class* This = (class*)(((char*)name)-_IPersistFolder3_Offset); #define _IDropTarget_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblDropTarget))) #define _ICOM_THIS_From_IDropTarget(class, name) class* This = (class*)(((char*)name)-_IDropTarget_Offset); #define _ISFHelper_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblSFHelper))) #define _ICOM_THIS_From_ISFHelper(class, name) class* This = (class*)(((char*)name)-_ISFHelper_Offset); /* converts This to a interface pointer */ #define _IUnknown_(This) (IUnknown*)&(This->lpVtbl) #define _IShellFolder_(This) (IShellFolder*)&(This->lpvtblShellFolder) #define _IShellFolder2_(This) (IShellFolder2*)&(This->lpvtblShellFolder) #define _IPersist_(This) (IPersist*)&(This->lpvtblPersistFolder3) #define _IPersistFolder_(This) (IPersistFolder*)&(This->lpvtblPersistFolder3) #define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpvtblPersistFolder3) #define _IPersistFolder3_(This) (IPersistFolder3*)&(This->lpvtblPersistFolder3) #define _IDropTarget_(This) (IDropTarget*)&(This->lpvtblDropTarget) #define _ISFHelper_(This) (ISFHelper*)&(This->lpvtblSFHelper) /************************************************************************** * registers clipboardformat once */ static void SF_RegisterClipFmt (IGenericSFImpl * This) { TRACE ("(%p)\n", This); if (!This->cfShellIDList) { This->cfShellIDList = RegisterClipboardFormatA (CFSTR_SHELLIDLIST); } } /************************************************************************** * we need a separate IUnknown to handle aggregation * (inner IUnknown) */ static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj) { ICOM_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) { ICOM_THIS (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); return ++(This->ref); } static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface) { ICOM_THIS (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); if (!--(This->ref)) { TRACE ("-- destroying IShellFolder(%p)\n", This); if (This->pidlRoot) SHFree (This->pidlRoot); if (This->sPathTarget) SHFree (This->sPathTarget); LocalFree ((HLOCAL) This); return 0; } return This->ref; } static ICOM_VTABLE (IUnknown) unkvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IUnknown_fnQueryInterface, IUnknown_fnAddRef, IUnknown_fnRelease, }; static 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 = (IGenericSFImpl *) LocalAlloc (GMEM_ZEROINIT, sizeof (IGenericSFImpl)); if (!sf) return E_OUTOFMEMORY; sf->ref = 0; ICOM_VTBL (sf) = &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 (!SUCCEEDED (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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_AddRef (This->pUnkOuter); } /************************************************************************** * IShellFolder_fnRelease */ static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_Release (This->pUnkOuter); } /************************************************************************** * IShellFolder_fnParseDisplayName * PARAMETERS * HWND hwndOwner, //[in ] Parent window for any message's * LPBC pbc, //[in ] reserved * LPOLESTR lpszDisplayName,//[in ] "Unicode" displayname. * ULONG* pchEaten, //[out] (unicode) characters processed * LPITEMIDLIST* ppidl, //[out] complex pidl to item * ULONG* 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 -> chrash * lpszDisplayName="" -> returns mycoputer-pidl * * FIXME: * pdwAttributes: not set * pchEaten: not set like in windows */ static HRESULT WINAPI IShellFolder_fnParseDisplayName (IShellFolder2 * iface, HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName, DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) HRESULT hr = E_OUTOFMEMORY; LPCWSTR szNext = NULL; WCHAR szElement[MAX_PATH]; CHAR szTempA[MAX_PATH], szPath[MAX_PATH]; LPITEMIDLIST pidlTemp = NULL; TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", This, hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName), pchEaten, ppidl, pdwAttributes); if (!lpszDisplayName || !ppidl) return E_INVALIDARG; if (pchEaten) *pchEaten = 0; /* strange but like the original */ if (*lpszDisplayName) { /* get the next element */ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH); /* build the full pathname to the element */ WideCharToMultiByte (CP_ACP, 0, szElement, -1, szTempA, MAX_PATH, NULL, NULL); lstrcpyA (szPath, This->sPathTarget); PathAddBackslashA (szPath); lstrcatA (szPath, szTempA); /* get the pidl */ pidlTemp = SHSimpleIDListFromPathA (szPath); if (pidlTemp) { if (szNext && *szNext) { /* try to analyse the next element */ hr = SHELL32_ParseNextElement (hwndOwner, iface, &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); } else { /* it's the last element */ if (pdwAttributes && *pdwAttributes) { SHELL32_GetItemAttributes (_IShellFolder_ (This), pidlTemp, pdwAttributes); } hr = S_OK; } } } if (!hr) *ppidl = pidlTemp; else *ppidl = NULL; TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n", This, hwndOwner, dwFlags, ppEnumIDList); *ppEnumIDList = IEnumIDList_Constructor (This->sPathTarget, dwFlags, EIDL_FILE); 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 ] reserved * REFIID riid, //[in ] Initial Interface * LPVOID* ppvObject //[out] Interface* */ static HRESULT WINAPI IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbcReserved, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) HRESULT hr = S_OK; TRACE ("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n", This, cidl, apidl, *rgfInOut); if ((!cidl) || (!apidl) || (!rgfInOut)) return E_INVALIDARG; while (cidl > 0 && *apidl) { pdump (*apidl); SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut); apidl++; cidl--; } TRACE ("-- result=0x%08lx\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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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 { hr = E_NOINTERFACE; } if (!pObj) hr = E_OUTOFMEMORY; *ppvOut = pObj; } TRACE ("(%p)->hr=0x%08lx\n", This, hr); return hr; } /************************************************************************** * 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) CHAR szPath[MAX_PATH] = ""; int len = 0; BOOL bSimplePidl; TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet); pdump (pidl); if (!pidl || !strRet) return E_INVALIDARG; bSimplePidl = _ILIsPidlSimple (pidl); /* take names of special folders only if its only this folder */ if (_ILIsSpecialFolder (pidl)) { if (bSimplePidl) { _ILSimpleGetText (pidl, szPath, MAX_PATH); /* append my own path */ } else { FIXME ("special pidl\n"); } } else { if (!(dwFlags & SHGDN_INFOLDER) && (dwFlags & SHGDN_FORPARSING) && This->sPathTarget) { lstrcpyA (szPath, This->sPathTarget); /* get path to root */ PathAddBackslashA (szPath); len = lstrlenA (szPath); } _ILSimpleGetText (pidl, szPath + len, MAX_PATH - len); /* append my own path */ /* MSDN also mentions SHGDN_FOREDITING, which isn't defined in wine */ if (!_ILIsFolder (pidl) && !(dwFlags & SHGDN_FORPARSING) && ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) { HKEY hKey; DWORD dwData; DWORD dwDataSize = sizeof (DWORD); BOOL doHide = 0; /* The default value is FALSE (win98 at least) */ /* XXX should it do this only for known file types? -- that would make it even slower! */ /* XXX That's what the prompt says!! */ if (!RegCreateKeyExA (HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) { if (!RegQueryValueExA (hKey, "HideFileExt", 0, 0, (LPBYTE) & dwData, &dwDataSize)) doHide = dwData; RegCloseKey (hKey); } if (doHide && szPath[0] != '.') PathRemoveExtensionA (szPath); } } if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl) { /* go deeper if needed */ PathAddBackslashA (szPath); len = lstrlenA (szPath); if (!SUCCEEDED (SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags | SHGDN_INFOLDER, szPath + len, MAX_PATH - len))) return E_OUTOFMEMORY; } strRet->uType = STRRET_CSTR; lstrcpynA (strRet->u.cStr, szPath, MAX_PATH); TRACE ("-- (%p)->(%s)\n", This, szPath); return S_OK; } /************************************************************************** * 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, /*simple pidl */ LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) char szSrc[MAX_PATH], szDest[MAX_PATH]; int len; BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This, hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut); /* build source path */ if (dwFlags & SHGDN_INFOLDER) { strcpy (szSrc, This->sPathTarget); PathAddBackslashA (szSrc); len = strlen (szSrc); _ILSimpleGetText (pidl, szSrc + len, MAX_PATH - len); } else { SHGetPathFromIDListA (pidl, szSrc); } /* build destination path */ strcpy (szDest, This->sPathTarget); PathAddBackslashA (szDest); len = strlen (szDest); WideCharToMultiByte (CP_ACP, 0, lpName, -1, szDest + len, MAX_PATH - len, NULL, NULL); szDest[MAX_PATH - 1] = 0; TRACE ("src=%s dest=%s\n", szSrc, szDest); if (MoveFileA (szSrc, szDest)) { if (pPidlOut) *pPidlOut = SHSimpleIDListFromPathA (szDest); SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, SHCNF_PATHA, szSrc, szDest); return S_OK; } return E_FAIL; } static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 * iface, GUID * pguid) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) FIXME ("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface, IEnumExtraSearch ** ppenum) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) FIXME ("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes, ULONG * pSort, ULONG * pDisplay) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) FIXME ("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, 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 { /* 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; } hr = S_OK; psd->str.uType = STRRET_CSTR; } return hr; } static HRESULT WINAPI IShellFolder_fnMapNameToSCID (IShellFolder2 * iface, LPCWSTR pwszName, SHCOLUMNID * pscid) { _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface) FIXME ("(%p)\n", This); return E_NOTIMPL; } static ICOM_VTABLE (IShellFolder2) sfvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 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_fnMapNameToSCID }; /**************************************************************************** * ISFHelper for IShellFolder implementation */ static HRESULT WINAPI ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj); } static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_AddRef (This->pUnkOuter); } static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface); TRACE ("(%p)\n", This); return IUnknown_Release (This->pUnkOuter); } /**************************************************************************** * ISFHelper_fnAddFolder * * creates a unique folder name */ static HRESULT WINAPI ISFHelper_fnGetUniqueName (ISFHelper * iface, LPSTR lpName, UINT uLen) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface) IEnumIDList *penum; HRESULT hr; char szText[MAX_PATH]; char *szNewFolder = "New Folder"; TRACE ("(%p)(%s %u)\n", This, lpName, uLen); if (uLen < strlen (szNewFolder) + 4) return E_POINTER; strcpy (lpName, szNewFolder); 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) { _ILSimpleGetText (pidl, szText, MAX_PATH); if (0 == strcasecmp (szText, lpName)) { sprintf (lpName, "%s %d", szNewFolder, 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, LPCSTR lpName, LPITEMIDLIST * ppidlOut) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface) char lpstrNewDir[MAX_PATH]; DWORD bRes; HRESULT hres = E_FAIL; TRACE ("(%p)(%s %p)\n", This, lpName, ppidlOut); strcpy (lpstrNewDir, This->sPathTarget); PathAddBackslashA (lpstrNewDir); strcat (lpstrNewDir, lpName); bRes = CreateDirectoryA (lpstrNewDir, NULL); if (bRes) { LPITEMIDLIST pidl, pidlitem; pidlitem = SHSimpleIDListFromPathA (lpstrNewDir); pidl = ILCombine (This->pidlRoot, pidlitem); SHChangeNotify (SHCNE_MKDIR, SHCNF_IDLIST, pidl, NULL); SHFree (pidl); if (ppidlOut) *ppidlOut = pidlitem; hres = S_OK; } else { char lpstrText[128 + MAX_PATH]; char lpstrTempText[128]; char lpstrCaption[256]; /* Cannot Create folder because of permissions */ LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_DENIED, lpstrTempText, sizeof (lpstrTempText)); LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, lpstrCaption, sizeof (lpstrCaption)); sprintf (lpstrText, lpstrTempText, lpstrNewDir); MessageBoxA (hwnd, lpstrText, lpstrCaption, MB_OK | MB_ICONEXCLAMATION); } return hres; } /**************************************************************************** * ISFHelper_fnDeleteItems * * deletes items in folder */ static HRESULT WINAPI ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl) { _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface) UINT i; char szPath[MAX_PATH]; BOOL bConfirm = TRUE; TRACE ("(%p)(%u %p)\n", This, cidl, apidl); /* deleting multiple items so give a slightly different warning */ if (cidl != 1) { char tmp[8]; snprintf (tmp, sizeof (tmp), "%d", cidl); if (!SHELL_ConfirmDialog(ASK_DELETE_MULTIPLE_ITEM, tmp)) return E_FAIL; bConfirm = FALSE; } for (i = 0; i < cidl; i++) { strcpy (szPath, This->sPathTarget); PathAddBackslashA (szPath); _ILSimpleGetText (apidl[i], szPath + strlen (szPath), MAX_PATH); if (_ILIsFolder (apidl[i])) { LPITEMIDLIST pidl; TRACE ("delete %s\n", szPath); if (!SHELL_DeleteDirectoryA (szPath, bConfirm)) { TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm); return E_FAIL; } pidl = ILCombine (This->pidlRoot, apidl[i]); SHChangeNotify (SHCNE_RMDIR, SHCNF_IDLIST, pidl, NULL); SHFree (pidl); } else if (_ILIsValue (apidl[i])) { LPITEMIDLIST pidl; TRACE ("delete %s\n", szPath); if (!SHELL_DeleteFileA (szPath, bConfirm)) { TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm); return E_FAIL; } pidl = ILCombine (This->pidlRoot, apidl[i]); SHChangeNotify (SHCNE_DELETE, SHCNF_IDLIST, pidl, NULL); SHFree (pidl); } } return S_OK; } /**************************************************************************** * 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]; _ICOM_THIS_From_ISFHelper (IGenericSFImpl, 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); strcpy (szDstPath, This->sPathTarget); 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 ICOM_VTABLE (ISFHelper) shvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 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) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)\n", This); return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj); } /************************************************************************ * IFSFldr_PersistFolder3_AddRef * */ static ULONG WINAPI IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_AddRef (This->pUnkOuter); } /************************************************************************ * IFSFldr_PersistFolder3_Release * */ static ULONG WINAPI IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)->(count=%lu)\n", This, This->ref); return IUnknown_Release (This->pUnkOuter); } /************************************************************************ * IFSFldr_PersistFolder3_GetClassID */ static HRESULT WINAPI IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, 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) { char sTemp[MAX_PATH]; _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)->(%p)\n", This, pidl); if (This->pidlRoot) SHFree (This->pidlRoot); /* free the old pidl */ This->pidlRoot = ILClone (pidl); /* set my pidl */ if (This->sPathTarget) SHFree (This->sPathTarget); /* set my path */ if (SHGetPathFromIDListA (pidl, sTemp)) { This->sPathTarget = SHAlloc (strlen (sTemp) + 1); strcpy (This->sPathTarget, sTemp); } TRACE ("--(%p)->(%s)\n", This, This->sPathTarget); return S_OK; } /************************************************************************** * IFSFldr_PersistFolder3_GetCurFolder */ static HRESULT WINAPI IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface, LPITEMIDLIST * pidl) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)->(%p)\n", This, pidl); if (!pidl) return E_POINTER; *pidl = ILClone (This->pidlRoot); return S_OK; } /************************************************************************** * IFSFldr_PersistFolder3_InitializeEx * * FIXME: errorhandling */ static HRESULT WINAPI IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface, IBindCtx * pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO * ppfti) { char sTemp[MAX_PATH]; _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti); if (ppfti) TRACE ("--%p %s %s 0x%08lx 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 spezified in csidl OR pidlTargetFolder OR szTargetParsingName */ if (ppfti) { if (ppfti->csidl != -1) { if (SHGetSpecialFolderPathA (0, sTemp, ppfti->csidl, ppfti->csidl & CSIDL_FLAG_CREATE)) { __SHCloneStrA (&This->sPathTarget, sTemp); } } else if (ppfti->szTargetParsingName[0]) { __SHCloneStrWtoA (&This->sPathTarget, ppfti->szTargetParsingName); } else if (ppfti->pidlTargetFolder) { if (SHGetPathFromIDListA (ppfti->pidlTargetFolder, sTemp)) { __SHCloneStrA (&This->sPathTarget, sTemp); } } } TRACE ("--(%p)->(target=%s)\n", This, debugstr_a (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) { _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface); FIXME ("(%p)->(%p)\n", This, ppfti); ZeroMemory (ppfti, sizeof (ppfti)); return E_NOTIMPL; } static ICOM_VTABLE (IPersistFolder3) vt_FSFldr_PersistFolder3 = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE 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; _ICOM_THIS_From_IDropTarget (IGenericSFImpl, 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) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface); TRACE ("(%p)\n", This); return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj); } static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface); TRACE ("(%p)\n", This); return IUnknown_AddRef (This->pUnkOuter); } static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, 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; _ICOM_THIS_From_IDropTarget (IGenericSFImpl, 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) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, 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) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, 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) { _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface); FIXME ("(%p) object dropped\n", This); return E_NOTIMPL; } static struct ICOM_VTABLE (IDropTarget) dtvt = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE ISFDropTarget_QueryInterface, ISFDropTarget_AddRef, ISFDropTarget_Release, ISFDropTarget_DragEnter, ISFDropTarget_DragOver, ISFDropTarget_DragLeave, ISFDropTarget_Drop };