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 CEnumIDListBase
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 lpszPath
, DWORD dwFlags
)
62 WIN32_FIND_DATAW stffile
;
64 WCHAR szPath
[MAX_PATH
];
65 BOOL succeeded
= TRUE
;
66 static const WCHAR stars
[] = { '*','.','*',0 };
67 static const WCHAR dot
[] = { '.',0 };
68 static const WCHAR dotdot
[] = { '.','.',0 };
70 TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath
), dwFlags
);
72 if(!lpszPath
|| !lpszPath
[0]) return FALSE
;
74 wcscpy(szPath
, lpszPath
);
75 PathAddBackslashW(szPath
);
78 hFile
= FindFirstFileW(szPath
,&stffile
);
79 if ( hFile
!= INVALID_HANDLE_VALUE
)
81 BOOL findFinished
= FALSE
;
85 if ( !(stffile
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
86 || (dwFlags
& SHCONTF_INCLUDEHIDDEN
) )
88 LPITEMIDLIST pidl
= NULL
;
90 if ( (stffile
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
91 dwFlags
& SHCONTF_FOLDERS
&&
92 strcmpW(stffile
.cFileName
, dot
) && strcmpW(stffile
.cFileName
, dotdot
))
94 pidl
= _ILCreateFromFindDataW(&stffile
);
95 succeeded
= succeeded
&& AddToEnumList(pidl
);
97 else if (!(stffile
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
98 && dwFlags
& SHCONTF_NONFOLDERS
)
100 pidl
= _ILCreateFromFindDataW(&stffile
);
101 succeeded
= succeeded
&& AddToEnumList(pidl
);
106 if (!FindNextFileW(hFile
, &stffile
))
108 if (GetLastError() == ERROR_NO_MORE_FILES
)
114 } while (succeeded
&& !findFinished
);
121 CFSFolder::CFSFolder()
123 pclsid
= (CLSID
*)&CLSID_ShellFSFolder
;
126 m_bGroupPolicyActive
= 0;
129 CFSFolder::~CFSFolder()
131 TRACE("-- destroying IShellFolder(%p)\n", this);
138 static const shvheader GenericSFHeader
[] = {
139 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
140 {IDS_SHV_COLUMN_COMMENTS
, SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 0},
141 {IDS_SHV_COLUMN_TYPE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
142 {IDS_SHV_COLUMN_SIZE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
143 {IDS_SHV_COLUMN_MODIFIED
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 12},
144 {IDS_SHV_COLUMN_ATTRIBUTES
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10}
147 #define GENERICSHELLVIEWCOLUMNS 6
149 /**************************************************************************
150 * SHELL32_CreatePidlFromBindCtx [internal]
152 * If the caller bound File System Bind Data, assume it is the
153 * find data for the path.
154 * This allows binding of paths that don't exist.
156 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
158 IFileSystemBindData
*fsbd
= NULL
;
159 LPITEMIDLIST pidl
= NULL
;
160 IUnknown
*param
= NULL
;
161 WIN32_FIND_DATAW wfd
;
164 TRACE("%p %s\n", pbc
, debugstr_w(path
));
169 /* see if the caller bound File System Bind Data */
170 r
= pbc
->GetObjectParam((LPOLESTR
)STR_FILE_SYS_BIND_DATA
, ¶m
);
174 r
= param
->QueryInterface(IID_PPV_ARG(IFileSystemBindData
,&fsbd
));
177 r
= fsbd
->GetFindData(&wfd
);
180 lstrcpynW(&wfd
.cFileName
[0], path
, MAX_PATH
);
181 pidl
= _ILCreateFromFindDataW(&wfd
);
189 void SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir
, CLSID
* pclsidFolder
)
191 WCHAR wszCLSIDValue
[CHARS_IN_GUID
];
192 WCHAR wszDesktopIni
[MAX_PATH
];
193 StringCchCopyW(wszDesktopIni
, MAX_PATH
, pwszDir
);
194 StringCchCatW(wszDesktopIni
, MAX_PATH
, L
"\\desktop.ini");
196 if (GetPrivateProfileStringW(L
".ShellClassInfo",
203 CLSIDFromString (wszCLSIDValue
, pclsidFolder
);
208 static const DWORD dwSupportedAttr
=
209 SFGAO_CANCOPY
| /*0x00000001 */
210 SFGAO_CANMOVE
| /*0x00000002 */
211 SFGAO_CANLINK
| /*0x00000004 */
212 SFGAO_CANRENAME
| /*0x00000010 */
213 SFGAO_CANDELETE
| /*0x00000020 */
214 SFGAO_HASPROPSHEET
| /*0x00000040 */
215 SFGAO_DROPTARGET
| /*0x00000100 */
216 SFGAO_LINK
| /*0x00010000 */
217 SFGAO_READONLY
| /*0x00040000 */
218 SFGAO_HIDDEN
| /*0x00080000 */
219 SFGAO_FILESYSANCESTOR
| /*0x10000000 */
220 SFGAO_FOLDER
| /*0x20000000 */
221 SFGAO_FILESYSTEM
| /*0x40000000 */
222 SFGAO_HASSUBFOLDER
; /*0x80000000 */
224 HRESULT
SHELL32_GetFSItemAttributes(IShellFolder
* psf
, LPCITEMIDLIST pidl
, LPDWORD pdwAttributes
)
226 DWORD dwFileAttributes
, dwShellAttributes
;
228 if (!_ILIsFolder(pidl
) && !_ILIsValue(pidl
))
230 ERR("Got wrong type of pidl!\n");
231 *pdwAttributes
&= SFGAO_CANLINK
;
235 if (*pdwAttributes
& ~dwSupportedAttr
)
237 WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes
& ~dwSupportedAttr
));
238 *pdwAttributes
&= dwSupportedAttr
;
241 dwFileAttributes
= _ILGetFileAttributes(pidl
, NULL
, 0);
243 /* Set common attributes */
244 dwShellAttributes
= *pdwAttributes
;
245 dwShellAttributes
|= SFGAO_FILESYSTEM
| SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANDELETE
|
246 SFGAO_CANRENAME
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANCOPY
;
248 if (dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
250 dwShellAttributes
|= (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
);
253 dwShellAttributes
&= ~(SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
);
255 if (dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
256 dwShellAttributes
|= SFGAO_HIDDEN
;
258 dwShellAttributes
&= ~SFGAO_HIDDEN
;
260 if (dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
261 dwShellAttributes
|= SFGAO_READONLY
;
263 dwShellAttributes
&= ~SFGAO_READONLY
;
265 if (SFGAO_LINK
& *pdwAttributes
)
269 if (!_ILGetExtension(pidl
, ext
, MAX_PATH
) || lstrcmpiA(ext
, "lnk"))
270 dwShellAttributes
&= ~SFGAO_LINK
;
273 if (SFGAO_HASSUBFOLDER
& *pdwAttributes
)
275 CComPtr
<IShellFolder
> psf2
;
276 if (SUCCEEDED(psf
->BindToObject(pidl
, 0, IID_PPV_ARG(IShellFolder
, &psf2
))))
278 CComPtr
<IEnumIDList
> pEnumIL
;
279 if (SUCCEEDED(psf2
->EnumObjects(0, SHCONTF_FOLDERS
, &pEnumIL
)))
281 if (pEnumIL
->Skip(1) != S_OK
)
282 dwShellAttributes
&= ~SFGAO_HASSUBFOLDER
;
287 *pdwAttributes
&= dwShellAttributes
;
289 TRACE ("-- 0x%08x\n", *pdwAttributes
);
293 /**************************************************************************
294 * CFSFolder::ParseDisplayName {SHELL32}
296 * Parse a display name.
299 * hwndOwner [in] Parent window for any message's
300 * pbc [in] optional FileSystemBindData context
301 * lpszDisplayName [in] Unicode displayname.
302 * pchEaten [out] (unicode) characters processed
303 * ppidl [out] complex pidl to item
304 * pdwAttributes [out] items attributes
307 * Every folder tries to parse only its own (the leftmost) pidl and creates a
308 * subfolder to evaluate the remaining parts.
309 * Now we can parse into namespaces implemented by shell extensions
311 * Behaviour on win98: lpszDisplayName=NULL -> crash
312 * lpszDisplayName="" -> returns mycoputer-pidl
315 * pdwAttributes is not set
316 * pchEaten is not set like in windows
318 HRESULT WINAPI
CFSFolder::ParseDisplayName(HWND hwndOwner
,
320 LPOLESTR lpszDisplayName
,
321 DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
,
322 DWORD
*pdwAttributes
)
324 HRESULT hr
= E_INVALIDARG
;
325 LPCWSTR szNext
= NULL
;
326 WCHAR szElement
[MAX_PATH
];
327 WCHAR szPath
[MAX_PATH
];
328 LPITEMIDLIST pidlTemp
= NULL
;
331 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
332 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
333 pchEaten
, ppidl
, pdwAttributes
);
338 if (!lpszDisplayName
)
347 *pchEaten
= 0; /* strange but like the original */
349 if (*lpszDisplayName
)
351 /* get the next element */
352 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
354 pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, szElement
);
355 if (pidlTemp
!= NULL
)
357 /* We are creating an id list without ensuring that the items exist.
358 If we have a remaining path, this must be a folder.
359 We have to do it now because it is set as a file by default */
362 pidlTemp
->mkid
.abID
[0] = PT_FOLDER
;
368 /* build the full pathname to the element */
369 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
- 1);
370 PathAddBackslashW(szPath
);
371 len
= wcslen(szPath
);
372 lstrcpynW(szPath
+ len
, szElement
, MAX_PATH
- len
);
375 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
380 if (szNext
&& *szNext
)
382 /* try to analyse the next element */
383 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
384 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
388 /* it's the last element */
389 if (pdwAttributes
&& *pdwAttributes
)
390 hr
= SHELL32_GetFSItemAttributes(this, pidlTemp
, pdwAttributes
);
400 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl
? *ppidl
: 0, hr
);
405 /**************************************************************************
406 * CFSFolder::EnumObjects
408 * HWND hwndOwner, //[in ] Parent Window
409 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
410 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
412 HRESULT WINAPI
CFSFolder::EnumObjects(
415 LPENUMIDLIST
*ppEnumIDList
)
417 return ShellObjectCreatorInit
<CFileSysEnum
>(sPathTarget
, dwFlags
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
420 /**************************************************************************
421 * CFSFolder::BindToObject
423 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
424 * LPBC pbc, //[in ] optional FileSystemBindData context
425 * REFIID riid, //[in ] Initial Interface
426 * LPVOID* ppvObject //[out] Interface*
428 HRESULT WINAPI
CFSFolder::BindToObject(
429 PCUIDLIST_RELATIVE pidl
,
434 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbc
,
435 shdebugstr_guid(&riid
), ppvOut
);
437 CComPtr
<IShellFolder
> pSF
;
440 if (!pidlRoot
|| !ppvOut
|| !pidl
|| !pidl
->mkid
.cb
)
443 if (_ILIsValue(pidl
))
445 ERR("Binding to file is unimplemented\n");
446 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
448 if (!_ILIsFolder(pidl
))
450 ERR("Got an unknown type of pidl!\n");
456 /* Get the pidl data */
457 FileStruct
* pData
= &_ILGetDataPointer(pidl
)->u
.file
;
458 FileStructW
* pDataW
= _ILGetFileStructW(pidl
);
460 /* Create the target folder info */
461 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
462 pfti
.dwAttributes
= -1;
464 PathCombineW(pfti
.szTargetParsingName
, sPathTarget
, pDataW
->wszName
);
466 /* Get the CLSID to bind to */
467 CLSID clsidFolder
= CLSID_ShellFSFolder
;
468 if ((pData
->uFileAttribs
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
)) != 0)
469 SHELL32_GetCLSIDForDirectory(pfti
.szTargetParsingName
, &clsidFolder
);
471 hr
= SHELL32_BindToSF(pidlRoot
, &pfti
, pidl
, &clsidFolder
, riid
, ppvOut
);
472 if (FAILED_UNEXPECTEDLY(hr
))
475 TRACE ("-- returning (%p) %08x\n", *ppvOut
, hr
);
481 /**************************************************************************
482 * CFSFolder::BindToStorage
484 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
485 * LPBC pbc, //[in ] reserved
486 * REFIID riid, //[in ] Initial storage interface
487 * LPVOID* ppvObject //[out] Interface* returned
489 HRESULT WINAPI
CFSFolder::BindToStorage(
490 PCUIDLIST_RELATIVE pidl
,
495 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
,
496 shdebugstr_guid (&riid
), ppvOut
);
502 /**************************************************************************
503 * CFSFolder::CompareIDs
506 HRESULT WINAPI
CFSFolder::CompareIDs(LPARAM lParam
,
507 PCUIDLIST_RELATIVE pidl1
,
508 PCUIDLIST_RELATIVE pidl2
)
510 LPPIDLDATA pData1
= _ILGetDataPointer(pidl1
);
511 LPPIDLDATA pData2
= _ILGetDataPointer(pidl2
);
512 FileStructW
* pDataW1
= _ILGetFileStructW(pidl1
);
513 FileStructW
* pDataW2
= _ILGetFileStructW(pidl2
);
514 BOOL bIsFolder1
= _ILIsFolder(pidl1
);
515 BOOL bIsFolder2
= _ILIsFolder(pidl2
);
516 LPWSTR pExtension1
, pExtension2
;
518 if (!pDataW1
|| !pDataW2
|| LOWORD(lParam
) >= GENERICSHELLVIEWCOLUMNS
)
521 /* When sorting between a File and a Folder, the Folder gets sorted first */
522 if (bIsFolder1
!= bIsFolder2
)
524 return MAKE_COMPARE_HRESULT(bIsFolder1
? -1 : 1);
528 switch (LOWORD(lParam
))
531 result
= wcsicmp(pDataW1
->wszName
, pDataW2
->wszName
);
533 case 1: /* Comments */
537 pExtension1
= PathFindExtensionW(pDataW1
->wszName
);
538 pExtension2
= PathFindExtensionW(pDataW2
->wszName
);
539 result
= wcsicmp(pExtension1
, pExtension2
);
542 result
= pData1
->u
.file
.dwFileSize
- pData2
->u
.file
.dwFileSize
;
544 case 4: /* Modified */
545 result
= pData1
->u
.file
.uFileDate
- pData2
->u
.file
.uFileDate
;
547 result
= pData1
->u
.file
.uFileTime
- pData2
->u
.file
.uFileTime
;
549 case 5: /* Attributes */
550 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
554 return SHELL32_CompareChildren(this, lParam
, pidl1
, pidl2
);
556 return MAKE_COMPARE_HRESULT(result
);
559 /**************************************************************************
560 * CFSFolder::CreateViewObject
562 HRESULT WINAPI
CFSFolder::CreateViewObject(HWND hwndOwner
,
563 REFIID riid
, LPVOID
* ppvOut
)
565 CComPtr
<IShellView
> pShellView
;
566 HRESULT hr
= E_INVALIDARG
;
568 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid (&riid
),
575 if (IsEqualIID (riid
, IID_IDropTarget
))
576 hr
= CFSDropTarget_CreateInstance(sPathTarget
, riid
, ppvOut
);
577 else if (IsEqualIID (riid
, IID_IContextMenu
))
581 AddClassKeyToArray(L
"Directory\\Background", hKeys
, &cKeys
);
584 dcm
.hwnd
= hwndOwner
;
586 dcm
.pidlFolder
= pidlRoot
;
592 dcm
.punkAssociationInfo
= NULL
;
593 hr
= SHCreateDefaultContextMenu (&dcm
, riid
, ppvOut
);
595 else if (IsEqualIID (riid
, IID_IShellView
))
597 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this};
598 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
601 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
605 /**************************************************************************
606 * CFSFolder::GetAttributesOf
609 * UINT cidl, //[in ] num elements in pidl array
610 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
611 * ULONG* rgfInOut) //[out] result array
614 HRESULT WINAPI
CFSFolder::GetAttributesOf(UINT cidl
,
615 PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
629 LPCITEMIDLIST rpidl
= ILFindLastID(pidlRoot
);
631 if (_ILIsFolder(rpidl
) || _ILIsValue(rpidl
))
633 SHELL32_GetFSItemAttributes(this, rpidl
, rgfInOut
);
635 else if (_ILIsDrive(rpidl
))
637 IShellFolder
*psfParent
= NULL
;
638 hr
= SHBindToParent(pidlRoot
, IID_PPV_ARG(IShellFolder
, &psfParent
), NULL
);
641 hr
= psfParent
->GetAttributesOf(1, &rpidl
, (SFGAOF
*)rgfInOut
);
642 psfParent
->Release();
647 ERR("Got and unknown pidl!\n");
652 while (cidl
> 0 && *apidl
)
655 if(_ILIsFolder(*apidl
) || _ILIsValue(*apidl
))
656 SHELL32_GetFSItemAttributes(this, *apidl
, rgfInOut
);
658 ERR("Got an unknown type of pidl!!!\n");
663 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
664 *rgfInOut
&= ~SFGAO_VALIDATE
;
666 TRACE("-- result=0x%08x\n", *rgfInOut
);
671 /**************************************************************************
672 * CFSFolder::GetUIObjectOf
675 * HWND hwndOwner, //[in ] Parent window for any output
676 * UINT cidl, //[in ] array size
677 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
678 * REFIID riid, //[in ] Requested Interface
679 * UINT* prgfInOut, //[ ] reserved
680 * LPVOID* ppvObject) //[out] Resulting Interface
683 * This function gets asked to return "view objects" for one or more (multiple
685 * The viewobject typically is an COM object with one of the following
687 * IExtractIcon,IDataObject,IContextMenu
688 * In order to support icon positions in the default Listview your DataObject
689 * must implement the SetData method (in addition to GetData :) - the shell
690 * passes a barely documented "Icon positions" structure to SetData when the
691 * drag starts, and GetData's it if the drop is in another explorer window that
692 * needs the positions.
694 HRESULT WINAPI
CFSFolder::GetUIObjectOf(HWND hwndOwner
,
695 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
696 REFIID riid
, UINT
* prgfInOut
,
700 HRESULT hr
= E_INVALIDARG
;
702 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
703 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
709 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1))
713 AddFSClassKeysToArray(apidl
[0], hKeys
, &cKeys
);
716 dcm
.hwnd
= hwndOwner
;
718 dcm
.pidlFolder
= pidlRoot
;
724 dcm
.punkAssociationInfo
= NULL
;
725 hr
= SHCreateDefaultContextMenu (&dcm
, riid
, &pObj
);
727 else if (IsEqualIID (riid
, IID_IDataObject
))
731 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
738 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
740 hr
= CFSExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
742 else if (IsEqualIID (riid
, IID_IDropTarget
))
744 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
745 if (cidl
!= 1 || FAILED(hr
= this->_GetDropTarget(apidl
[0], (LPVOID
*) &pObj
)))
747 IDropTarget
* pDt
= NULL
;
748 hr
= CFSDropTarget_CreateInstance(sPathTarget
, riid
, ppvOut
);
752 else if ((IsEqualIID(riid
, IID_IShellLinkW
) ||
753 IsEqualIID(riid
, IID_IShellLinkA
)) && (cidl
== 1))
755 hr
= IShellLink_ConstructFromFile(this, apidl
[0], riid
, &pObj
);
760 if (SUCCEEDED(hr
) && !pObj
)
765 TRACE("(%p)->hr=0x%08x\n", this, hr
);
769 static const WCHAR AdvancedW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
770 static const WCHAR HideFileExtW
[] = L
"HideFileExt";
771 static const WCHAR NeverShowExtW
[] = L
"NeverShowExt";
773 /******************************************************************************
774 * SHELL_FS_HideExtension [Internal]
776 * Query the registry if the filename extension of a given path should be
780 * szPath [I] Relative or absolute path of a file
783 * TRUE, if the filename's extension should be hidden
786 BOOL
SHELL_FS_HideExtension(LPWSTR szPath
)
790 DWORD dwDataSize
= sizeof (DWORD
);
791 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
793 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, AdvancedW
, 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
794 if (!RegQueryValueExW(hKey
, HideFileExtW
, 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
800 LPWSTR ext
= PathFindExtensionW(szPath
);
803 WCHAR classname
[MAX_PATH
];
804 LONG classlen
= sizeof(classname
);
806 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
807 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
808 if (!RegQueryValueExW(hKey
, NeverShowExtW
, 0, NULL
, NULL
, NULL
))
817 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
819 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
820 if (!(dwFlags
& SHGDN_FORPARSING
) &&
821 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
822 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
823 PathRemoveExtensionW(szPath
);
827 /**************************************************************************
828 * CFSFolder::GetDisplayNameOf
829 * Retrieves the display name for the specified file object or subfolder
832 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
833 * DWORD dwFlags, //[in ] SHGNO formatting flags
834 * LPSTRRET lpName) //[out] Returned display name
837 * if the name is in the pidl the ret value should be a STRRET_OFFSET
840 HRESULT WINAPI
CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
,
841 DWORD dwFlags
, LPSTRRET strRet
)
846 /* If it is a complex pidl, let the child handle it */
847 if (!_ILIsPidlSimple (pidl
)) /* complex pidl */
849 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
851 else if (pidl
&& !pidl
->mkid
.cb
) /* empty pidl */
853 /* If it is an empty pidl return only the path of the folder */
854 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
855 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
858 return SHSetStrRet(strRet
, sPathTarget
);
864 LPWSTR pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
866 return E_OUTOFMEMORY
;
868 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
869 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
872 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
873 PathAddBackslashW(pszPath
);
874 len
= wcslen(pszPath
);
876 _ILSimpleGetTextW(pidl
, pszPath
+ len
, MAX_PATH
+ 1 - len
);
877 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
879 strRet
->uType
= STRRET_WSTR
;
880 strRet
->pOleStr
= pszPath
;
882 TRACE ("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
886 /**************************************************************************
887 * CFSFolder::SetNameOf
888 * Changes the name of a file object or subfolder, possibly changing its item
889 * identifier in the process.
892 * HWND hwndOwner, //[in ] Owner window for output
893 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
894 * LPCOLESTR lpszName, //[in ] the items new display name
895 * DWORD dwFlags, //[in ] SHGNO formatting flags
896 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
898 HRESULT WINAPI
CFSFolder::SetNameOf(
900 PCUITEMID_CHILD pidl
,
903 PITEMID_CHILD
*pPidlOut
)
905 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
907 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
909 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
910 debugstr_w (lpName
), dwFlags
, pPidlOut
);
912 /* build source path */
913 lstrcpynW(szSrc
, sPathTarget
, MAX_PATH
);
914 ptr
= PathAddBackslashW (szSrc
);
916 _ILSimpleGetTextW (pidl
, ptr
, MAX_PATH
+ 1 - (ptr
- szSrc
));
918 /* build destination path */
919 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
) {
920 lstrcpynW(szDest
, sPathTarget
, MAX_PATH
);
921 ptr
= PathAddBackslashW (szDest
);
923 lstrcpynW(ptr
, lpName
, MAX_PATH
+ 1 - (ptr
- szDest
));
925 lstrcpynW(szDest
, lpName
, MAX_PATH
);
927 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
928 WCHAR
*ext
= PathFindExtensionW(szSrc
);
930 INT len
= wcslen(szDest
);
931 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
935 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
936 if (!memcmp(szSrc
, szDest
, (wcslen(szDest
) + 1) * sizeof(WCHAR
)))
938 /* src and destination is the same */
941 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
947 if (MoveFileW (szSrc
, szDest
))
952 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
954 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
955 SHCNF_PATHW
, szSrc
, szDest
);
963 HRESULT WINAPI
CFSFolder::GetDefaultSearchGUID(GUID
* pguid
)
965 FIXME ("(%p)\n", this);
969 HRESULT WINAPI
CFSFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
971 FIXME ("(%p)\n", this);
975 HRESULT WINAPI
CFSFolder::GetDefaultColumn(DWORD dwRes
,
976 ULONG
* pSort
, ULONG
* pDisplay
)
978 TRACE ("(%p)\n", this);
988 HRESULT WINAPI
CFSFolder::GetDefaultColumnState(UINT iColumn
,
991 TRACE ("(%p)\n", this);
993 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
996 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
1001 HRESULT WINAPI
CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl
,
1002 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
1004 FIXME ("(%p)\n", this);
1009 HRESULT WINAPI
CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl
,
1010 UINT iColumn
, SHELLDETAILS
* psd
)
1012 HRESULT hr
= E_FAIL
;
1014 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
1016 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
1017 return E_INVALIDARG
;
1021 /* the header titles */
1022 psd
->fmt
= GenericSFHeader
[iColumn
].fmt
;
1023 psd
->cxChar
= GenericSFHeader
[iColumn
].cxChar
;
1024 return SHSetStrRet(&psd
->str
, GenericSFHeader
[iColumn
].colnameid
);
1029 psd
->str
.uType
= STRRET_CSTR
;
1030 /* the data from the pidl */
1034 hr
= GetDisplayNameOf (pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
1036 case 1: /* FIXME: comments */
1037 psd
->str
.cStr
[0] = 0;
1040 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
1043 _ILGetFileSize(pidl
, psd
->str
.cStr
, MAX_PATH
);
1046 _ILGetFileDate(pidl
, psd
->str
.cStr
, MAX_PATH
);
1048 case 5: /* attributes */
1049 _ILGetFileAttributes(pidl
, psd
->str
.cStr
, MAX_PATH
);
1057 HRESULT WINAPI
CFSFolder::MapColumnToSCID (UINT column
,
1060 FIXME ("(%p)\n", this);
1064 /************************************************************************
1065 * CFSFolder::GetClassID
1067 HRESULT WINAPI
CFSFolder::GetClassID(CLSID
* lpClassId
)
1069 TRACE ("(%p)\n", this);
1074 *lpClassId
= *pclsid
;
1079 /************************************************************************
1080 * CFSFolder::Initialize
1083 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1085 HRESULT WINAPI
CFSFolder::Initialize(LPCITEMIDLIST pidl
)
1087 WCHAR wszTemp
[MAX_PATH
];
1089 TRACE ("(%p)->(%p)\n", this, pidl
);
1091 SHFree (pidlRoot
); /* free the old pidl */
1092 pidlRoot
= ILClone (pidl
); /* set my pidl */
1094 SHFree (sPathTarget
);
1098 if (SHGetPathFromIDListW (pidl
, wszTemp
))
1100 int len
= wcslen(wszTemp
);
1101 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1103 return E_OUTOFMEMORY
;
1104 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1107 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget
));
1111 /**************************************************************************
1112 * CFSFolder::GetCurFolder
1114 HRESULT WINAPI
CFSFolder::GetCurFolder(LPITEMIDLIST
* pidl
)
1116 TRACE ("(%p)->(%p)\n", this, pidl
);
1121 *pidl
= ILClone(pidlRoot
);
1125 /**************************************************************************
1126 * CFSFolder::InitializeEx
1128 * FIXME: error handling
1130 HRESULT WINAPI
CFSFolder::InitializeEx(IBindCtx
* pbc
, LPCITEMIDLIST pidlRootx
,
1131 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1133 WCHAR wszTemp
[MAX_PATH
];
1135 TRACE("(%p)->(%p,%p,%p)\n", this, pbc
, pidlRootx
, ppfti
);
1137 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1138 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1139 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1143 if (ppfti
&& ppfti
->pidlTargetFolder
)
1144 pdump(ppfti
->pidlTargetFolder
);
1147 __SHFreeAndNil(&pidlRoot
); /* free the old */
1149 __SHFreeAndNil(&sPathTarget
);
1152 * Root path and pidl
1154 pidlRoot
= ILClone(pidlRootx
);
1157 * the target folder is spezified in csidl OR pidlTargetFolder OR
1158 * szTargetParsingName
1162 if (ppfti
->csidl
!= -1)
1164 if (SHGetSpecialFolderPathW(0, wszTemp
, ppfti
->csidl
,
1165 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1166 int len
= wcslen(wszTemp
);
1167 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1169 return E_OUTOFMEMORY
;
1170 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1173 else if (ppfti
->szTargetParsingName
[0])
1175 int len
= wcslen(ppfti
->szTargetParsingName
);
1176 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1178 return E_OUTOFMEMORY
;
1179 memcpy(sPathTarget
, ppfti
->szTargetParsingName
,
1180 (len
+ 1) * sizeof(WCHAR
));
1182 else if (ppfti
->pidlTargetFolder
)
1184 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
))
1186 int len
= wcslen(wszTemp
);
1187 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1189 return E_OUTOFMEMORY
;
1190 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1195 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget
));
1197 return (sPathTarget
) ? S_OK
: E_FAIL
;
1200 HRESULT WINAPI
CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1202 FIXME("(%p)->(%p)\n", this, ppfti
);
1203 ZeroMemory(ppfti
, sizeof (*ppfti
));
1207 HRESULT WINAPI
CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl
, LPVOID
*ppvOut
) {
1211 TRACE("CFSFolder::_GetDropTarget entered\n");
1213 if (_ILIsFolder (pidl
))
1215 CComPtr
<IShellFolder
> psfChild
;
1216 hr
= this->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
1217 if (FAILED_UNEXPECTEDLY(hr
))
1220 return psfChild
->CreateViewObject(NULL
, IID_IDropTarget
, ppvOut
);
1224 hr
= this->GetDisplayNameOf(pidl
, SHGDN_FORPARSING
, &strFile
);
1227 WCHAR wszPath
[MAX_PATH
];
1228 hr
= StrRetToBufW(&strFile
, pidl
, wszPath
, _countof(wszPath
));
1232 LPCWSTR pwszExt
= PathFindExtensionW(wszPath
);
1235 /* enumerate dynamic/static for a given file class */
1236 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pwszExt
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
1238 /* load dynamic extensions from file extension key, for example .jpg */
1239 _LoadDynamicDropTargetHandlerForKey(hKey
, wszPath
, ppvOut
);
1244 DWORD dwSize
= sizeof(wszTemp
);
1245 if (RegGetValueW(HKEY_CLASSES_ROOT
, pwszExt
, NULL
, RRF_RT_REG_SZ
, NULL
, wszTemp
, &dwSize
) == ERROR_SUCCESS
)
1247 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
1249 /* load dynamic extensions from progid key, for example jpegfile */
1250 _LoadDynamicDropTargetHandlerForKey(hKey
, wszPath
, ppvOut
);
1258 ERR("GetDisplayNameOf failed: %x\n", hr
);
1263 HRESULT WINAPI
CFSFolder::_LoadDynamicDropTargetHandlerForKey(HKEY hRootKey
, LPCWSTR pwcsname
, LPVOID
*ppvOut
)
1265 TRACE("CFSFolder::_LoadDynamicDropTargetHandlerForKey entered\n");
1267 WCHAR wszName
[MAX_PATH
];
1268 DWORD dwSize
= sizeof(wszName
);
1272 res
= RegGetValueW(hRootKey
, L
"shellex\\DropHandler", NULL
, RRF_RT_REG_SZ
, NULL
, wszName
, &dwSize
);
1273 if (res
!= ERROR_SUCCESS
)
1277 hr
= CLSIDFromString(wszName
, &clsid
);
1278 if (FAILED_UNEXPECTEDLY(hr
))
1281 if (m_bGroupPolicyActive
)
1283 res
= RegGetValueW(HKEY_LOCAL_MACHINE
,
1284 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1290 if (res
!= ERROR_SUCCESS
)
1292 ERR("DropHandler extension %S not approved\n", wszName
);
1297 hr
= _LoadDynamicDropTargetHandler(&clsid
, pwcsname
, ppvOut
);
1298 if (FAILED_UNEXPECTEDLY(hr
))
1304 HRESULT WINAPI
CFSFolder::_LoadDynamicDropTargetHandler(const CLSID
*pclsid
, LPCWSTR pwcsname
, LPVOID
*ppvOut
)
1306 TRACE("CFSFolder::_LoadDynamicDropTargetHandler entered\n");
1309 CComPtr
<IPersistFile
> pp
;
1310 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IPersistFile
, &pp
));
1313 ERR("SHCoCreateInstance failed %x\n", GetLastError());
1315 pp
->Load(pwcsname
, 0);
1317 hr
= pp
->QueryInterface(IID_PPV_ARG(IDropTarget
, (IDropTarget
**) ppvOut
));
1320 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
1326 HRESULT WINAPI
CFSFolder::CallBack(IShellFolder
*psf
, HWND hwndOwner
, IDataObject
*pdtobj
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1328 if (uMsg
!= DFM_MERGECONTEXTMENU
&& uMsg
!= DFM_INVOKECOMMAND
)
1331 /* no data object means no selection */
1334 if (uMsg
== DFM_INVOKECOMMAND
&& wParam
== DFM_CMD_PROPERTIES
)
1336 PUITEMID_CHILD pidlChild
= ILClone(ILFindLastID(pidlRoot
));
1337 LPITEMIDLIST pidlParent
= ILClone(pidlRoot
);
1338 ILRemoveLastID(pidlParent
);
1339 HRESULT hr
= SH_ShowPropertiesDialog(sPathTarget
, pidlParent
, &pidlChild
);
1341 ERR("SH_ShowPropertiesDialog failed\n");
1345 else if (uMsg
== DFM_MERGECONTEXTMENU
)
1347 QCMINFO
*pqcminfo
= (QCMINFO
*)lParam
;
1348 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
1349 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
1355 if (uMsg
!= DFM_INVOKECOMMAND
|| wParam
!= DFM_CMD_PROPERTIES
)
1358 PIDLIST_ABSOLUTE pidlFolder
;
1359 PUITEMID_CHILD
*apidl
;
1361 HRESULT hr
= SH_GetApidlFromDataObject(pdtobj
, &pidlFolder
, &apidl
, &cidl
);
1362 if (FAILED_UNEXPECTEDLY(hr
))
1366 ERR("SHMultiFileProperties is not yet implemented\n");
1369 hr
= GetDisplayNameOf(apidl
[0], SHGDN_FORPARSING
, &strFile
);
1372 hr
= SH_ShowPropertiesDialog(strFile
.pOleStr
, pidlFolder
, apidl
);
1374 ERR("SH_ShowPropertiesDialog failed\n");
1378 ERR("Failed to get display name\n");
1382 _ILFreeaPidl(apidl
, cidl
);