shell32: COM clean up for IPersistFolder3 in ShellFSFolder.
[wine.git] / dlls / shell32 / shfldr_fs.c
blobf52c1923b048ede072e988b61c3a291720e8f876
2 /*
3 * file system folder
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "wingdi.h"
40 #include "winuser.h"
42 #include "ole2.h"
43 #include "shlguid.h"
45 #include "pidl.h"
46 #include "undocshell.h"
47 #include "shell32_main.h"
48 #include "shresdef.h"
49 #include "shlwapi.h"
50 #include "shellfolder.h"
51 #include "wine/debug.h"
52 #include "debughlp.h"
53 #include "shfldr.h"
55 WINE_DEFAULT_DEBUG_CHANNEL (shell);
57 /***********************************************************************
58 * IShellFolder implementation
61 typedef struct {
62 IUnknown IUnknown_inner;
63 LONG ref;
64 IShellFolder2 IShellFolder2_iface;
65 IPersistFolder3 IPersistFolder3_iface;
66 const IDropTargetVtbl *lpvtblDropTarget;
67 const ISFHelperVtbl *lpvtblSFHelper;
68 IUnknown *outer_unk;
70 CLSID *pclsid;
72 /* both paths are parsible from the desktop */
73 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
75 LPITEMIDLIST pidlRoot; /* absolute pidl */
77 UINT cfShellIDList; /* clipboardformat for IDropTarget */
78 BOOL fAcceptFmt; /* flag for pending Drop */
79 } IGenericSFImpl;
81 static const IShellFolder2Vtbl sfvt;
82 static const IPersistFolder3Vtbl pfvt;
83 static const IDropTargetVtbl dtvt;
84 static const ISFHelperVtbl shvt;
86 static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
88 return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
91 static inline IGenericSFImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
93 return CONTAINING_RECORD(iface, IGenericSFImpl, IShellFolder2_iface);
96 static inline IGenericSFImpl *impl_from_IPersistFolder3(IPersistFolder3 *iface)
98 return CONTAINING_RECORD(iface, IGenericSFImpl, IPersistFolder3_iface);
101 static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface )
103 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget));
106 static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface )
108 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
113 converts This to an interface pointer
115 #define _IDropTarget_(This) (&(This)->lpvtblDropTarget)
116 #define _ISFHelper_(This) (&(This)->lpvtblSFHelper)
118 /**************************************************************************
119 * registers clipboardformat once
121 static void SF_RegisterClipFmt (IGenericSFImpl * This)
123 TRACE ("(%p)\n", This);
125 if (!This->cfShellIDList) {
126 This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
130 /**************************************************************************
131 * inner IUnknown
133 static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
135 IGenericSFImpl *This = impl_from_IUnknown(iface);
137 TRACE("(%p)->(%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
139 *ppvObj = NULL;
141 if (IsEqualIID (riid, &IID_IUnknown))
142 *ppvObj = &This->IUnknown_inner;
143 else if (IsEqualIID(riid, &IID_IShellFolder) || IsEqualIID(riid, &IID_IShellFolder2))
144 *ppvObj = &This->IShellFolder2_iface;
145 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IPersistFolder) ||
146 IsEqualIID(riid, &IID_IPersistFolder2) || IsEqualIID(riid, &IID_IPersistFolder3))
147 *ppvObj = &This->IPersistFolder3_iface;
148 else if (IsEqualIID (riid, &IID_ISFHelper))
149 *ppvObj = _ISFHelper_ (This);
150 else if (IsEqualIID (riid, &IID_IDropTarget)) {
151 *ppvObj = _IDropTarget_ (This);
152 SF_RegisterClipFmt (This);
155 if (*ppvObj) {
156 IUnknown_AddRef((IUnknown *)*ppvObj);
157 TRACE ("-- Interface = %p\n", *ppvObj);
158 return S_OK;
160 TRACE ("-- Interface: E_NOINTERFACE\n");
161 return E_NOINTERFACE;
164 static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface)
166 IGenericSFImpl *This = impl_from_IUnknown(iface);
167 ULONG ref = InterlockedIncrement(&This->ref);
169 TRACE("(%p) ref=%d\n", This, ref);
171 return ref;
174 static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface)
176 IGenericSFImpl *This = impl_from_IUnknown(iface);
177 ULONG ref = InterlockedDecrement(&This->ref);
179 TRACE("(%p) ref=%d\n", This, ref);
181 if (!ref) {
182 TRACE("-- destroying IShellFolder(%p)\n", This);
184 SHFree(This->pidlRoot);
185 SHFree(This->sPathTarget);
186 LocalFree(This);
188 return ref;
191 static const IUnknownVtbl unkvt =
193 IUnknown_fnQueryInterface,
194 IUnknown_fnAddRef,
195 IUnknown_fnRelease,
198 static const shvheader GenericSFHeader[] = {
199 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
200 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
201 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
202 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
203 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
206 #define GENERICSHELLVIEWCOLUMNS 5
208 /**************************************************************************
209 * IFSFolder_Constructor
211 * NOTES
212 * creating undocumented ShellFS_Folder as part of an aggregation
213 * {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
216 HRESULT WINAPI
217 IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
219 IGenericSFImpl *sf;
221 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
223 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
224 return CLASS_E_NOAGGREGATION;
225 sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
226 if (!sf)
227 return E_OUTOFMEMORY;
229 sf->ref = 0;
230 sf->IUnknown_inner.lpVtbl = &unkvt;
231 sf->IShellFolder2_iface.lpVtbl = &sfvt;
232 sf->IPersistFolder3_iface.lpVtbl = &pfvt;
233 sf->lpvtblDropTarget = &dtvt;
234 sf->lpvtblSFHelper = &shvt;
235 sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
236 sf->outer_unk = pUnkOuter ? pUnkOuter : &sf->IUnknown_inner;
238 if (FAILED(IUnknown_QueryInterface(&sf->IUnknown_inner, riid, ppv))) {
239 IUnknown_Release(&sf->IUnknown_inner);
240 return E_NOINTERFACE;
243 TRACE ("--%p\n", *ppv);
244 return S_OK;
247 /**************************************************************************
248 * IShellFolder_fnQueryInterface
250 static HRESULT WINAPI IShellFolder_fnQueryInterface(IShellFolder2 *iface, REFIID riid,
251 void **ppvObj)
253 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
255 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
258 /**************************************************************************
259 * IShellFolder_AddRef
261 static ULONG WINAPI IShellFolder_fnAddRef(IShellFolder2 *iface)
263 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
265 return IUnknown_AddRef(This->outer_unk);
268 /**************************************************************************
269 * IShellFolder_fnRelease
271 static ULONG WINAPI IShellFolder_fnRelease(IShellFolder2 *iface)
273 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
275 return IUnknown_Release(This->outer_unk);
278 /**************************************************************************
279 * SHELL32_CreatePidlFromBindCtx [internal]
281 * If the caller bound File System Bind Data, assume it is the
282 * find data for the path.
283 * This allows binding of paths that don't exist.
285 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
287 static WCHAR szfsbc[] = {
288 'F','i','l','e',' ','S','y','s','t','e','m',' ',
289 'B','i','n','d',' ','D','a','t','a',0 };
290 IFileSystemBindData *fsbd = NULL;
291 LPITEMIDLIST pidl = NULL;
292 IUnknown *unk = NULL;
293 HRESULT r;
295 TRACE("%p %s\n", pbc, debugstr_w(path));
297 if (!pbc)
298 return NULL;
300 /* see if the caller bound File System Bind Data */
301 r = IBindCtx_GetObjectParam( pbc, szfsbc, &unk );
302 if (FAILED(r))
303 return NULL;
305 r = IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
306 if (SUCCEEDED(r))
308 WIN32_FIND_DATAW wfd;
310 r = IFileSystemBindData_GetFindData( fsbd, &wfd );
311 if (SUCCEEDED(r))
313 lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
314 pidl = _ILCreateFromFindDataW( &wfd );
316 IFileSystemBindData_Release( fsbd );
318 IUnknown_Release( unk );
320 return pidl;
323 /**************************************************************************
324 * IShellFolder_ParseDisplayName {SHELL32}
326 * Parse a display name.
328 * PARAMS
329 * hwndOwner [in] Parent window for any message's
330 * pbc [in] optional FileSystemBindData context
331 * lpszDisplayName [in] Unicode displayname.
332 * pchEaten [out] (unicode) characters processed
333 * ppidl [out] complex pidl to item
334 * pdwAttributes [out] items attributes
336 * NOTES
337 * Every folder tries to parse only its own (the leftmost) pidl and creates a
338 * subfolder to evaluate the remaining parts.
339 * Now we can parse into namespaces implemented by shell extensions
341 * Behaviour on win98: lpszDisplayName=NULL -> crash
342 * lpszDisplayName="" -> returns mycoputer-pidl
344 * FIXME
345 * pdwAttributes is not set
346 * pchEaten is not set like in windows
348 static HRESULT WINAPI
349 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
350 HWND hwndOwner,
351 LPBC pbc,
352 LPOLESTR lpszDisplayName,
353 DWORD * pchEaten, LPITEMIDLIST * ppidl,
354 DWORD * pdwAttributes)
356 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
358 HRESULT hr = E_INVALIDARG;
359 LPCWSTR szNext = NULL;
360 WCHAR szElement[MAX_PATH];
361 WCHAR szPath[MAX_PATH];
362 LPITEMIDLIST pidlTemp = NULL;
363 DWORD len;
365 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
366 This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
367 pchEaten, ppidl, pdwAttributes);
369 if (!lpszDisplayName || !ppidl)
370 return E_INVALIDARG;
372 if (pchEaten)
373 *pchEaten = 0; /* strange but like the original */
375 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
376 if (!pidlTemp && *lpszDisplayName)
378 /* get the next element */
379 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
381 /* build the full pathname to the element */
382 lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1);
383 PathAddBackslashW(szPath);
384 len = lstrlenW(szPath);
385 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
387 /* get the pidl */
388 hr = _ILCreateFromPathW(szPath, &pidlTemp);
390 if (SUCCEEDED(hr)) {
391 if (szNext && *szNext) {
392 /* try to analyse the next element */
393 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
394 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
395 } else {
396 /* it's the last element */
397 if (pdwAttributes && *pdwAttributes) {
398 hr = SHELL32_GetItemAttributes((IShellFolder *)&This->IShellFolder2_iface,
399 pidlTemp, pdwAttributes);
405 if (SUCCEEDED(hr))
406 *ppidl = pidlTemp;
407 else
408 *ppidl = NULL;
410 TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", This, *ppidl, hr);
412 return hr;
415 /**************************************************************************
416 * IShellFolder_fnEnumObjects
417 * PARAMETERS
418 * HWND hwndOwner, //[in ] Parent Window
419 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
420 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
422 static HRESULT WINAPI
423 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
424 DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
426 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
427 IEnumIDListImpl *list;
429 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner,
430 dwFlags, ppEnumIDList);
432 if (!(list = IEnumIDList_Constructor()))
433 return E_OUTOFMEMORY;
434 CreateFolderEnumList(list, This->sPathTarget, dwFlags);
435 *ppEnumIDList = &list->IEnumIDList_iface;
437 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
439 return S_OK;
442 /**************************************************************************
443 * IShellFolder_fnBindToObject
444 * PARAMETERS
445 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
446 * LPBC pbc, //[in ] optional FileSystemBindData context
447 * REFIID riid, //[in ] Initial Interface
448 * LPVOID* ppvObject //[out] Interface*
450 static HRESULT WINAPI
451 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
452 LPBC pbc, REFIID riid, LPVOID * ppvOut)
454 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
456 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
457 shdebugstr_guid (riid), ppvOut);
459 return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid,
460 ppvOut);
463 /**************************************************************************
464 * IShellFolder_fnBindToStorage
465 * PARAMETERS
466 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
467 * LPBC pbc, //[in ] reserved
468 * REFIID riid, //[in ] Initial storage interface
469 * LPVOID* ppvObject //[out] Interface* returned
471 static HRESULT WINAPI
472 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
473 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
475 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
477 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
478 shdebugstr_guid (riid), ppvOut);
480 *ppvOut = NULL;
481 return E_NOTIMPL;
484 /**************************************************************************
485 * IShellFolder_fnCompareIDs
488 static HRESULT WINAPI
489 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
490 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
492 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
494 int nReturn;
496 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
497 nReturn = SHELL32_CompareIDs(&This->IShellFolder2_iface, lParam, pidl1, pidl2);
498 TRACE ("-- %i\n", nReturn);
499 return nReturn;
502 /**************************************************************************
503 * IShellFolder_fnCreateViewObject
505 static HRESULT WINAPI
506 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
507 REFIID riid, LPVOID * ppvOut)
509 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
511 LPSHELLVIEW pShellView;
512 HRESULT hr = E_INVALIDARG;
514 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
515 ppvOut);
517 if (ppvOut) {
518 *ppvOut = NULL;
520 if (IsEqualIID (riid, &IID_IDropTarget)) {
521 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget, ppvOut);
522 } else if (IsEqualIID (riid, &IID_IContextMenu)) {
523 FIXME ("IContextMenu not implemented\n");
524 hr = E_NOTIMPL;
525 } else if (IsEqualIID (riid, &IID_IShellView)) {
526 pShellView = IShellView_Constructor ((IShellFolder *) iface);
527 if (pShellView) {
528 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
529 IShellView_Release (pShellView);
533 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
534 return hr;
537 /**************************************************************************
538 * IShellFolder_fnGetAttributesOf
540 * PARAMETERS
541 * UINT cidl, //[in ] num elements in pidl array
542 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
543 * ULONG* rgfInOut) //[out] result array
546 static HRESULT WINAPI
547 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
548 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
550 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
552 HRESULT hr = S_OK;
554 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", This, cidl, apidl,
555 rgfInOut, rgfInOut ? *rgfInOut : 0);
557 if (!rgfInOut)
558 return E_INVALIDARG;
559 if (cidl && !apidl)
560 return E_INVALIDARG;
562 if (*rgfInOut == 0)
563 *rgfInOut = ~0;
565 if(cidl == 0){
566 IShellFolder *psfParent = NULL;
567 LPCITEMIDLIST rpidl = NULL;
569 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
570 if(SUCCEEDED(hr)) {
571 SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
572 IShellFolder_Release(psfParent);
575 else {
576 while (cidl > 0 && *apidl) {
577 pdump (*apidl);
578 SHELL32_GetItemAttributes((IShellFolder *)&This->IShellFolder2_iface, *apidl, rgfInOut);
579 apidl++;
580 cidl--;
583 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
584 *rgfInOut &= ~SFGAO_VALIDATE;
586 TRACE ("-- result=0x%08x\n", *rgfInOut);
588 return hr;
591 /**************************************************************************
592 * SHELL32_CreateExtensionUIObject (internal)
594 HRESULT SHELL32_CreateExtensionUIObject(IShellFolder2 *iface,
595 LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
597 static const WCHAR reg_blockedW[] = {'S','o','f','t','w','a','r','e','\\',
598 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
599 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
600 'S','h','e','l','l',' ','E','x','t','e','n','s','i','o','n','s','\\',
601 'B','l','o','c','k','e','d',0};
602 static const WCHAR formatW[] = {'.','%','s','\\','S','h','e','l','l','E','x','\\',
603 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
604 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
605 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
607 IPersistFile *persist_file;
608 char extensionA[20];
609 WCHAR extensionW[20], buf[MAX_PATH];
610 DWORD size = MAX_PATH;
611 STRRET path;
612 WCHAR *file;
613 GUID guid;
614 HKEY key;
615 HRESULT hr;
618 if(!_ILGetExtension(pidl, extensionA, 20))
619 return S_FALSE;
621 MultiByteToWideChar(CP_ACP, 0, extensionA, -1, extensionW, 20);
623 sprintfW(buf, formatW, extensionW, riid->Data1, riid->Data2, riid->Data3,
624 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
625 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
627 if(RegGetValueW(HKEY_CLASSES_ROOT, buf, NULL, RRF_RT_REG_SZ,
628 NULL, buf, &size) != ERROR_SUCCESS)
629 return S_FALSE;
631 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, reg_blockedW, 0, 0, 0,
632 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
633 return E_FAIL;
634 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
635 != ERROR_FILE_NOT_FOUND)
636 return E_ACCESSDENIED;
637 RegCloseKey(key);
639 if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_blockedW, 0, 0, 0,
640 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
641 return E_FAIL;
642 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
643 != ERROR_FILE_NOT_FOUND)
644 return E_ACCESSDENIED;
645 RegCloseKey(key);
647 if(!GUIDFromStringW(buf, &guid))
648 return E_FAIL;
650 hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER,
651 &IID_IPersistFile, (void**)&persist_file);
652 if(FAILED(hr))
653 return hr;
655 hr = IShellFolder2_GetDisplayNameOf(iface, pidl, SHGDN_FORPARSING, &path);
656 if(SUCCEEDED(hr))
657 hr = StrRetToStrW(&path, NULL, &file);
658 if(FAILED(hr)) {
659 IPersistFile_Release(persist_file);
660 return hr;
663 hr = IPersistFile_Load(persist_file, file, STGM_READ);
664 CoTaskMemFree(file);
665 if(FAILED(hr)) {
666 IPersistFile_Release(persist_file);
667 return hr;
670 hr = IPersistFile_QueryInterface(persist_file, riid, ppvOut);
671 IPersistFile_Release(persist_file);
672 return hr;
675 /**************************************************************************
676 * IShellFolder_fnGetUIObjectOf
678 * PARAMETERS
679 * HWND hwndOwner, //[in ] Parent window for any output
680 * UINT cidl, //[in ] array size
681 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
682 * REFIID riid, //[in ] Requested Interface
683 * UINT* prgfInOut, //[ ] reserved
684 * LPVOID* ppvObject) //[out] Resulting Interface
686 * NOTES
687 * This function gets asked to return "view objects" for one or more (multiple
688 * select) items:
689 * The viewobject typically is an COM object with one of the following
690 * interfaces:
691 * IExtractIcon,IDataObject,IContextMenu
692 * In order to support icon positions in the default Listview your DataObject
693 * must implement the SetData method (in addition to GetData :) - the shell
694 * passes a barely documented "Icon positions" structure to SetData when the
695 * drag starts, and GetData's it if the drop is in another explorer window that
696 * needs the positions.
698 static HRESULT WINAPI
699 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
700 HWND hwndOwner,
701 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
702 UINT * prgfInOut, LPVOID * ppvOut)
704 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
706 LPITEMIDLIST pidl;
707 IUnknown *pObj = NULL;
708 HRESULT hr = E_INVALIDARG;
710 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
711 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
713 if (ppvOut) {
714 *ppvOut = NULL;
716 if(cidl == 1) {
717 hr = SHELL32_CreateExtensionUIObject(iface, *apidl, riid, ppvOut);
718 if(hr != S_FALSE)
719 return hr;
722 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
723 return ItemMenu_Constructor((IShellFolder*)iface, This->pidlRoot, apidl, cidl, riid, ppvOut);
724 } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
725 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
726 This->pidlRoot, apidl, cidl);
727 hr = S_OK;
728 } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
729 pidl = ILCombine (This->pidlRoot, apidl[0]);
730 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
731 SHFree (pidl);
732 hr = S_OK;
733 } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
734 pidl = ILCombine (This->pidlRoot, apidl[0]);
735 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
736 SHFree (pidl);
737 hr = S_OK;
738 } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
739 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget,
740 (LPVOID *) & pObj);
741 } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
742 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
743 pidl = ILCombine (This->pidlRoot, apidl[0]);
744 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
745 SHFree (pidl);
746 } else {
747 hr = E_NOINTERFACE;
750 if (SUCCEEDED(hr) && !pObj)
751 hr = E_OUTOFMEMORY;
753 *ppvOut = pObj;
755 TRACE ("(%p)->hr=0x%08x\n", This, hr);
756 return hr;
759 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
760 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
761 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
762 'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
763 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
764 't',0 };
765 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
766 'x','t',0 };
768 /******************************************************************************
769 * SHELL_FS_HideExtension [Internal]
771 * Query the registry if the filename extension of a given path should be
772 * hidden.
774 * PARAMS
775 * szPath [I] Relative or absolute path of a file
777 * RETURNS
778 * TRUE, if the filename's extension should be hidden
779 * FALSE, otherwise.
781 BOOL SHELL_FS_HideExtension(LPCWSTR szPath)
783 HKEY hKey;
784 DWORD dwData;
785 DWORD dwDataSize = sizeof (DWORD);
786 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
788 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
789 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
790 doHide = dwData;
791 RegCloseKey (hKey);
794 if (!doHide) {
795 LPWSTR ext = PathFindExtensionW(szPath);
797 if (*ext != '\0') {
798 WCHAR classname[MAX_PATH];
799 LONG classlen = sizeof(classname);
801 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
802 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
803 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
804 doHide = TRUE;
805 RegCloseKey(hKey);
809 return doHide;
812 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
814 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
815 if (!(dwFlags & SHGDN_FORPARSING) &&
816 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
817 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
818 PathRemoveExtensionW(szPath);
822 /**************************************************************************
823 * IShellFolder_fnGetDisplayNameOf
824 * Retrieves the display name for the specified file object or subfolder
826 * PARAMETERS
827 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
828 * DWORD dwFlags, //[in ] SHGNO formatting flags
829 * LPSTRRET lpName) //[out] Returned display name
831 * FIXME
832 * if the name is in the pidl the ret value should be a STRRET_OFFSET
835 static HRESULT WINAPI
836 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
837 DWORD dwFlags, LPSTRRET strRet)
839 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
840 LPWSTR pszPath;
842 HRESULT hr = S_OK;
843 int len = 0;
845 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
846 pdump (pidl);
848 if (!pidl || !strRet)
849 return E_INVALIDARG;
851 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
852 if (!pszPath)
853 return E_OUTOFMEMORY;
855 if (_ILIsDesktop(pidl)) { /* empty pidl */
856 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
857 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
859 if (This->sPathTarget)
860 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
861 } else {
862 /* pidl has to contain exactly one non null SHITEMID */
863 hr = E_INVALIDARG;
865 } else if (_ILIsPidlSimple(pidl)) {
866 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
867 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
868 This->sPathTarget)
870 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
871 PathAddBackslashW(pszPath);
872 len = lstrlenW(pszPath);
874 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
875 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
876 } else {
877 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
880 if (SUCCEEDED(hr)) {
881 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
882 if (GetVersion() & 0x80000000) {
883 strRet->uType = STRRET_CSTR;
884 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
885 NULL, NULL))
886 strRet->u.cStr[0] = '\0';
887 CoTaskMemFree(pszPath);
888 } else {
889 strRet->uType = STRRET_WSTR;
890 strRet->u.pOleStr = pszPath;
892 } else
893 CoTaskMemFree(pszPath);
895 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
896 return hr;
899 /**************************************************************************
900 * IShellFolder_fnSetNameOf
901 * Changes the name of a file object or subfolder, possibly changing its item
902 * identifier in the process.
904 * PARAMETERS
905 * HWND hwndOwner, //[in ] Owner window for output
906 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
907 * LPCOLESTR lpszName, //[in ] the items new display name
908 * DWORD dwFlags, //[in ] SHGNO formatting flags
909 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
911 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
912 HWND hwndOwner,
913 LPCITEMIDLIST pidl,
914 LPCOLESTR lpName,
915 DWORD dwFlags,
916 LPITEMIDLIST * pPidlOut)
918 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
919 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
920 LPWSTR ptr;
921 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
923 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
924 debugstr_w (lpName), dwFlags, pPidlOut);
926 /* build source path */
927 lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
928 ptr = PathAddBackslashW (szSrc);
929 if (ptr)
930 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
932 /* build destination path */
933 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
934 lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
935 ptr = PathAddBackslashW (szDest);
936 if (ptr)
937 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
938 } else
939 lstrcpynW(szDest, lpName, MAX_PATH);
941 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
942 WCHAR *ext = PathFindExtensionW(szSrc);
943 if(*ext != '\0') {
944 INT len = strlenW(szDest);
945 lstrcpynW(szDest + len, ext, MAX_PATH - len);
949 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
951 if (MoveFileW (szSrc, szDest)) {
952 HRESULT hr = S_OK;
954 if (pPidlOut)
955 hr = _ILCreateFromPathW(szDest, pPidlOut);
957 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
958 SHCNF_PATHW, szSrc, szDest);
960 return hr;
963 return E_FAIL;
966 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
967 GUID * pguid)
969 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
970 FIXME ("(%p)\n", This);
971 return E_NOTIMPL;
973 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
974 IEnumExtraSearch ** ppenum)
976 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
977 FIXME ("(%p)\n", This);
978 return E_NOTIMPL;
981 static HRESULT WINAPI
982 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
983 ULONG * pSort, ULONG * pDisplay)
985 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
987 TRACE ("(%p)\n", This);
989 if (pSort)
990 *pSort = 0;
991 if (pDisplay)
992 *pDisplay = 0;
994 return S_OK;
997 static HRESULT WINAPI
998 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
999 DWORD * pcsFlags)
1001 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1003 TRACE ("(%p)\n", This);
1005 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
1006 return E_INVALIDARG;
1008 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
1010 return S_OK;
1013 static HRESULT WINAPI
1014 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1015 const SHCOLUMNID * pscid, VARIANT * pv)
1017 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1018 FIXME ("(%p)\n", This);
1020 return E_NOTIMPL;
1023 static HRESULT WINAPI
1024 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1025 UINT iColumn, SHELLDETAILS * psd)
1027 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1028 HRESULT hr = E_FAIL;
1030 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
1032 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
1033 return E_INVALIDARG;
1035 if (!pidl) {
1036 /* the header titles */
1037 psd->fmt = GenericSFHeader[iColumn].fmt;
1038 psd->cxChar = GenericSFHeader[iColumn].cxChar;
1039 psd->str.uType = STRRET_CSTR;
1040 LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
1041 psd->str.u.cStr, MAX_PATH);
1042 return S_OK;
1043 } else {
1044 hr = S_OK;
1045 psd->str.uType = STRRET_CSTR;
1046 /* the data from the pidl */
1047 switch (iColumn) {
1048 case 0: /* name */
1049 hr = IShellFolder2_GetDisplayNameOf (iface, pidl,
1050 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
1051 break;
1052 case 1: /* size */
1053 _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
1054 break;
1055 case 2: /* type */
1056 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
1057 break;
1058 case 3: /* date */
1059 _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
1060 break;
1061 case 4: /* attributes */
1062 _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
1063 break;
1067 return hr;
1070 static HRESULT WINAPI
1071 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
1072 SHCOLUMNID * pscid)
1074 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1075 FIXME ("(%p)\n", This);
1076 return E_NOTIMPL;
1079 static const IShellFolder2Vtbl sfvt =
1081 IShellFolder_fnQueryInterface,
1082 IShellFolder_fnAddRef,
1083 IShellFolder_fnRelease,
1084 IShellFolder_fnParseDisplayName,
1085 IShellFolder_fnEnumObjects,
1086 IShellFolder_fnBindToObject,
1087 IShellFolder_fnBindToStorage,
1088 IShellFolder_fnCompareIDs,
1089 IShellFolder_fnCreateViewObject,
1090 IShellFolder_fnGetAttributesOf,
1091 IShellFolder_fnGetUIObjectOf,
1092 IShellFolder_fnGetDisplayNameOf,
1093 IShellFolder_fnSetNameOf,
1094 /* ShellFolder2 */
1095 IShellFolder_fnGetDefaultSearchGUID,
1096 IShellFolder_fnEnumSearches,
1097 IShellFolder_fnGetDefaultColumn,
1098 IShellFolder_fnGetDefaultColumnState,
1099 IShellFolder_fnGetDetailsEx,
1100 IShellFolder_fnGetDetailsOf,
1101 IShellFolder_fnMapColumnToSCID
1104 /****************************************************************************
1105 * ISFHelper for IShellFolder implementation
1108 static HRESULT WINAPI
1109 ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1111 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1113 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1115 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1118 static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface)
1120 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1122 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1124 return IUnknown_AddRef(This->outer_unk);
1127 static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface)
1129 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1131 TRACE ("(%p)\n", This);
1133 return IUnknown_Release(This->outer_unk);
1136 /****************************************************************************
1137 * ISFHelper_fnGetUniqueName
1139 * creates a unique folder name
1142 static HRESULT WINAPI
1143 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1145 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1146 IEnumIDList *penum;
1147 HRESULT hr;
1148 WCHAR wszText[MAX_PATH];
1149 WCHAR wszNewFolder[25];
1150 const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
1152 TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1154 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder)/sizeof(WCHAR));
1155 if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
1156 return E_POINTER;
1158 lstrcpynW (pwszName, wszNewFolder, uLen);
1160 hr = IShellFolder2_EnumObjects(&This->IShellFolder2_iface, 0,
1161 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1162 if (penum) {
1163 LPITEMIDLIST pidl;
1164 DWORD dwFetched;
1165 int i = 1;
1167 next:
1168 IEnumIDList_Reset (penum);
1169 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1170 dwFetched) {
1171 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1172 if (0 == lstrcmpiW (wszText, pwszName)) {
1173 snprintfW (pwszName, uLen, wszFormat, wszNewFolder, i++);
1174 if (i > 99) {
1175 hr = E_FAIL;
1176 break;
1178 goto next;
1182 IEnumIDList_Release (penum);
1184 return hr;
1187 /****************************************************************************
1188 * ISFHelper_fnAddFolder
1190 * adds a new folder.
1193 static HRESULT WINAPI
1194 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1195 LPITEMIDLIST * ppidlOut)
1197 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1198 WCHAR wszNewDir[MAX_PATH];
1199 DWORD bRes;
1200 HRESULT hres = E_FAIL;
1202 TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1204 wszNewDir[0] = 0;
1205 if (This->sPathTarget)
1206 lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1207 PathAppendW(wszNewDir, pwszName);
1209 bRes = CreateDirectoryW (wszNewDir, NULL);
1210 if (bRes) {
1211 LPITEMIDLIST relPidl;
1213 lstrcpyW(wszNewDir, pwszName);
1215 hres = IShellFolder2_ParseDisplayName(&This->IShellFolder2_iface, hwnd, NULL, wszNewDir,
1216 NULL, &relPidl, NULL);
1218 if (SUCCEEDED(hres)) {
1219 LPITEMIDLIST fullPidl;
1221 fullPidl = ILCombine(This->pidlRoot, relPidl);
1223 if (fullPidl) {
1224 SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST, fullPidl, NULL);
1225 ILFree(fullPidl);
1227 if (ppidlOut)
1228 *ppidlOut = relPidl;
1229 else
1230 ILFree(relPidl);
1231 } else {
1232 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName));
1233 ILFree(relPidl);
1236 } else
1237 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName));
1239 } else {
1240 WCHAR wszText[128 + MAX_PATH];
1241 WCHAR wszTempText[128];
1242 WCHAR wszCaption[256];
1244 /* Cannot Create folder because of permissions */
1245 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
1246 sizeof (wszTempText)/sizeof (wszTempText[0]));
1247 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
1248 sizeof (wszCaption)/sizeof (wszCaption[0]));
1249 sprintfW (wszText, wszTempText, wszNewDir);
1250 MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
1253 return hres;
1256 /****************************************************************************
1257 * build_paths_list
1259 * Builds a list of paths like the one used in SHFileOperation from a table of
1260 * PIDLs relative to the given base folder
1262 static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls)
1264 WCHAR *wszPathsList;
1265 WCHAR *wszListPos;
1266 int iPathLen;
1267 int i;
1269 iPathLen = lstrlenW(wszBasePath);
1270 wszPathsList = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1);
1271 wszListPos = wszPathsList;
1273 for (i = 0; i < cidl; i++) {
1274 if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
1275 continue;
1277 lstrcpynW(wszListPos, wszBasePath, MAX_PATH);
1278 /* FIXME: abort if path too long */
1279 _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen);
1280 wszListPos += lstrlenW(wszListPos)+1;
1282 *wszListPos=0;
1283 return wszPathsList;
1286 /****************************************************************************
1287 * ISFHelper_fnDeleteItems
1289 * deletes items in folder
1291 static HRESULT WINAPI
1292 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1294 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1295 UINT i;
1296 SHFILEOPSTRUCTW op;
1297 WCHAR wszPath[MAX_PATH];
1298 WCHAR *wszPathsList;
1299 HRESULT ret;
1300 WCHAR *wszCurrentPath;
1302 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1303 if (cidl==0) return S_OK;
1305 if (This->sPathTarget)
1306 lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1307 else
1308 wszPath[0] = '\0';
1309 PathAddBackslashW(wszPath);
1310 wszPathsList = build_paths_list(wszPath, cidl, apidl);
1312 ZeroMemory(&op, sizeof(op));
1313 op.hwnd = GetActiveWindow();
1314 op.wFunc = FO_DELETE;
1315 op.pFrom = wszPathsList;
1316 op.fFlags = FOF_ALLOWUNDO;
1317 if (SHFileOperationW(&op))
1319 WARN("SHFileOperation failed\n");
1320 ret = E_FAIL;
1322 else
1323 ret = S_OK;
1325 /* we currently need to manually send the notifies */
1326 wszCurrentPath = wszPathsList;
1327 for (i = 0; i < cidl; i++)
1329 LONG wEventId;
1331 if (_ILIsFolder(apidl[i]))
1332 wEventId = SHCNE_RMDIR;
1333 else if (_ILIsValue(apidl[i]))
1334 wEventId = SHCNE_DELETE;
1335 else
1336 continue;
1338 /* check if file exists */
1339 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1341 LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1342 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1343 SHFree(pidl);
1346 wszCurrentPath += lstrlenW(wszCurrentPath)+1;
1348 HeapFree(GetProcessHeap(), 0, wszPathsList);
1349 return ret;
1352 /****************************************************************************
1353 * ISFHelper_fnCopyItems
1355 * copies items to this folder
1357 static HRESULT WINAPI
1358 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1359 LPCITEMIDLIST * apidl)
1361 HRESULT ret=E_FAIL;
1362 IPersistFolder2 *ppf2 = NULL;
1363 WCHAR wszSrcPathRoot[MAX_PATH],
1364 wszDstPath[MAX_PATH+1];
1365 WCHAR *wszSrcPathsList;
1366 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1368 SHFILEOPSTRUCTW fop;
1370 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1372 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1373 (LPVOID *) & ppf2);
1374 if (ppf2) {
1375 LPITEMIDLIST pidl;
1377 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1378 SHGetPathFromIDListW (pidl, wszSrcPathRoot);
1379 ZeroMemory(wszDstPath, MAX_PATH+1);
1380 if (This->sPathTarget)
1381 lstrcpynW(wszDstPath, This->sPathTarget, MAX_PATH);
1382 PathAddBackslashW(wszSrcPathRoot);
1383 PathAddBackslashW(wszDstPath);
1384 wszSrcPathsList = build_paths_list(wszSrcPathRoot, cidl, apidl);
1385 ZeroMemory(&fop, sizeof(fop));
1386 fop.hwnd = GetActiveWindow();
1387 fop.wFunc = FO_COPY;
1388 fop.pFrom = wszSrcPathsList;
1389 fop.pTo = wszDstPath;
1390 fop.fFlags = FOF_ALLOWUNDO;
1391 ret = S_OK;
1392 if(SHFileOperationW(&fop))
1394 WARN("Copy failed\n");
1395 ret = E_FAIL;
1397 HeapFree(GetProcessHeap(), 0, wszSrcPathsList);
1400 SHFree(pidl);
1401 IPersistFolder2_Release(ppf2);
1403 return ret;
1406 static const ISFHelperVtbl shvt =
1408 ISFHelper_fnQueryInterface,
1409 ISFHelper_fnAddRef,
1410 ISFHelper_fnRelease,
1411 ISFHelper_fnGetUniqueName,
1412 ISFHelper_fnAddFolder,
1413 ISFHelper_fnDeleteItems,
1414 ISFHelper_fnCopyItems
1417 /************************************************************************
1418 * IFSFldr_PersistFolder3_QueryInterface
1421 static HRESULT WINAPI IFSFldr_PersistFolder3_QueryInterface(IPersistFolder3 *iface, REFIID iid,
1422 void **ppv)
1424 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1426 return IUnknown_QueryInterface(This->outer_unk, iid, ppv);
1429 /************************************************************************
1430 * IFSFldr_PersistFolder3_AddRef
1433 static ULONG WINAPI IFSFldr_PersistFolder3_AddRef(IPersistFolder3 *iface)
1435 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1437 return IUnknown_AddRef(This->outer_unk);
1440 /************************************************************************
1441 * IFSFldr_PersistFolder3_Release
1444 static ULONG WINAPI IFSFldr_PersistFolder3_Release(IPersistFolder3 *iface)
1446 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1448 return IUnknown_Release(This->outer_unk);
1451 /************************************************************************
1452 * IFSFldr_PersistFolder3_GetClassID
1454 static HRESULT WINAPI
1455 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1457 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1459 TRACE ("(%p)\n", This);
1461 if (!lpClassId)
1462 return E_POINTER;
1463 *lpClassId = *This->pclsid;
1465 return S_OK;
1468 /************************************************************************
1469 * IFSFldr_PersistFolder3_Initialize
1471 * NOTES
1472 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1474 static HRESULT WINAPI
1475 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1477 WCHAR wszTemp[MAX_PATH];
1479 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1481 TRACE ("(%p)->(%p)\n", This, pidl);
1483 SHFree (This->pidlRoot); /* free the old pidl */
1484 This->pidlRoot = ILClone (pidl); /* set my pidl */
1486 SHFree (This->sPathTarget);
1487 This->sPathTarget = NULL;
1489 /* set my path */
1490 if (SHGetPathFromIDListW (pidl, wszTemp)) {
1491 int len = strlenW(wszTemp);
1492 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1493 if (!This->sPathTarget)
1494 return E_OUTOFMEMORY;
1495 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1498 TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget));
1499 return S_OK;
1502 /**************************************************************************
1503 * IFSFldr_PersistFolder3_GetCurFolder
1505 static HRESULT WINAPI
1506 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1507 LPITEMIDLIST * pidl)
1509 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1511 TRACE ("(%p)->(%p)\n", This, pidl);
1513 if (!pidl) return E_POINTER;
1514 *pidl = ILClone (This->pidlRoot);
1515 return S_OK;
1518 /**************************************************************************
1519 * IFSFldr_PersistFolder3_InitializeEx
1521 * FIXME: error handling
1523 static HRESULT WINAPI
1524 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1525 IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1526 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1528 WCHAR wszTemp[MAX_PATH];
1530 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1532 TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1533 if (ppfti)
1534 TRACE ("--%p %s %s 0x%08x 0x%08x\n",
1535 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1536 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1537 ppfti->csidl);
1539 pdump (pidlRoot);
1540 if (ppfti && ppfti->pidlTargetFolder)
1541 pdump (ppfti->pidlTargetFolder);
1543 if (This->pidlRoot)
1544 __SHFreeAndNil (&This->pidlRoot); /* free the old */
1545 if (This->sPathTarget)
1546 __SHFreeAndNil (&This->sPathTarget);
1549 * Root path and pidl
1551 This->pidlRoot = ILClone (pidlRoot);
1554 * the target folder is specified in csidl OR pidlTargetFolder OR
1555 * szTargetParsingName
1557 if (ppfti) {
1558 if (ppfti->csidl != -1) {
1559 if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl,
1560 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1561 int len = strlenW(wszTemp);
1562 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1563 if (!This->sPathTarget)
1564 return E_OUTOFMEMORY;
1565 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1567 } else if (ppfti->szTargetParsingName[0]) {
1568 int len = strlenW(ppfti->szTargetParsingName);
1569 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1570 if (!This->sPathTarget)
1571 return E_OUTOFMEMORY;
1572 memcpy(This->sPathTarget, ppfti->szTargetParsingName,
1573 (len + 1) * sizeof(WCHAR));
1574 } else if (ppfti->pidlTargetFolder) {
1575 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) {
1576 int len = strlenW(wszTemp);
1577 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1578 if (!This->sPathTarget)
1579 return E_OUTOFMEMORY;
1580 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1585 TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget));
1586 pdump (This->pidlRoot);
1587 return (This->sPathTarget) ? S_OK : E_FAIL;
1590 static HRESULT WINAPI
1591 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1592 PERSIST_FOLDER_TARGET_INFO * ppfti)
1594 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1595 FIXME ("(%p)->(%p)\n", This, ppfti);
1596 ZeroMemory (ppfti, sizeof (*ppfti));
1597 return E_NOTIMPL;
1600 static const IPersistFolder3Vtbl pfvt =
1602 IFSFldr_PersistFolder3_QueryInterface,
1603 IFSFldr_PersistFolder3_AddRef,
1604 IFSFldr_PersistFolder3_Release,
1605 IFSFldr_PersistFolder3_GetClassID,
1606 IFSFldr_PersistFolder3_Initialize,
1607 IFSFldr_PersistFolder3_fnGetCurFolder,
1608 IFSFldr_PersistFolder3_InitializeEx,
1609 IFSFldr_PersistFolder3_GetFolderTargetInfo
1612 /****************************************************************************
1613 * ISFDropTarget implementation
1615 static BOOL
1616 ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState,
1617 LPDWORD pdwEffect)
1619 DWORD dwEffect = *pdwEffect;
1621 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1623 *pdwEffect = DROPEFFECT_NONE;
1625 if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */
1626 *pdwEffect = KeyStateToDropEffect (dwKeyState);
1628 /* ... matches the desired effect ? */
1629 if (dwEffect & *pdwEffect) {
1630 return TRUE;
1633 return FALSE;
1636 static HRESULT WINAPI
1637 ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj)
1639 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1641 TRACE ("(%p)\n", This);
1643 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1646 static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface)
1648 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1650 TRACE ("(%p)\n", This);
1652 return IUnknown_AddRef(This->outer_unk);
1655 static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface)
1657 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1659 TRACE ("(%p)\n", This);
1661 return IUnknown_Release(This->outer_unk);
1664 static HRESULT WINAPI
1665 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1666 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1668 FORMATETC fmt;
1670 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1672 TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1674 InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1675 This->fAcceptFmt = IDataObject_QueryGetData (pDataObject, &fmt) == S_OK;
1676 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1678 return S_OK;
1681 static HRESULT WINAPI
1682 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1683 DWORD * pdwEffect)
1685 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1687 TRACE ("(%p)\n", This);
1689 if (!pdwEffect)
1690 return E_INVALIDARG;
1692 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1694 return S_OK;
1697 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1699 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1701 TRACE ("(%p)\n", This);
1703 This->fAcceptFmt = FALSE;
1705 return S_OK;
1708 static HRESULT WINAPI
1709 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1710 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1712 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1714 FIXME ("(%p) object dropped\n", This);
1716 return E_NOTIMPL;
1719 static const IDropTargetVtbl dtvt = {
1720 ISFDropTarget_QueryInterface,
1721 ISFDropTarget_AddRef,
1722 ISFDropTarget_Release,
1723 ISFDropTarget_DragEnter,
1724 ISFDropTarget_DragOver,
1725 ISFDropTarget_DragLeave,
1726 ISFDropTarget_Drop