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
25 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
28 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
29 returned by Next. When the enumerator is created, it can do numerous additional operations
30 including formatting a drive, reconnecting a network share drive, and requesting a disk
31 be inserted in a removable drive.
34 /***********************************************************************
35 * IShellFolder implementation
39 public IEnumIDListImpl
45 HRESULT WINAPI
Initialize(LPWSTR sPathTarget
, DWORD dwFlags
);
47 BEGIN_COM_MAP(CFileSysEnum
)
48 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
52 CFileSysEnum::CFileSysEnum()
56 CFileSysEnum::~CFileSysEnum()
60 HRESULT WINAPI
CFileSysEnum::Initialize(LPWSTR sPathTarget
, DWORD dwFlags
)
62 return CreateFolderEnumList(sPathTarget
, dwFlags
);
65 /**************************************************************************
66 * registers clipboardformat once
68 void CFSFolder::SF_RegisterClipFmt()
70 TRACE ("(%p)\n", this);
73 cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
76 CFSFolder::CFSFolder()
78 pclsid
= (CLSID
*)&CLSID_ShellFSFolder
;
85 CFSFolder::~CFSFolder()
87 TRACE("-- destroying IShellFolder(%p)\n", this);
94 static const shvheader GenericSFHeader
[] = {
95 {IDS_SHV_COLUMN1
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 15},
96 {IDS_SHV_COLUMN2
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
97 {IDS_SHV_COLUMN3
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
98 {IDS_SHV_COLUMN4
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 12},
99 {IDS_SHV_COLUMN5
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 5}
102 #define GENERICSHELLVIEWCOLUMNS 5
104 /**************************************************************************
105 * SHELL32_CreatePidlFromBindCtx [internal]
107 * If the caller bound File System Bind Data, assume it is the
108 * find data for the path.
109 * This allows binding of paths that don't exist.
111 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
113 IFileSystemBindData
*fsbd
= NULL
;
114 LPITEMIDLIST pidl
= NULL
;
115 IUnknown
*param
= NULL
;
116 WIN32_FIND_DATAW wfd
;
119 TRACE("%p %s\n", pbc
, debugstr_w(path
));
124 /* see if the caller bound File System Bind Data */
125 r
= pbc
->GetObjectParam((LPOLESTR
)STR_FILE_SYS_BIND_DATA
, ¶m
);
129 r
= param
->QueryInterface(IID_PPV_ARG(IFileSystemBindData
,&fsbd
));
132 r
= fsbd
->GetFindData(&wfd
);
135 lstrcpynW(&wfd
.cFileName
[0], path
, MAX_PATH
);
136 pidl
= _ILCreateFromFindDataW(&wfd
);
144 /**************************************************************************
145 * CFSFolder::ParseDisplayName {SHELL32}
147 * Parse a display name.
150 * hwndOwner [in] Parent window for any message's
151 * pbc [in] optional FileSystemBindData context
152 * lpszDisplayName [in] Unicode displayname.
153 * pchEaten [out] (unicode) characters processed
154 * ppidl [out] complex pidl to item
155 * pdwAttributes [out] items attributes
158 * Every folder tries to parse only its own (the leftmost) pidl and creates a
159 * subfolder to evaluate the remaining parts.
160 * Now we can parse into namespaces implemented by shell extensions
162 * Behaviour on win98: lpszDisplayName=NULL -> crash
163 * lpszDisplayName="" -> returns mycoputer-pidl
166 * pdwAttributes is not set
167 * pchEaten is not set like in windows
169 HRESULT WINAPI
CFSFolder::ParseDisplayName(HWND hwndOwner
,
171 LPOLESTR lpszDisplayName
,
172 DWORD
*pchEaten
, LPITEMIDLIST
*ppidl
,
173 DWORD
*pdwAttributes
)
175 HRESULT hr
= E_INVALIDARG
;
176 LPCWSTR szNext
= NULL
;
177 WCHAR szElement
[MAX_PATH
];
178 WCHAR szPath
[MAX_PATH
];
179 LPITEMIDLIST pidlTemp
= NULL
;
182 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
183 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
184 pchEaten
, ppidl
, pdwAttributes
);
189 if (!lpszDisplayName
)
198 *pchEaten
= 0; /* strange but like the original */
200 if (*lpszDisplayName
)
202 /* get the next element */
203 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
205 pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, szElement
);
206 if (pidlTemp
!= NULL
)
212 /* build the full pathname to the element */
213 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
- 1);
214 PathAddBackslashW(szPath
);
215 len
= wcslen(szPath
);
216 lstrcpynW(szPath
+ len
, szElement
, MAX_PATH
- len
);
219 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
224 if (szNext
&& *szNext
)
226 /* try to analyse the next element */
227 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
228 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
232 /* it's the last element */
233 if (pdwAttributes
&& *pdwAttributes
)
234 hr
= SHELL32_GetItemAttributes(this, pidlTemp
, pdwAttributes
);
244 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl
? *ppidl
: 0, hr
);
249 /**************************************************************************
250 * CFSFolder::EnumObjects
252 * HWND hwndOwner, //[in ] Parent Window
253 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
254 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
256 HRESULT WINAPI
CFSFolder::EnumObjects(
259 LPENUMIDLIST
*ppEnumIDList
)
261 CComObject
<CFileSysEnum
> *theEnumerator
;
262 CComPtr
<IEnumIDList
> result
;
265 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner
, dwFlags
, ppEnumIDList
);
267 if (ppEnumIDList
== NULL
)
269 *ppEnumIDList
= NULL
;
270 ATLTRY (theEnumerator
= new CComObject
<CFileSysEnum
>);
271 if (theEnumerator
== NULL
)
272 return E_OUTOFMEMORY
;
273 hResult
= theEnumerator
->QueryInterface(IID_PPV_ARG(IEnumIDList
, &result
));
276 delete theEnumerator
;
279 hResult
= theEnumerator
->Initialize (sPathTarget
, dwFlags
);
280 if (FAILED (hResult
))
282 *ppEnumIDList
= result
.Detach();
284 TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList
);
289 /**************************************************************************
290 * CFSFolder::BindToObject
292 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
293 * LPBC pbc, //[in ] optional FileSystemBindData context
294 * REFIID riid, //[in ] Initial Interface
295 * LPVOID* ppvObject //[out] Interface*
297 HRESULT WINAPI
CFSFolder::BindToObject(
303 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbc
,
304 shdebugstr_guid(&riid
), ppvOut
);
306 return SHELL32_BindToChild(pidlRoot
, sPathTarget
, pidl
, riid
, ppvOut
);
309 /**************************************************************************
310 * CFSFolder::BindToStorage
312 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
313 * LPBC pbc, //[in ] reserved
314 * REFIID riid, //[in ] Initial storage interface
315 * LPVOID* ppvObject //[out] Interface* returned
317 HRESULT WINAPI
CFSFolder::BindToStorage(
323 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
,
324 shdebugstr_guid (&riid
), ppvOut
);
330 /**************************************************************************
331 * CFSFolder::CompareIDs
334 HRESULT WINAPI
CFSFolder::CompareIDs(LPARAM lParam
,
335 LPCITEMIDLIST pidl1
, LPCITEMIDLIST pidl2
)
339 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam
, pidl1
, pidl2
);
340 nReturn
= SHELL32_CompareIDs(this, lParam
, pidl1
, pidl2
);
341 TRACE("-- %i\n", nReturn
);
345 /**************************************************************************
346 * CFSFolder::CreateViewObject
348 HRESULT WINAPI
CFSFolder::CreateViewObject(HWND hwndOwner
,
349 REFIID riid
, LPVOID
* ppvOut
)
351 LPSHELLVIEW pShellView
;
352 HRESULT hr
= E_INVALIDARG
;
354 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid (&riid
),
361 if (IsEqualIID (riid
, IID_IDropTarget
))
362 hr
= this->QueryInterface (IID_IDropTarget
, ppvOut
);
363 else if (IsEqualIID (riid
, IID_IContextMenu
))
365 FIXME ("IContextMenu not implemented\n");
368 else if (IsEqualIID (riid
, IID_IShellView
))
370 hr
= IShellView_Constructor ((IShellFolder
*)this, &pShellView
);
373 hr
= pShellView
->QueryInterface(riid
, ppvOut
);
374 pShellView
->Release();
378 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
382 /**************************************************************************
383 * CFSFolder::GetAttributesOf
386 * UINT cidl, //[in ] num elements in pidl array
387 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
388 * ULONG* rgfInOut) //[out] result array
391 HRESULT WINAPI
CFSFolder::GetAttributesOf(UINT cidl
,
392 LPCITEMIDLIST
* apidl
, DWORD
* rgfInOut
)
396 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this, cidl
, apidl
,
397 rgfInOut
, rgfInOut
? *rgfInOut
: 0);
409 IShellFolder
*psfParent
= NULL
;
410 LPCITEMIDLIST rpidl
= NULL
;
412 hr
= SHBindToParent(pidlRoot
, IID_PPV_ARG(IShellFolder
, &psfParent
), &rpidl
);
415 SHELL32_GetItemAttributes (psfParent
, rpidl
, rgfInOut
);
416 psfParent
->Release();
421 while (cidl
> 0 && *apidl
)
424 SHELL32_GetItemAttributes(this, *apidl
, rgfInOut
);
429 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
430 *rgfInOut
&= ~SFGAO_VALIDATE
;
432 TRACE("-- result=0x%08x\n", *rgfInOut
);
437 /**************************************************************************
438 * CFSFolder::GetUIObjectOf
441 * HWND hwndOwner, //[in ] Parent window for any output
442 * UINT cidl, //[in ] array size
443 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
444 * REFIID riid, //[in ] Requested Interface
445 * UINT* prgfInOut, //[ ] reserved
446 * LPVOID* ppvObject) //[out] Resulting Interface
449 * This function gets asked to return "view objects" for one or more (multiple
451 * The viewobject typically is an COM object with one of the following
453 * IExtractIcon,IDataObject,IContextMenu
454 * In order to support icon positions in the default Listview your DataObject
455 * must implement the SetData method (in addition to GetData :) - the shell
456 * passes a barely documented "Icon positions" structure to SetData when the
457 * drag starts, and GetData's it if the drop is in another explorer window that
458 * needs the positions.
460 HRESULT WINAPI
CFSFolder::GetUIObjectOf(HWND hwndOwner
,
461 UINT cidl
, LPCITEMIDLIST
* apidl
, REFIID riid
,
462 UINT
* prgfInOut
, LPVOID
* ppvOut
)
465 IUnknown
*pObj
= NULL
;
466 HRESULT hr
= E_INVALIDARG
;
468 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
469 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
475 if (IsEqualIID (riid
, IID_IContextMenu
) && (cidl
>= 1))
476 hr
= CDefFolderMenu_Create2(pidlRoot
, hwndOwner
, cidl
, apidl
, (IShellFolder
*)this, NULL
, 0, NULL
, (IContextMenu
**)&pObj
);
477 else if (IsEqualIID (riid
, IID_IDataObject
))
480 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
484 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, (LPCITEMIDLIST
*)&pidlRoot
, 1, (IDataObject
**)&pObj
);
487 else if (IsEqualIID (riid
, IID_IExtractIconA
) && (cidl
== 1))
489 pidl
= ILCombine (pidlRoot
, apidl
[0]);
490 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor (pidl
);
494 else if (IsEqualIID (riid
, IID_IExtractIconW
) && (cidl
== 1))
496 pidl
= ILCombine (pidlRoot
, apidl
[0]);
497 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor (pidl
);
501 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
>= 1))
502 hr
= this->QueryInterface(IID_IDropTarget
, (LPVOID
*)&pObj
);
503 else if ((IsEqualIID(riid
, IID_IShellLinkW
) ||
504 IsEqualIID(riid
, IID_IShellLinkA
)) && (cidl
== 1))
506 pidl
= ILCombine (pidlRoot
, apidl
[0]);
507 hr
= IShellLink_ConstructFromFile(NULL
, riid
, pidl
, (LPVOID
*)&pObj
);
513 if (SUCCEEDED(hr
) && !pObj
)
518 TRACE("(%p)->hr=0x%08x\n", this, hr
);
522 static const WCHAR AdvancedW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
523 static const WCHAR HideFileExtW
[] = L
"HideFileExt";
524 static const WCHAR NeverShowExtW
[] = L
"NeverShowExt";
526 /******************************************************************************
527 * SHELL_FS_HideExtension [Internal]
529 * Query the registry if the filename extension of a given path should be
533 * szPath [I] Relative or absolute path of a file
536 * TRUE, if the filename's extension should be hidden
539 BOOL
SHELL_FS_HideExtension(LPWSTR szPath
)
543 DWORD dwDataSize
= sizeof (DWORD
);
544 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
546 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, AdvancedW
, 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
547 if (!RegQueryValueExW(hKey
, HideFileExtW
, 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
553 LPWSTR ext
= PathFindExtensionW(szPath
);
556 WCHAR classname
[MAX_PATH
];
557 LONG classlen
= sizeof(classname
);
559 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
560 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
561 if (!RegQueryValueExW(hKey
, NeverShowExtW
, 0, NULL
, NULL
, NULL
))
570 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
572 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
573 if (!(dwFlags
& SHGDN_FORPARSING
) &&
574 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
575 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
576 PathRemoveExtensionW(szPath
);
580 /**************************************************************************
581 * CFSFolder::GetDisplayNameOf
582 * Retrieves the display name for the specified file object or subfolder
585 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
586 * DWORD dwFlags, //[in ] SHGNO formatting flags
587 * LPSTRRET lpName) //[out] Returned display name
590 * if the name is in the pidl the ret value should be a STRRET_OFFSET
593 HRESULT WINAPI
CFSFolder::GetDisplayNameOf(LPCITEMIDLIST pidl
,
594 DWORD dwFlags
, LPSTRRET strRet
)
601 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
604 if (!pidl
|| !strRet
)
607 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
609 return E_OUTOFMEMORY
;
611 if (_ILIsDesktop(pidl
)) /* empty pidl */
613 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
614 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
))
617 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
620 hr
= E_INVALIDARG
; /* pidl has to contain exactly one non null SHITEMID */
622 else if (_ILIsPidlSimple(pidl
))
624 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
625 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
628 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
629 PathAddBackslashW(pszPath
);
630 len
= wcslen(pszPath
);
632 _ILSimpleGetTextW(pidl
, pszPath
+ len
, MAX_PATH
+ 1 - len
);
633 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
635 hr
= SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, pszPath
, MAX_PATH
);
638 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
639 if (GetVersion() & 0x80000000)
641 strRet
->uType
= STRRET_CSTR
;
642 if (!WideCharToMultiByte(CP_ACP
, 0, pszPath
, -1, strRet
->cStr
, MAX_PATH
,
644 strRet
->cStr
[0] = '\0';
645 CoTaskMemFree(pszPath
);
649 strRet
->uType
= STRRET_WSTR
;
650 strRet
->pOleStr
= pszPath
;
653 CoTaskMemFree(pszPath
);
655 TRACE ("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
659 /**************************************************************************
660 * CFSFolder::SetNameOf
661 * Changes the name of a file object or subfolder, possibly changing its item
662 * identifier in the process.
665 * HWND hwndOwner, //[in ] Owner window for output
666 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
667 * LPCOLESTR lpszName, //[in ] the items new display name
668 * DWORD dwFlags, //[in ] SHGNO formatting flags
669 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
671 HRESULT WINAPI
CFSFolder::SetNameOf(
676 LPITEMIDLIST
* pPidlOut
)
678 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
680 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
682 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
683 debugstr_w (lpName
), dwFlags
, pPidlOut
);
685 /* build source path */
686 lstrcpynW(szSrc
, sPathTarget
, MAX_PATH
);
687 ptr
= PathAddBackslashW (szSrc
);
689 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
691 /* build destination path */
692 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
) {
693 lstrcpynW(szDest
, sPathTarget
, MAX_PATH
);
694 ptr
= PathAddBackslashW (szDest
);
696 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
698 lstrcpynW(szDest
, lpName
, MAX_PATH
);
700 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
701 WCHAR
*ext
= PathFindExtensionW(szSrc
);
703 INT len
= wcslen(szDest
);
704 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
708 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
709 if (!memcmp(szSrc
, szDest
, (wcslen(szDest
) + 1) * sizeof(WCHAR
)))
711 /* src and destination is the same */
714 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
720 if (MoveFileW (szSrc
, szDest
))
725 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
727 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
728 SHCNF_PATHW
, szSrc
, szDest
);
736 HRESULT WINAPI
CFSFolder::GetDefaultSearchGUID(GUID
* pguid
)
738 FIXME ("(%p)\n", this);
742 HRESULT WINAPI
CFSFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
744 FIXME ("(%p)\n", this);
748 HRESULT WINAPI
CFSFolder::GetDefaultColumn(DWORD dwRes
,
749 ULONG
* pSort
, ULONG
* pDisplay
)
751 TRACE ("(%p)\n", this);
761 HRESULT WINAPI
CFSFolder::GetDefaultColumnState(UINT iColumn
,
764 TRACE ("(%p)\n", this);
766 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
769 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
774 HRESULT WINAPI
CFSFolder::GetDetailsEx(LPCITEMIDLIST pidl
,
775 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
777 FIXME ("(%p)\n", this);
782 HRESULT WINAPI
CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl
,
783 UINT iColumn
, SHELLDETAILS
* psd
)
787 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
789 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
794 /* the header titles */
795 psd
->fmt
= GenericSFHeader
[iColumn
].fmt
;
796 psd
->cxChar
= GenericSFHeader
[iColumn
].cxChar
;
797 psd
->str
.uType
= STRRET_CSTR
;
798 LoadStringA(shell32_hInstance
, GenericSFHeader
[iColumn
].colnameid
,
799 psd
->str
.cStr
, MAX_PATH
);
805 psd
->str
.uType
= STRRET_CSTR
;
806 /* the data from the pidl */
810 hr
= GetDisplayNameOf (pidl
,
811 SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
814 _ILGetFileSize(pidl
, psd
->str
.cStr
, MAX_PATH
);
817 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
820 _ILGetFileDate(pidl
, psd
->str
.cStr
, MAX_PATH
);
822 case 4: /* attributes */
823 _ILGetFileAttributes(pidl
, psd
->str
.cStr
, MAX_PATH
);
831 HRESULT WINAPI
CFSFolder::MapColumnToSCID (UINT column
,
834 FIXME ("(%p)\n", this);
838 /****************************************************************************
839 * ISFHelper for IShellFolder implementation
842 /****************************************************************************
843 * CFSFolder::GetUniqueName
845 * creates a unique folder name
848 HRESULT WINAPI
CFSFolder::GetUniqueName(LPWSTR pwszName
, UINT uLen
)
852 WCHAR wszText
[MAX_PATH
];
853 WCHAR wszNewFolder
[25];
854 const WCHAR wszFormat
[] = L
"%s %d";
856 LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, _countof(wszNewFolder
));
858 TRACE ("(%p)(%p %u)\n", this, pwszName
, uLen
);
860 if (uLen
< _countof(wszNewFolder
) + 3)
863 lstrcpynW (pwszName
, wszNewFolder
, uLen
);
865 hr
= EnumObjects(0, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penum
);
874 while (S_OK
== penum
->Next(1, &pidl
, &dwFetched
) && dwFetched
)
876 _ILSimpleGetTextW(pidl
, wszText
, MAX_PATH
);
877 if (0 == lstrcmpiW(wszText
, pwszName
))
879 _snwprintf(pwszName
, uLen
, wszFormat
, wszNewFolder
, i
++);
894 /****************************************************************************
895 * CFSFolder::AddFolder
900 HRESULT WINAPI
CFSFolder::AddFolder(HWND hwnd
, LPCWSTR pwszName
,
901 LPITEMIDLIST
* ppidlOut
)
903 WCHAR wszNewDir
[MAX_PATH
];
905 HRESULT hres
= E_FAIL
;
907 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName
), ppidlOut
);
911 lstrcpynW(wszNewDir
, sPathTarget
, MAX_PATH
);
912 PathAppendW(wszNewDir
, pwszName
);
914 bRes
= CreateDirectoryW(wszNewDir
, NULL
);
917 SHChangeNotify(SHCNE_MKDIR
, SHCNF_PATHW
, wszNewDir
, NULL
);
922 hres
= _ILCreateFromPathW(wszNewDir
, ppidlOut
);
926 WCHAR wszText
[128 + MAX_PATH
];
927 WCHAR wszTempText
[128];
928 WCHAR wszCaption
[256];
930 /* Cannot Create folder because of permissions */
931 LoadStringW(shell32_hInstance
, IDS_CREATEFOLDER_DENIED
, wszTempText
,
932 _countof(wszTempText
));
933 LoadStringW(shell32_hInstance
, IDS_CREATEFOLDER_CAPTION
, wszCaption
,
934 _countof(wszCaption
));
935 swprintf(wszText
, wszTempText
, wszNewDir
);
936 MessageBoxW(hwnd
, wszText
, wszCaption
, MB_OK
| MB_ICONEXCLAMATION
);
942 /****************************************************************************
945 * Builds a list of paths like the one used in SHFileOperation from a table of
946 * PIDLs relative to the given base folder
949 BuildPathsList(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
)
951 WCHAR
*pwszPathsList
;
955 iPathLen
= wcslen(wszBasePath
);
956 pwszPathsList
= (WCHAR
*)HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
) * cidl
+ 1);
957 pwszListPos
= pwszPathsList
;
959 for (i
= 0; i
< cidl
; i
++)
961 if (!_ILIsFolder(pidls
[i
]) && !_ILIsValue(pidls
[i
]))
964 wcscpy(pwszListPos
, wszBasePath
);
965 pwszListPos
+= iPathLen
;
966 /* FIXME: abort if path too long */
967 _ILSimpleGetTextW(pidls
[i
], pwszListPos
, MAX_PATH
- iPathLen
);
968 pwszListPos
+= wcslen(pwszListPos
) + 1;
971 return pwszPathsList
;
974 /****************************************************************************
975 * CFSFolder::DeleteItems
977 * deletes items in folder
979 HRESULT WINAPI
CFSFolder::DeleteItems(UINT cidl
, LPCITEMIDLIST
*apidl
)
983 WCHAR wszPath
[MAX_PATH
];
986 WCHAR
*wszCurrentPath
;
988 TRACE ("(%p)(%u %p)\n", this, cidl
, apidl
);
989 if (cidl
== 0) return S_OK
;
992 lstrcpynW(wszPath
, sPathTarget
, MAX_PATH
);
995 PathAddBackslashW(wszPath
);
996 wszPathsList
= BuildPathsList(wszPath
, cidl
, apidl
);
998 ZeroMemory(&op
, sizeof(op
));
999 op
.hwnd
= GetActiveWindow();
1000 op
.wFunc
= FO_DELETE
;
1001 op
.pFrom
= wszPathsList
;
1002 op
.fFlags
= FOF_ALLOWUNDO
;
1003 if (SHFileOperationW(&op
))
1005 WARN("SHFileOperation failed\n");
1011 /* we currently need to manually send the notifies */
1012 wszCurrentPath
= wszPathsList
;
1013 for (i
= 0; i
< cidl
; i
++)
1017 if (_ILIsFolder(apidl
[i
]))
1018 wEventId
= SHCNE_RMDIR
;
1019 else if (_ILIsValue(apidl
[i
]))
1020 wEventId
= SHCNE_DELETE
;
1024 /* check if file exists */
1025 if (GetFileAttributesW(wszCurrentPath
) == INVALID_FILE_ATTRIBUTES
)
1027 LPITEMIDLIST pidl
= ILCombine(pidlRoot
, apidl
[i
]);
1028 SHChangeNotify(wEventId
, SHCNF_IDLIST
, pidl
, NULL
);
1032 wszCurrentPath
+= wcslen(wszCurrentPath
) + 1;
1034 HeapFree(GetProcessHeap(), 0, wszPathsList
);
1038 /****************************************************************************
1039 * CFSFolder::CopyItems
1041 * copies items to this folder
1043 HRESULT WINAPI
CFSFolder::CopyItems(IShellFolder
* pSFFrom
, UINT cidl
,
1044 LPCITEMIDLIST
* apidl
, bool bCopy
)
1046 IPersistFolder2
*ppf2
= NULL
;
1047 WCHAR szSrcPath
[MAX_PATH
];
1048 WCHAR szTargetPath
[MAX_PATH
];
1051 LPWSTR pszSrc
, pszTarget
, pszSrcList
, pszTargetList
, pszFileName
;
1056 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom
, cidl
, apidl
);
1058 hr
= pSFFrom
->QueryInterface (IID_PPV_ARG(IPersistFolder2
, &ppf2
));
1061 hr
= ppf2
->GetCurFolder(&pidl
);
1069 hr
= pSFFrom
->GetDisplayNameOf(pidl
, SHGDN_FORPARSING
, &strRet
);
1076 hr
= StrRetToBufW(&strRet
, pidl
, szSrcPath
, MAX_PATH
);
1084 pszSrc
= PathAddBackslashW(szSrcPath
);
1086 wcscpy(szTargetPath
, sPathTarget
);
1087 pszTarget
= PathAddBackslashW(szTargetPath
);
1089 pszSrcList
= BuildPathsList(szSrcPath
, cidl
, apidl
);
1090 pszTargetList
= BuildPathsList(szTargetPath
, cidl
, apidl
);
1092 if (!pszSrcList
|| !pszTargetList
)
1095 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1098 HeapFree(GetProcessHeap(), 0, pszTargetList
);
1102 return E_OUTOFMEMORY
;
1105 ZeroMemory(&op
, sizeof(op
));
1108 /* remove trailing backslash */
1111 op
.pFrom
= szSrcPath
;
1115 op
.pFrom
= pszSrcList
;
1118 if (!pszTargetList
[0])
1120 /* remove trailing backslash */
1121 if (pszTarget
- szTargetPath
> 3)
1124 pszTarget
[0] = L
'\0';
1128 pszTarget
[1] = L
'\0';
1131 op
.pTo
= szTargetPath
;
1136 op
.pTo
= pszTargetList
;
1137 op
.fFlags
= FOF_MULTIDESTFILES
;
1139 op
.hwnd
= GetActiveWindow();
1140 op
.wFunc
= bCopy
? FO_COPY
: FO_MOVE
;
1141 op
.fFlags
|= FOF_ALLOWUNDO
| FOF_NOCONFIRMMKDIR
;
1143 res
= SHFileOperationW(&op
);
1145 if (res
== DE_SAMEFILE
)
1147 length
= wcslen(szTargetPath
);
1149 pszFileName
= wcsrchr(pszSrcList
, '\\');
1152 if (LoadStringW(shell32_hInstance
, IDS_COPY_OF
, pszTarget
, MAX_PATH
- length
))
1154 wcscat(szTargetPath
, L
" ");
1157 wcscat(szTargetPath
, pszFileName
);
1158 op
.pTo
= szTargetPath
;
1160 res
= SHFileOperationW(&op
);
1163 HeapFree(GetProcessHeap(), 0, pszSrcList
);
1164 HeapFree(GetProcessHeap(), 0, pszTargetList
);
1174 /************************************************************************
1175 * CFSFolder::GetClassID
1177 HRESULT WINAPI
CFSFolder::GetClassID(CLSID
* lpClassId
)
1179 TRACE ("(%p)\n", this);
1184 *lpClassId
= *pclsid
;
1189 /************************************************************************
1190 * CFSFolder::Initialize
1193 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1195 HRESULT WINAPI
CFSFolder::Initialize(LPCITEMIDLIST pidl
)
1197 WCHAR wszTemp
[MAX_PATH
];
1199 TRACE ("(%p)->(%p)\n", this, pidl
);
1201 SHFree (pidlRoot
); /* free the old pidl */
1202 pidlRoot
= ILClone (pidl
); /* set my pidl */
1204 SHFree (sPathTarget
);
1208 if (SHGetPathFromIDListW (pidl
, wszTemp
))
1210 int len
= wcslen(wszTemp
);
1211 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1213 return E_OUTOFMEMORY
;
1214 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1217 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget
));
1221 /**************************************************************************
1222 * CFSFolder::GetCurFolder
1224 HRESULT WINAPI
CFSFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1226 TRACE ("(%p)->(%p)\n", this, pidl
);
1231 *pidl
= ILClone(pidlRoot
);
1235 /**************************************************************************
1236 * CFSFolder::InitializeEx
1238 * FIXME: error handling
1240 HRESULT WINAPI
CFSFolder::InitializeEx(IBindCtx
* pbc
, LPCITEMIDLIST pidlRootx
,
1241 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1243 WCHAR wszTemp
[MAX_PATH
];
1245 TRACE("(%p)->(%p,%p,%p)\n", this, pbc
, pidlRootx
, ppfti
);
1247 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1248 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1249 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1253 if (ppfti
&& ppfti
->pidlTargetFolder
)
1254 pdump(ppfti
->pidlTargetFolder
);
1257 __SHFreeAndNil(&pidlRoot
); /* free the old */
1259 __SHFreeAndNil(&sPathTarget
);
1262 * Root path and pidl
1264 pidlRoot
= ILClone(pidlRootx
);
1267 * the target folder is spezified in csidl OR pidlTargetFolder OR
1268 * szTargetParsingName
1272 if (ppfti
->csidl
!= -1)
1274 if (SHGetSpecialFolderPathW(0, wszTemp
, ppfti
->csidl
,
1275 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1276 int len
= wcslen(wszTemp
);
1277 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1279 return E_OUTOFMEMORY
;
1280 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1283 else if (ppfti
->szTargetParsingName
[0])
1285 int len
= wcslen(ppfti
->szTargetParsingName
);
1286 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1288 return E_OUTOFMEMORY
;
1289 memcpy(sPathTarget
, ppfti
->szTargetParsingName
,
1290 (len
+ 1) * sizeof(WCHAR
));
1292 else if (ppfti
->pidlTargetFolder
)
1294 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
))
1296 int len
= wcslen(wszTemp
);
1297 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1299 return E_OUTOFMEMORY
;
1300 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1305 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget
));
1307 return (sPathTarget
) ? S_OK
: E_FAIL
;
1310 HRESULT WINAPI
CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1312 FIXME("(%p)->(%p)\n", this, ppfti
);
1313 ZeroMemory(ppfti
, sizeof (*ppfti
));
1317 /****************************************************************************
1318 * ISFDropTarget implementation
1320 BOOL
CFSFolder::QueryDrop(DWORD dwKeyState
, LPDWORD pdwEffect
)
1322 DWORD dwEffect
= *pdwEffect
;
1324 *pdwEffect
= DROPEFFECT_NONE
;
1326 if (fAcceptFmt
) { /* Does our interpretation of the keystate ... */
1327 *pdwEffect
= KeyStateToDropEffect (dwKeyState
);
1329 /* ... matches the desired effect ? */
1330 if (dwEffect
& *pdwEffect
) {
1337 HRESULT WINAPI
CFSFolder::DragEnter(IDataObject
*pDataObject
,
1338 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1342 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject
);
1344 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1346 fAcceptFmt
= (S_OK
== pDataObject
->QueryGetData(&fmt
)) ?
1349 QueryDrop(dwKeyState
, pdwEffect
);
1354 HRESULT WINAPI
CFSFolder::DragOver(DWORD dwKeyState
, POINTL pt
,
1357 TRACE("(%p)\n", this);
1360 return E_INVALIDARG
;
1362 QueryDrop(dwKeyState
, pdwEffect
);
1367 HRESULT WINAPI
CFSFolder::DragLeave()
1369 TRACE("(%p)\n", this);
1376 HRESULT WINAPI
CFSFolder::Drop(IDataObject
*pDataObject
,
1377 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1379 FIXME("(%p) object dropped\n", this);