ntdll: Use PAGE_EXECUTE_READWRITE protection when allocating stubs.
[wine.git] / dlls / shell32 / shfldr_fs.c
blobb591533126dfc7945b53214be2bbf704903c3d8d
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 const IUnknownVtbl *lpVtbl;
63 LONG ref;
64 const IShellFolder2Vtbl *lpvtblShellFolder;
65 const IPersistFolder3Vtbl *lpvtblPersistFolder3;
66 const IDropTargetVtbl *lpvtblDropTarget;
67 const ISFHelperVtbl *lpvtblSFHelper;
69 IUnknown *pUnkOuter; /* used for aggregation */
71 CLSID *pclsid;
73 /* both paths are parsible from the desktop */
74 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
76 LPITEMIDLIST pidlRoot; /* absolute pidl */
78 UINT cfShellIDList; /* clipboardformat for IDropTarget */
79 BOOL fAcceptFmt; /* flag for pending Drop */
80 } IGenericSFImpl;
82 static const IUnknownVtbl unkvt;
83 static const IShellFolder2Vtbl sfvt;
84 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */
85 static const IDropTargetVtbl dtvt;
86 static const ISFHelperVtbl shvt;
88 static inline IGenericSFImpl *impl_from_IShellFolder2( IShellFolder2 *iface )
90 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblShellFolder));
93 static inline IGenericSFImpl *impl_from_IPersistFolder3( IPersistFolder3 *iface )
95 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblPersistFolder3));
98 static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface )
100 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget));
103 static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface )
105 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
110 converts This to an interface pointer
112 #define _IUnknown_(This) ((IUnknown*)&(This)->lpVtbl)
113 #define _IShellFolder_(This) ((IShellFolder*)&(This)->lpvtblShellFolder)
114 #define _IShellFolder2_(This) ((IShellFolder2*)&(This)->lpvtblShellFolder)
115 #define _IPersist_(This) (&(This)->lpvtblPersistFolder3)
116 #define _IPersistFolder_(This) (&(This)->lpvtblPersistFolder3)
117 #define _IPersistFolder2_(This) (&(This)->lpvtblPersistFolder3)
118 #define _IPersistFolder3_(This) (&(This)->lpvtblPersistFolder3)
119 #define _IDropTarget_(This) (&(This)->lpvtblDropTarget)
120 #define _ISFHelper_(This) (&(This)->lpvtblSFHelper)
122 /**************************************************************************
123 * registers clipboardformat once
125 static void SF_RegisterClipFmt (IGenericSFImpl * This)
127 TRACE ("(%p)\n", This);
129 if (!This->cfShellIDList) {
130 This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
134 /**************************************************************************
135 * we need a separate IUnknown to handle aggregation
136 * (inner IUnknown)
138 static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj)
140 IGenericSFImpl *This = (IGenericSFImpl *)iface;
142 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
144 *ppvObj = NULL;
146 if (IsEqualIID (riid, &IID_IUnknown))
147 *ppvObj = _IUnknown_ (This);
148 else if (IsEqualIID (riid, &IID_IShellFolder))
149 *ppvObj = _IShellFolder_ (This);
150 else if (IsEqualIID (riid, &IID_IShellFolder2))
151 *ppvObj = _IShellFolder_ (This);
152 else if (IsEqualIID (riid, &IID_IPersist))
153 *ppvObj = _IPersist_ (This);
154 else if (IsEqualIID (riid, &IID_IPersistFolder))
155 *ppvObj = _IPersistFolder_ (This);
156 else if (IsEqualIID (riid, &IID_IPersistFolder2))
157 *ppvObj = _IPersistFolder2_ (This);
158 else if (IsEqualIID (riid, &IID_IPersistFolder3))
159 *ppvObj = _IPersistFolder3_ (This);
160 else if (IsEqualIID (riid, &IID_ISFHelper))
161 *ppvObj = _ISFHelper_ (This);
162 else if (IsEqualIID (riid, &IID_IDropTarget)) {
163 *ppvObj = _IDropTarget_ (This);
164 SF_RegisterClipFmt (This);
167 if (*ppvObj) {
168 IUnknown_AddRef ((IUnknown *) (*ppvObj));
169 TRACE ("-- Interface = %p\n", *ppvObj);
170 return S_OK;
172 TRACE ("-- Interface: E_NOINTERFACE\n");
173 return E_NOINTERFACE;
176 static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface)
178 IGenericSFImpl *This = (IGenericSFImpl *)iface;
179 ULONG refCount = InterlockedIncrement(&This->ref);
181 TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
183 return refCount;
186 static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface)
188 IGenericSFImpl *This = (IGenericSFImpl *)iface;
189 ULONG refCount = InterlockedDecrement(&This->ref);
191 TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
193 if (!refCount) {
194 TRACE ("-- destroying IShellFolder(%p)\n", This);
196 SHFree (This->pidlRoot);
197 SHFree (This->sPathTarget);
198 LocalFree (This);
200 return refCount;
203 static const IUnknownVtbl unkvt =
205 IUnknown_fnQueryInterface,
206 IUnknown_fnAddRef,
207 IUnknown_fnRelease,
210 static const shvheader GenericSFHeader[] = {
211 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
212 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
213 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
214 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
215 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
218 #define GENERICSHELLVIEWCOLUMNS 5
220 /**************************************************************************
221 * IFSFolder_Constructor
223 * NOTES
224 * creating undocumented ShellFS_Folder as part of an aggregation
225 * {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
228 HRESULT WINAPI
229 IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
231 IGenericSFImpl *sf;
233 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
235 if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
236 return CLASS_E_NOAGGREGATION;
237 sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
238 if (!sf)
239 return E_OUTOFMEMORY;
241 sf->ref = 0;
242 sf->lpVtbl = &unkvt;
243 sf->lpvtblShellFolder = &sfvt;
244 sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3;
245 sf->lpvtblDropTarget = &dtvt;
246 sf->lpvtblSFHelper = &shvt;
247 sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
248 sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
250 if (FAILED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) {
251 IUnknown_Release (_IUnknown_ (sf));
252 return E_NOINTERFACE;
255 TRACE ("--%p\n", *ppv);
256 return S_OK;
259 /**************************************************************************
260 * IShellFolder_fnQueryInterface
262 * PARAMETERS
263 * REFIID riid [in ] Requested InterfaceID
264 * LPVOID* ppvObject [out] Interface* to hold the result
266 static HRESULT WINAPI
267 IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid,
268 LPVOID * ppvObj)
270 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
272 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
274 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
277 /**************************************************************************
278 * IShellFolder_AddRef
281 static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface)
283 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
285 TRACE ("(%p)->(count=%u)\n", This, This->ref);
287 return IUnknown_AddRef (This->pUnkOuter);
290 /**************************************************************************
291 * IShellFolder_fnRelease
293 static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface)
295 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
297 TRACE ("(%p)->(count=%u)\n", This, This->ref);
299 return IUnknown_Release (This->pUnkOuter);
302 /**************************************************************************
303 * SHELL32_CreatePidlFromBindCtx [internal]
305 * If the caller bound File System Bind Data, assume it is the
306 * find data for the path.
307 * This allows binding of paths that don't exist.
309 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
311 static WCHAR szfsbc[] = {
312 'F','i','l','e',' ','S','y','s','t','e','m',' ',
313 'B','i','n','d',' ','D','a','t','a',0 };
314 IFileSystemBindData *fsbd = NULL;
315 LPITEMIDLIST pidl = NULL;
316 IUnknown *unk = NULL;
317 HRESULT r;
319 TRACE("%p %s\n", pbc, debugstr_w(path));
321 if (!pbc)
322 return NULL;
324 /* see if the caller bound File System Bind Data */
325 r = IBindCtx_GetObjectParam( pbc, szfsbc, &unk );
326 if (FAILED(r))
327 return NULL;
329 r = IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
330 if (SUCCEEDED(r))
332 WIN32_FIND_DATAW wfd;
334 r = IFileSystemBindData_GetFindData( fsbd, &wfd );
335 if (SUCCEEDED(r))
337 lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
338 pidl = _ILCreateFromFindDataW( &wfd );
340 IFileSystemBindData_Release( fsbd );
342 IUnknown_Release( unk );
344 return pidl;
347 /**************************************************************************
348 * IShellFolder_ParseDisplayName {SHELL32}
350 * Parse a display name.
352 * PARAMS
353 * hwndOwner [in] Parent window for any message's
354 * pbc [in] optional FileSystemBindData context
355 * lpszDisplayName [in] Unicode displayname.
356 * pchEaten [out] (unicode) characters processed
357 * ppidl [out] complex pidl to item
358 * pdwAttributes [out] items attributes
360 * NOTES
361 * Every folder tries to parse only its own (the leftmost) pidl and creates a
362 * subfolder to evaluate the remaining parts.
363 * Now we can parse into namespaces implemented by shell extensions
365 * Behaviour on win98: lpszDisplayName=NULL -> crash
366 * lpszDisplayName="" -> returns mycoputer-pidl
368 * FIXME
369 * pdwAttributes is not set
370 * pchEaten is not set like in windows
372 static HRESULT WINAPI
373 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
374 HWND hwndOwner,
375 LPBC pbc,
376 LPOLESTR lpszDisplayName,
377 DWORD * pchEaten, LPITEMIDLIST * ppidl,
378 DWORD * pdwAttributes)
380 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
382 HRESULT hr = E_INVALIDARG;
383 LPCWSTR szNext = NULL;
384 WCHAR szElement[MAX_PATH];
385 WCHAR szPath[MAX_PATH];
386 LPITEMIDLIST pidlTemp = NULL;
387 DWORD len;
389 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
390 This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
391 pchEaten, ppidl, pdwAttributes);
393 if (!lpszDisplayName || !ppidl)
394 return E_INVALIDARG;
396 if (pchEaten)
397 *pchEaten = 0; /* strange but like the original */
399 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
400 if (!pidlTemp && *lpszDisplayName)
402 /* get the next element */
403 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
405 /* build the full pathname to the element */
406 lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1);
407 PathAddBackslashW(szPath);
408 len = lstrlenW(szPath);
409 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
411 /* get the pidl */
412 hr = _ILCreateFromPathW(szPath, &pidlTemp);
414 if (SUCCEEDED(hr)) {
415 if (szNext && *szNext) {
416 /* try to analyse the next element */
417 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
418 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
419 } else {
420 /* it's the last element */
421 if (pdwAttributes && *pdwAttributes) {
422 hr = SHELL32_GetItemAttributes (_IShellFolder_ (This),
423 pidlTemp, pdwAttributes);
429 if (SUCCEEDED(hr))
430 *ppidl = pidlTemp;
431 else
432 *ppidl = NULL;
434 TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", This, *ppidl, hr);
436 return hr;
439 /**************************************************************************
440 * IShellFolder_fnEnumObjects
441 * PARAMETERS
442 * HWND hwndOwner, //[in ] Parent Window
443 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
444 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
446 static HRESULT WINAPI
447 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
448 DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
450 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
451 IEnumIDListImpl *list;
453 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner,
454 dwFlags, ppEnumIDList);
456 if (!(list = IEnumIDList_Constructor()))
457 return E_OUTOFMEMORY;
458 CreateFolderEnumList(list, This->sPathTarget, dwFlags);
459 *ppEnumIDList = &list->IEnumIDList_iface;
461 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
463 return S_OK;
466 /**************************************************************************
467 * IShellFolder_fnBindToObject
468 * PARAMETERS
469 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
470 * LPBC pbc, //[in ] optional FileSystemBindData context
471 * REFIID riid, //[in ] Initial Interface
472 * LPVOID* ppvObject //[out] Interface*
474 static HRESULT WINAPI
475 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
476 LPBC pbc, REFIID riid, LPVOID * ppvOut)
478 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
480 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
481 shdebugstr_guid (riid), ppvOut);
483 return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid,
484 ppvOut);
487 /**************************************************************************
488 * IShellFolder_fnBindToStorage
489 * PARAMETERS
490 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
491 * LPBC pbc, //[in ] reserved
492 * REFIID riid, //[in ] Initial storage interface
493 * LPVOID* ppvObject //[out] Interface* returned
495 static HRESULT WINAPI
496 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
497 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
499 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
501 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
502 shdebugstr_guid (riid), ppvOut);
504 *ppvOut = NULL;
505 return E_NOTIMPL;
508 /**************************************************************************
509 * IShellFolder_fnCompareIDs
512 static HRESULT WINAPI
513 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
514 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
516 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
518 int nReturn;
520 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
521 nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
522 TRACE ("-- %i\n", nReturn);
523 return nReturn;
526 /**************************************************************************
527 * IShellFolder_fnCreateViewObject
529 static HRESULT WINAPI
530 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
531 REFIID riid, LPVOID * ppvOut)
533 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
535 LPSHELLVIEW pShellView;
536 HRESULT hr = E_INVALIDARG;
538 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
539 ppvOut);
541 if (ppvOut) {
542 *ppvOut = NULL;
544 if (IsEqualIID (riid, &IID_IDropTarget)) {
545 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, ppvOut);
546 } else if (IsEqualIID (riid, &IID_IContextMenu)) {
547 FIXME ("IContextMenu not implemented\n");
548 hr = E_NOTIMPL;
549 } else if (IsEqualIID (riid, &IID_IShellView)) {
550 pShellView = IShellView_Constructor ((IShellFolder *) iface);
551 if (pShellView) {
552 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
553 IShellView_Release (pShellView);
557 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
558 return hr;
561 /**************************************************************************
562 * IShellFolder_fnGetAttributesOf
564 * PARAMETERS
565 * UINT cidl, //[in ] num elements in pidl array
566 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
567 * ULONG* rgfInOut) //[out] result array
570 static HRESULT WINAPI
571 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
572 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
574 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
576 HRESULT hr = S_OK;
578 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", This, cidl, apidl,
579 rgfInOut, rgfInOut ? *rgfInOut : 0);
581 if (!rgfInOut)
582 return E_INVALIDARG;
583 if (cidl && !apidl)
584 return E_INVALIDARG;
586 if (*rgfInOut == 0)
587 *rgfInOut = ~0;
589 if(cidl == 0){
590 IShellFolder *psfParent = NULL;
591 LPCITEMIDLIST rpidl = NULL;
593 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
594 if(SUCCEEDED(hr)) {
595 SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
596 IShellFolder_Release(psfParent);
599 else {
600 while (cidl > 0 && *apidl) {
601 pdump (*apidl);
602 SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
603 apidl++;
604 cidl--;
607 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
608 *rgfInOut &= ~SFGAO_VALIDATE;
610 TRACE ("-- result=0x%08x\n", *rgfInOut);
612 return hr;
615 /**************************************************************************
616 * SHELL32_CreateExtensionUIObject (internal)
618 HRESULT SHELL32_CreateExtensionUIObject(IShellFolder2 *iface,
619 LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
621 static const WCHAR reg_blockedW[] = {'S','o','f','t','w','a','r','e','\\',
622 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
623 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
624 'S','h','e','l','l',' ','E','x','t','e','n','s','i','o','n','s','\\',
625 'B','l','o','c','k','e','d',0};
626 static const WCHAR formatW[] = {'.','%','s','\\','S','h','e','l','l','E','x','\\',
627 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
628 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
629 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
631 IPersistFile *persist_file;
632 char extensionA[20];
633 WCHAR extensionW[20], buf[MAX_PATH];
634 DWORD size = MAX_PATH;
635 STRRET path;
636 WCHAR *file;
637 GUID guid;
638 HKEY key;
639 HRESULT hr;
642 if(!_ILGetExtension(pidl, extensionA, 20))
643 return S_FALSE;
645 MultiByteToWideChar(CP_ACP, 0, extensionA, -1, extensionW, 20);
647 sprintfW(buf, formatW, extensionW, riid->Data1, riid->Data2, riid->Data3,
648 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
649 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
651 if(RegGetValueW(HKEY_CLASSES_ROOT, buf, NULL, RRF_RT_REG_SZ,
652 NULL, buf, &size) != ERROR_SUCCESS)
653 return S_FALSE;
655 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, reg_blockedW, 0, 0, 0,
656 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
657 return E_FAIL;
658 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
659 != ERROR_FILE_NOT_FOUND)
660 return E_ACCESSDENIED;
661 RegCloseKey(key);
663 if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_blockedW, 0, 0, 0,
664 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
665 return E_FAIL;
666 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
667 != ERROR_FILE_NOT_FOUND)
668 return E_ACCESSDENIED;
669 RegCloseKey(key);
671 if(!GUIDFromStringW(buf, &guid))
672 return E_FAIL;
674 hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER,
675 &IID_IPersistFile, (void**)&persist_file);
676 if(FAILED(hr))
677 return hr;
679 hr = IShellFolder_GetDisplayNameOf(iface, pidl, SHGDN_FORPARSING, &path);
680 if(SUCCEEDED(hr))
681 hr = StrRetToStrW(&path, NULL, &file);
682 if(FAILED(hr)) {
683 IPersistFile_Release(persist_file);
684 return hr;
687 hr = IPersistFile_Load(persist_file, file, STGM_READ);
688 CoTaskMemFree(file);
689 if(FAILED(hr)) {
690 IPersistFile_Release(persist_file);
691 return hr;
694 hr = IPersistFile_QueryInterface(persist_file, riid, ppvOut);
695 IPersistFile_Release(persist_file);
696 return hr;
699 /**************************************************************************
700 * IShellFolder_fnGetUIObjectOf
702 * PARAMETERS
703 * HWND hwndOwner, //[in ] Parent window for any output
704 * UINT cidl, //[in ] array size
705 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
706 * REFIID riid, //[in ] Requested Interface
707 * UINT* prgfInOut, //[ ] reserved
708 * LPVOID* ppvObject) //[out] Resulting Interface
710 * NOTES
711 * This function gets asked to return "view objects" for one or more (multiple
712 * select) items:
713 * The viewobject typically is an COM object with one of the following
714 * interfaces:
715 * IExtractIcon,IDataObject,IContextMenu
716 * In order to support icon positions in the default Listview your DataObject
717 * must implement the SetData method (in addition to GetData :) - the shell
718 * passes a barely documented "Icon positions" structure to SetData when the
719 * drag starts, and GetData's it if the drop is in another explorer window that
720 * needs the positions.
722 static HRESULT WINAPI
723 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
724 HWND hwndOwner,
725 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
726 UINT * prgfInOut, LPVOID * ppvOut)
728 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
730 LPITEMIDLIST pidl;
731 IUnknown *pObj = NULL;
732 HRESULT hr = E_INVALIDARG;
734 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
735 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
737 if (ppvOut) {
738 *ppvOut = NULL;
740 if(cidl == 1) {
741 hr = SHELL32_CreateExtensionUIObject(iface, *apidl, riid, ppvOut);
742 if(hr != S_FALSE)
743 return hr;
746 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
747 pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
748 This->pidlRoot, apidl, cidl);
749 hr = S_OK;
750 } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
751 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
752 This->pidlRoot, apidl, cidl);
753 hr = S_OK;
754 } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
755 pidl = ILCombine (This->pidlRoot, apidl[0]);
756 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
757 SHFree (pidl);
758 hr = S_OK;
759 } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
760 pidl = ILCombine (This->pidlRoot, apidl[0]);
761 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
762 SHFree (pidl);
763 hr = S_OK;
764 } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
765 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
766 (LPVOID *) & pObj);
767 } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
768 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
769 pidl = ILCombine (This->pidlRoot, apidl[0]);
770 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
771 SHFree (pidl);
772 } else {
773 hr = E_NOINTERFACE;
776 if (SUCCEEDED(hr) && !pObj)
777 hr = E_OUTOFMEMORY;
779 *ppvOut = pObj;
781 TRACE ("(%p)->hr=0x%08x\n", This, hr);
782 return hr;
785 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
786 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
787 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
788 'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
789 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
790 't',0 };
791 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
792 'x','t',0 };
794 /******************************************************************************
795 * SHELL_FS_HideExtension [Internal]
797 * Query the registry if the filename extension of a given path should be
798 * hidden.
800 * PARAMS
801 * szPath [I] Relative or absolute path of a file
803 * RETURNS
804 * TRUE, if the filename's extension should be hidden
805 * FALSE, otherwise.
807 BOOL SHELL_FS_HideExtension(LPCWSTR szPath)
809 HKEY hKey;
810 DWORD dwData;
811 DWORD dwDataSize = sizeof (DWORD);
812 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
814 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
815 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
816 doHide = dwData;
817 RegCloseKey (hKey);
820 if (!doHide) {
821 LPWSTR ext = PathFindExtensionW(szPath);
823 if (*ext != '\0') {
824 WCHAR classname[MAX_PATH];
825 LONG classlen = sizeof(classname);
827 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
828 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
829 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
830 doHide = TRUE;
831 RegCloseKey(hKey);
835 return doHide;
838 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
840 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
841 if (!(dwFlags & SHGDN_FORPARSING) &&
842 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
843 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
844 PathRemoveExtensionW(szPath);
848 /**************************************************************************
849 * IShellFolder_fnGetDisplayNameOf
850 * Retrieves the display name for the specified file object or subfolder
852 * PARAMETERS
853 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
854 * DWORD dwFlags, //[in ] SHGNO formatting flags
855 * LPSTRRET lpName) //[out] Returned display name
857 * FIXME
858 * if the name is in the pidl the ret value should be a STRRET_OFFSET
861 static HRESULT WINAPI
862 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
863 DWORD dwFlags, LPSTRRET strRet)
865 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
866 LPWSTR pszPath;
868 HRESULT hr = S_OK;
869 int len = 0;
871 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
872 pdump (pidl);
874 if (!pidl || !strRet)
875 return E_INVALIDARG;
877 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
878 if (!pszPath)
879 return E_OUTOFMEMORY;
881 if (_ILIsDesktop(pidl)) { /* empty pidl */
882 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
883 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
885 if (This->sPathTarget)
886 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
887 } else {
888 /* pidl has to contain exactly one non null SHITEMID */
889 hr = E_INVALIDARG;
891 } else if (_ILIsPidlSimple(pidl)) {
892 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
893 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
894 This->sPathTarget)
896 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
897 PathAddBackslashW(pszPath);
898 len = lstrlenW(pszPath);
900 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
901 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
902 } else {
903 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
906 if (SUCCEEDED(hr)) {
907 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
908 if (GetVersion() & 0x80000000) {
909 strRet->uType = STRRET_CSTR;
910 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
911 NULL, NULL))
912 strRet->u.cStr[0] = '\0';
913 CoTaskMemFree(pszPath);
914 } else {
915 strRet->uType = STRRET_WSTR;
916 strRet->u.pOleStr = pszPath;
918 } else
919 CoTaskMemFree(pszPath);
921 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
922 return hr;
925 /**************************************************************************
926 * IShellFolder_fnSetNameOf
927 * Changes the name of a file object or subfolder, possibly changing its item
928 * identifier in the process.
930 * PARAMETERS
931 * HWND hwndOwner, //[in ] Owner window for output
932 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
933 * LPCOLESTR lpszName, //[in ] the items new display name
934 * DWORD dwFlags, //[in ] SHGNO formatting flags
935 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
937 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
938 HWND hwndOwner,
939 LPCITEMIDLIST pidl,
940 LPCOLESTR lpName,
941 DWORD dwFlags,
942 LPITEMIDLIST * pPidlOut)
944 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
945 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
946 LPWSTR ptr;
947 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
949 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
950 debugstr_w (lpName), dwFlags, pPidlOut);
952 /* build source path */
953 lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
954 ptr = PathAddBackslashW (szSrc);
955 if (ptr)
956 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
958 /* build destination path */
959 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
960 lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
961 ptr = PathAddBackslashW (szDest);
962 if (ptr)
963 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
964 } else
965 lstrcpynW(szDest, lpName, MAX_PATH);
967 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
968 WCHAR *ext = PathFindExtensionW(szSrc);
969 if(*ext != '\0') {
970 INT len = strlenW(szDest);
971 lstrcpynW(szDest + len, ext, MAX_PATH - len);
975 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
977 if (MoveFileW (szSrc, szDest)) {
978 HRESULT hr = S_OK;
980 if (pPidlOut)
981 hr = _ILCreateFromPathW(szDest, pPidlOut);
983 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
984 SHCNF_PATHW, szSrc, szDest);
986 return hr;
989 return E_FAIL;
992 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
993 GUID * pguid)
995 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
996 FIXME ("(%p)\n", This);
997 return E_NOTIMPL;
999 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
1000 IEnumExtraSearch ** ppenum)
1002 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1003 FIXME ("(%p)\n", This);
1004 return E_NOTIMPL;
1007 static HRESULT WINAPI
1008 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
1009 ULONG * pSort, ULONG * pDisplay)
1011 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1013 TRACE ("(%p)\n", This);
1015 if (pSort)
1016 *pSort = 0;
1017 if (pDisplay)
1018 *pDisplay = 0;
1020 return S_OK;
1023 static HRESULT WINAPI
1024 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
1025 DWORD * pcsFlags)
1027 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1029 TRACE ("(%p)\n", This);
1031 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
1032 return E_INVALIDARG;
1034 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
1036 return S_OK;
1039 static HRESULT WINAPI
1040 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1041 const SHCOLUMNID * pscid, VARIANT * pv)
1043 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1044 FIXME ("(%p)\n", This);
1046 return E_NOTIMPL;
1049 static HRESULT WINAPI
1050 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1051 UINT iColumn, SHELLDETAILS * psd)
1053 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1054 HRESULT hr = E_FAIL;
1056 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
1058 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
1059 return E_INVALIDARG;
1061 if (!pidl) {
1062 /* the header titles */
1063 psd->fmt = GenericSFHeader[iColumn].fmt;
1064 psd->cxChar = GenericSFHeader[iColumn].cxChar;
1065 psd->str.uType = STRRET_CSTR;
1066 LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
1067 psd->str.u.cStr, MAX_PATH);
1068 return S_OK;
1069 } else {
1070 hr = S_OK;
1071 psd->str.uType = STRRET_CSTR;
1072 /* the data from the pidl */
1073 switch (iColumn) {
1074 case 0: /* name */
1075 hr = IShellFolder_GetDisplayNameOf (iface, pidl,
1076 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
1077 break;
1078 case 1: /* size */
1079 _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
1080 break;
1081 case 2: /* type */
1082 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
1083 break;
1084 case 3: /* date */
1085 _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
1086 break;
1087 case 4: /* attributes */
1088 _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
1089 break;
1093 return hr;
1096 static HRESULT WINAPI
1097 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
1098 SHCOLUMNID * pscid)
1100 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1101 FIXME ("(%p)\n", This);
1102 return E_NOTIMPL;
1105 static const IShellFolder2Vtbl sfvt =
1107 IShellFolder_fnQueryInterface,
1108 IShellFolder_fnAddRef,
1109 IShellFolder_fnRelease,
1110 IShellFolder_fnParseDisplayName,
1111 IShellFolder_fnEnumObjects,
1112 IShellFolder_fnBindToObject,
1113 IShellFolder_fnBindToStorage,
1114 IShellFolder_fnCompareIDs,
1115 IShellFolder_fnCreateViewObject,
1116 IShellFolder_fnGetAttributesOf,
1117 IShellFolder_fnGetUIObjectOf,
1118 IShellFolder_fnGetDisplayNameOf,
1119 IShellFolder_fnSetNameOf,
1120 /* ShellFolder2 */
1121 IShellFolder_fnGetDefaultSearchGUID,
1122 IShellFolder_fnEnumSearches,
1123 IShellFolder_fnGetDefaultColumn,
1124 IShellFolder_fnGetDefaultColumnState,
1125 IShellFolder_fnGetDetailsEx,
1126 IShellFolder_fnGetDetailsOf,
1127 IShellFolder_fnMapColumnToSCID
1130 /****************************************************************************
1131 * ISFHelper for IShellFolder implementation
1134 static HRESULT WINAPI
1135 ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1137 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1139 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1141 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1144 static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface)
1146 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1148 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1150 return IUnknown_AddRef (This->pUnkOuter);
1153 static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface)
1155 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1157 TRACE ("(%p)\n", This);
1159 return IUnknown_Release (This->pUnkOuter);
1162 /****************************************************************************
1163 * ISFHelper_fnGetUniqueName
1165 * creates a unique folder name
1168 static HRESULT WINAPI
1169 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1171 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1172 IEnumIDList *penum;
1173 HRESULT hr;
1174 WCHAR wszText[MAX_PATH];
1175 WCHAR wszNewFolder[25];
1176 const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
1178 TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1180 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder)/sizeof(WCHAR));
1181 if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
1182 return E_POINTER;
1184 lstrcpynW (pwszName, wszNewFolder, uLen);
1186 hr = IShellFolder_fnEnumObjects (_IShellFolder2_ (This), 0,
1187 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1188 if (penum) {
1189 LPITEMIDLIST pidl;
1190 DWORD dwFetched;
1191 int i = 1;
1193 next:
1194 IEnumIDList_Reset (penum);
1195 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1196 dwFetched) {
1197 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1198 if (0 == lstrcmpiW (wszText, pwszName)) {
1199 snprintfW (pwszName, uLen, wszFormat, wszNewFolder, i++);
1200 if (i > 99) {
1201 hr = E_FAIL;
1202 break;
1204 goto next;
1208 IEnumIDList_Release (penum);
1210 return hr;
1213 /****************************************************************************
1214 * ISFHelper_fnAddFolder
1216 * adds a new folder.
1219 static HRESULT WINAPI
1220 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1221 LPITEMIDLIST * ppidlOut)
1223 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1224 WCHAR wszNewDir[MAX_PATH];
1225 DWORD bRes;
1226 HRESULT hres = E_FAIL;
1228 TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1230 wszNewDir[0] = 0;
1231 if (This->sPathTarget)
1232 lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1233 PathAppendW(wszNewDir, pwszName);
1235 bRes = CreateDirectoryW (wszNewDir, NULL);
1236 if (bRes) {
1237 LPITEMIDLIST relPidl;
1239 lstrcpyW(wszNewDir, pwszName);
1241 hres = IShellFolder_ParseDisplayName((IShellFolder*)&This->lpvtblShellFolder,
1242 hwnd, NULL, wszNewDir, NULL, &relPidl, NULL);
1244 if (SUCCEEDED(hres)) {
1245 LPITEMIDLIST fullPidl;
1247 fullPidl = ILCombine(This->pidlRoot, relPidl);
1249 if (fullPidl) {
1250 SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST, fullPidl, NULL);
1251 ILFree(fullPidl);
1253 if (ppidlOut)
1254 *ppidlOut = relPidl;
1255 else
1256 ILFree(relPidl);
1257 } else {
1258 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName));
1259 ILFree(relPidl);
1262 } else
1263 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName));
1265 } else {
1266 WCHAR wszText[128 + MAX_PATH];
1267 WCHAR wszTempText[128];
1268 WCHAR wszCaption[256];
1270 /* Cannot Create folder because of permissions */
1271 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
1272 sizeof (wszTempText)/sizeof (wszTempText[0]));
1273 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
1274 sizeof (wszCaption)/sizeof (wszCaption[0]));
1275 sprintfW (wszText, wszTempText, wszNewDir);
1276 MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
1279 return hres;
1282 /****************************************************************************
1283 * build_paths_list
1285 * Builds a list of paths like the one used in SHFileOperation from a table of
1286 * PIDLs relative to the given base folder
1288 static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls)
1290 WCHAR *wszPathsList;
1291 WCHAR *wszListPos;
1292 int iPathLen;
1293 int i;
1295 iPathLen = lstrlenW(wszBasePath);
1296 wszPathsList = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1);
1297 wszListPos = wszPathsList;
1299 for (i = 0; i < cidl; i++) {
1300 if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
1301 continue;
1303 lstrcpynW(wszListPos, wszBasePath, MAX_PATH);
1304 /* FIXME: abort if path too long */
1305 _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen);
1306 wszListPos += lstrlenW(wszListPos)+1;
1308 *wszListPos=0;
1309 return wszPathsList;
1312 /****************************************************************************
1313 * ISFHelper_fnDeleteItems
1315 * deletes items in folder
1317 static HRESULT WINAPI
1318 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1320 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1321 UINT i;
1322 SHFILEOPSTRUCTW op;
1323 WCHAR wszPath[MAX_PATH];
1324 WCHAR *wszPathsList;
1325 HRESULT ret;
1326 WCHAR *wszCurrentPath;
1328 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1329 if (cidl==0) return S_OK;
1331 if (This->sPathTarget)
1332 lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1333 else
1334 wszPath[0] = '\0';
1335 PathAddBackslashW(wszPath);
1336 wszPathsList = build_paths_list(wszPath, cidl, apidl);
1338 ZeroMemory(&op, sizeof(op));
1339 op.hwnd = GetActiveWindow();
1340 op.wFunc = FO_DELETE;
1341 op.pFrom = wszPathsList;
1342 op.fFlags = FOF_ALLOWUNDO;
1343 if (SHFileOperationW(&op))
1345 WARN("SHFileOperation failed\n");
1346 ret = E_FAIL;
1348 else
1349 ret = S_OK;
1351 /* we currently need to manually send the notifies */
1352 wszCurrentPath = wszPathsList;
1353 for (i = 0; i < cidl; i++)
1355 LONG wEventId;
1357 if (_ILIsFolder(apidl[i]))
1358 wEventId = SHCNE_RMDIR;
1359 else if (_ILIsValue(apidl[i]))
1360 wEventId = SHCNE_DELETE;
1361 else
1362 continue;
1364 /* check if file exists */
1365 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1367 LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1368 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1369 SHFree(pidl);
1372 wszCurrentPath += lstrlenW(wszCurrentPath)+1;
1374 HeapFree(GetProcessHeap(), 0, wszPathsList);
1375 return ret;
1378 /****************************************************************************
1379 * ISFHelper_fnCopyItems
1381 * copies items to this folder
1383 static HRESULT WINAPI
1384 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1385 LPCITEMIDLIST * apidl)
1387 HRESULT ret=E_FAIL;
1388 IPersistFolder2 *ppf2 = NULL;
1389 WCHAR wszSrcPathRoot[MAX_PATH],
1390 wszDstPath[MAX_PATH+1];
1391 WCHAR *wszSrcPathsList;
1392 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1394 SHFILEOPSTRUCTW fop;
1396 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1398 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1399 (LPVOID *) & ppf2);
1400 if (ppf2) {
1401 LPITEMIDLIST pidl;
1403 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1404 SHGetPathFromIDListW (pidl, wszSrcPathRoot);
1405 ZeroMemory(wszDstPath, MAX_PATH+1);
1406 if (This->sPathTarget)
1407 lstrcpynW(wszDstPath, This->sPathTarget, MAX_PATH);
1408 PathAddBackslashW(wszSrcPathRoot);
1409 PathAddBackslashW(wszDstPath);
1410 wszSrcPathsList = build_paths_list(wszSrcPathRoot, cidl, apidl);
1411 ZeroMemory(&fop, sizeof(fop));
1412 fop.hwnd = GetActiveWindow();
1413 fop.wFunc = FO_COPY;
1414 fop.pFrom = wszSrcPathsList;
1415 fop.pTo = wszDstPath;
1416 fop.fFlags = FOF_ALLOWUNDO;
1417 ret = S_OK;
1418 if(SHFileOperationW(&fop))
1420 WARN("Copy failed\n");
1421 ret = E_FAIL;
1423 HeapFree(GetProcessHeap(), 0, wszSrcPathsList);
1426 SHFree(pidl);
1427 IPersistFolder2_Release(ppf2);
1429 return ret;
1432 static const ISFHelperVtbl shvt =
1434 ISFHelper_fnQueryInterface,
1435 ISFHelper_fnAddRef,
1436 ISFHelper_fnRelease,
1437 ISFHelper_fnGetUniqueName,
1438 ISFHelper_fnAddFolder,
1439 ISFHelper_fnDeleteItems,
1440 ISFHelper_fnCopyItems
1443 /************************************************************************
1444 * IFSFldr_PersistFolder3_QueryInterface
1447 static HRESULT WINAPI
1448 IFSFldr_PersistFolder3_QueryInterface (IPersistFolder3 * iface, REFIID iid,
1449 LPVOID * ppvObj)
1451 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1453 TRACE ("(%p)\n", This);
1455 return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj);
1458 /************************************************************************
1459 * IFSFldr_PersistFolder3_AddRef
1462 static ULONG WINAPI
1463 IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface)
1465 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1467 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1469 return IUnknown_AddRef (This->pUnkOuter);
1472 /************************************************************************
1473 * IFSFldr_PersistFolder3_Release
1476 static ULONG WINAPI
1477 IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface)
1479 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1481 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1483 return IUnknown_Release (This->pUnkOuter);
1486 /************************************************************************
1487 * IFSFldr_PersistFolder3_GetClassID
1489 static HRESULT WINAPI
1490 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1492 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1494 TRACE ("(%p)\n", This);
1496 if (!lpClassId)
1497 return E_POINTER;
1498 *lpClassId = *This->pclsid;
1500 return S_OK;
1503 /************************************************************************
1504 * IFSFldr_PersistFolder3_Initialize
1506 * NOTES
1507 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1509 static HRESULT WINAPI
1510 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1512 WCHAR wszTemp[MAX_PATH];
1514 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1516 TRACE ("(%p)->(%p)\n", This, pidl);
1518 SHFree (This->pidlRoot); /* free the old pidl */
1519 This->pidlRoot = ILClone (pidl); /* set my pidl */
1521 SHFree (This->sPathTarget);
1522 This->sPathTarget = NULL;
1524 /* set my path */
1525 if (SHGetPathFromIDListW (pidl, wszTemp)) {
1526 int len = strlenW(wszTemp);
1527 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1528 if (!This->sPathTarget)
1529 return E_OUTOFMEMORY;
1530 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1533 TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget));
1534 return S_OK;
1537 /**************************************************************************
1538 * IFSFldr_PersistFolder3_GetCurFolder
1540 static HRESULT WINAPI
1541 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1542 LPITEMIDLIST * pidl)
1544 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1546 TRACE ("(%p)->(%p)\n", This, pidl);
1548 if (!pidl) return E_POINTER;
1549 *pidl = ILClone (This->pidlRoot);
1550 return S_OK;
1553 /**************************************************************************
1554 * IFSFldr_PersistFolder3_InitializeEx
1556 * FIXME: error handling
1558 static HRESULT WINAPI
1559 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1560 IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1561 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1563 WCHAR wszTemp[MAX_PATH];
1565 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1567 TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1568 if (ppfti)
1569 TRACE ("--%p %s %s 0x%08x 0x%08x\n",
1570 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1571 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1572 ppfti->csidl);
1574 pdump (pidlRoot);
1575 if (ppfti && ppfti->pidlTargetFolder)
1576 pdump (ppfti->pidlTargetFolder);
1578 if (This->pidlRoot)
1579 __SHFreeAndNil (&This->pidlRoot); /* free the old */
1580 if (This->sPathTarget)
1581 __SHFreeAndNil (&This->sPathTarget);
1584 * Root path and pidl
1586 This->pidlRoot = ILClone (pidlRoot);
1589 * the target folder is specified in csidl OR pidlTargetFolder OR
1590 * szTargetParsingName
1592 if (ppfti) {
1593 if (ppfti->csidl != -1) {
1594 if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl,
1595 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1596 int len = strlenW(wszTemp);
1597 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1598 if (!This->sPathTarget)
1599 return E_OUTOFMEMORY;
1600 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1602 } else if (ppfti->szTargetParsingName[0]) {
1603 int len = strlenW(ppfti->szTargetParsingName);
1604 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1605 if (!This->sPathTarget)
1606 return E_OUTOFMEMORY;
1607 memcpy(This->sPathTarget, ppfti->szTargetParsingName,
1608 (len + 1) * sizeof(WCHAR));
1609 } else if (ppfti->pidlTargetFolder) {
1610 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) {
1611 int len = strlenW(wszTemp);
1612 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1613 if (!This->sPathTarget)
1614 return E_OUTOFMEMORY;
1615 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1620 TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget));
1621 pdump (This->pidlRoot);
1622 return (This->sPathTarget) ? S_OK : E_FAIL;
1625 static HRESULT WINAPI
1626 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1627 PERSIST_FOLDER_TARGET_INFO * ppfti)
1629 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1630 FIXME ("(%p)->(%p)\n", This, ppfti);
1631 ZeroMemory (ppfti, sizeof (*ppfti));
1632 return E_NOTIMPL;
1635 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3 =
1637 IFSFldr_PersistFolder3_QueryInterface,
1638 IFSFldr_PersistFolder3_AddRef,
1639 IFSFldr_PersistFolder3_Release,
1640 IFSFldr_PersistFolder3_GetClassID,
1641 IFSFldr_PersistFolder3_Initialize,
1642 IFSFldr_PersistFolder3_fnGetCurFolder,
1643 IFSFldr_PersistFolder3_InitializeEx,
1644 IFSFldr_PersistFolder3_GetFolderTargetInfo
1647 /****************************************************************************
1648 * ISFDropTarget implementation
1650 static BOOL
1651 ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState,
1652 LPDWORD pdwEffect)
1654 DWORD dwEffect = *pdwEffect;
1656 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1658 *pdwEffect = DROPEFFECT_NONE;
1660 if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */
1661 *pdwEffect = KeyStateToDropEffect (dwKeyState);
1663 /* ... matches the desired effect ? */
1664 if (dwEffect & *pdwEffect) {
1665 return TRUE;
1668 return FALSE;
1671 static HRESULT WINAPI
1672 ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj)
1674 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1676 TRACE ("(%p)\n", This);
1678 return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1681 static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface)
1683 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1685 TRACE ("(%p)\n", This);
1687 return IUnknown_AddRef (This->pUnkOuter);
1690 static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface)
1692 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1694 TRACE ("(%p)\n", This);
1696 return IUnknown_Release (This->pUnkOuter);
1699 static HRESULT WINAPI
1700 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1701 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1703 FORMATETC fmt;
1705 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1707 TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1709 InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1711 This->fAcceptFmt = (S_OK == IDataObject_QueryGetData (pDataObject, &fmt)) ?
1712 TRUE : FALSE;
1714 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1716 return S_OK;
1719 static HRESULT WINAPI
1720 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1721 DWORD * pdwEffect)
1723 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1725 TRACE ("(%p)\n", This);
1727 if (!pdwEffect)
1728 return E_INVALIDARG;
1730 ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1732 return S_OK;
1735 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1737 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1739 TRACE ("(%p)\n", This);
1741 This->fAcceptFmt = FALSE;
1743 return S_OK;
1746 static HRESULT WINAPI
1747 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1748 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1750 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1752 FIXME ("(%p) object dropped\n", This);
1754 return E_NOTIMPL;
1757 static const IDropTargetVtbl dtvt = {
1758 ISFDropTarget_QueryInterface,
1759 ISFDropTarget_AddRef,
1760 ISFDropTarget_Release,
1761 ISFDropTarget_DragEnter,
1762 ISFDropTarget_DragOver,
1763 ISFDropTarget_DragLeave,
1764 ISFDropTarget_Drop