5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
7 * Copyright 2019 Katayama Hirofumi MZ
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
28 HKEY
OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl
, LPCWSTR KeyName
)
32 if (!_ILIsValue(pidl
))
34 ERR("Invalid pidl!\n");
38 FileStructW
* pDataW
= _ILGetFileStructW(pidl
);
41 ERR("Invalid pidl!\n");
45 LPWSTR pExtension
= PathFindExtensionW(pDataW
->wszName
);
46 if (!pExtension
|| *pExtension
== NULL
)
48 WARN("No extension for %S!\n", pDataW
->wszName
);
52 WCHAR FullName
[MAX_PATH
];
53 DWORD dwSize
= sizeof(FullName
);
54 wsprintf(FullName
, L
"%s\\%s", pExtension
, KeyName
);
56 LONG res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, FullName
, 0, KEY_READ
, &hkey
);
60 res
= RegGetValueW(HKEY_CLASSES_ROOT
, pExtension
, NULL
, RRF_RT_REG_SZ
, NULL
, FullName
, &dwSize
);
63 WARN("Failed to get progid for file %S, extension %S (%x), address %x, pidl: %x, error %d\n", pDataW
->wszName
, pExtension
, pExtension
, &dwSize
, pidl
, res
);
67 wcscat(FullName
, L
"\\");
68 wcscat(FullName
, KeyName
);
71 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, FullName
, 0, KEY_READ
, &hkey
);
73 WARN("Could not open key %S for extension %S\n", KeyName
, pExtension
);
78 HRESULT
GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl
, LPCWSTR KeyName
, CLSID
* pclsid
)
80 HKEY hkeyProgId
= OpenKeyFromFileType(pidl
, KeyName
);
83 WARN("OpenKeyFromFileType failed for key %S\n", KeyName
);
87 WCHAR wszCLSIDValue
[CHARS_IN_GUID
];
88 DWORD dwSize
= sizeof(wszCLSIDValue
);
89 LONG res
= RegGetValueW(hkeyProgId
, NULL
, NULL
, RRF_RT_REG_SZ
, NULL
, wszCLSIDValue
, &dwSize
);
90 RegCloseKey(hkeyProgId
);
93 ERR("OpenKeyFromFileType succeeded but RegGetValueW failed\n");
99 res
= RegGetValueW(HKEY_LOCAL_MACHINE
,
100 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
106 if (res
!= ERROR_SUCCESS
)
108 ERR("DropHandler extension %S not approved\n", wszName
);
109 return E_ACCESSDENIED
;
114 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
115 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked",
120 NULL
) == ERROR_SUCCESS
)
122 ERR("Extension %S not approved\n", wszCLSIDValue
);
123 return E_ACCESSDENIED
;
126 HRESULT hres
= CLSIDFromString (wszCLSIDValue
, pclsid
);
127 if (FAILED_UNEXPECTEDLY(hres
))
134 getDefaultIconLocation(LPWSTR szIconFile
, UINT cchMax
, int *piIndex
, UINT uFlags
)
136 static const WCHAR folder
[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
138 if (!HCR_GetIconW(folder
, szIconFile
, NULL
, cchMax
, piIndex
))
140 lstrcpynW(szIconFile
, swShell32Name
, cchMax
);
141 *piIndex
= -IDI_SHELL_FOLDER
;
144 if (uFlags
& GIL_OPENICON
)
156 static const WCHAR s_shellClassInfo
[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
159 getShellClassInfo(LPCWSTR Entry
, LPWSTR pszValue
, DWORD cchValueLen
, LPCWSTR IniFile
)
161 return GetPrivateProfileStringW(s_shellClassInfo
, Entry
, NULL
, pszValue
, cchValueLen
, IniFile
);
165 getIconLocationForFolder(IShellFolder
* psf
, PCITEMID_CHILD pidl
, UINT uFlags
,
166 LPWSTR szIconFile
, UINT cchMax
, int *piIndex
, UINT
*pwFlags
)
169 WCHAR wszPath
[MAX_PATH
];
170 WCHAR wszIniFullPath
[MAX_PATH
];
171 static const WCHAR iconFile
[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 };
172 static const WCHAR clsid
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
173 static const WCHAR clsid2
[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
174 static const WCHAR iconIndex
[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
175 static const WCHAR iconResource
[] = { 'I', 'c', 'o', 'n', 'R', 'e', 's', 'o', 'u', 'r', 'c', 'e', 0 };
176 static const WCHAR wszDesktopIni
[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 };
178 if (uFlags
& GIL_DEFAULTICON
)
182 if (!ILGetDisplayNameExW(psf
, pidl
, wszPath
, 0))
184 if (!PathIsDirectoryW(wszPath
))
187 // read-only or system folder?
188 dwFileAttrs
= _ILGetFileAttributes(ILFindLastID(pidl
), NULL
, 0);
189 if ((dwFileAttrs
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
)) == 0)
192 // build the full path of ini file
193 StringCchCopyW(wszIniFullPath
, _countof(wszIniFullPath
), wszPath
);
194 PathAppendW(wszIniFullPath
, wszDesktopIni
);
196 WCHAR wszValue
[MAX_PATH
], wszTemp
[MAX_PATH
];
197 if (getShellClassInfo(iconFile
, wszValue
, _countof(wszValue
), wszIniFullPath
))
199 // wszValue --> wszTemp
200 ExpandEnvironmentStringsW(wszValue
, wszTemp
, _countof(wszTemp
));
202 // wszPath + wszTemp --> wszPath
203 if (PathIsRelativeW(wszTemp
))
204 PathAppendW(wszPath
, wszTemp
);
206 StringCchCopyW(wszPath
, _countof(wszPath
), wszTemp
);
208 // wszPath --> szIconFile
209 GetFullPathNameW(wszPath
, cchMax
, szIconFile
, NULL
);
211 *piIndex
= GetPrivateProfileIntW(s_shellClassInfo
, iconIndex
, 0, wszIniFullPath
);
214 else if (getShellClassInfo(clsid
, wszValue
, _countof(wszValue
), wszIniFullPath
) &&
215 HCR_GetIconW(wszValue
, szIconFile
, NULL
, cchMax
, piIndex
))
219 else if (getShellClassInfo(clsid2
, wszValue
, _countof(wszValue
), wszIniFullPath
) &&
220 HCR_GetIconW(wszValue
, szIconFile
, NULL
, cchMax
, piIndex
))
224 else if (getShellClassInfo(iconResource
, wszValue
, _countof(wszValue
), wszIniFullPath
))
226 // wszValue --> wszTemp
227 ExpandEnvironmentStringsW(wszValue
, wszTemp
, _countof(wszTemp
));
229 // parse the icon location
230 *piIndex
= PathParseIconLocationW(wszTemp
);
232 // wszPath + wszTemp --> wszPath
233 if (PathIsRelativeW(wszTemp
))
234 PathAppendW(wszPath
, wszTemp
);
236 StringCchCopyW(wszPath
, _countof(wszPath
), wszTemp
);
238 // wszPath --> szIconFile
239 GetFullPathNameW(wszPath
, cchMax
, szIconFile
, NULL
);
244 return getDefaultIconLocation(szIconFile
, cchMax
, piIndex
, uFlags
);
247 HRESULT
CFSExtractIcon_CreateInstance(IShellFolder
* psf
, LPCITEMIDLIST pidl
, REFIID iid
, LPVOID
* ppvOut
)
249 CComPtr
<IDefaultExtractIconInit
> initIcon
;
252 UINT flags
= 0; // FIXME: Use it!
253 WCHAR wTemp
[MAX_PATH
] = L
"";
255 hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
,&initIcon
));
259 if (_ILIsFolder (pidl
))
261 if (SUCCEEDED(getIconLocationForFolder(psf
,
262 pidl
, 0, wTemp
, _countof(wTemp
),
266 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
267 // FIXME: if/when getIconLocationForFolder does something for
268 // GIL_FORSHORTCUT, code below should be uncommented. and
269 // the following line removed.
270 initIcon
->SetShortcutIcon(wTemp
, icon_idx
);
272 if (SUCCEEDED(getIconLocationForFolder(psf
,
273 pidl
, GIL_DEFAULTICON
, wTemp
, _countof(wTemp
),
277 initIcon
->SetDefaultIcon(wTemp
, icon_idx
);
279 // if (SUCCEEDED(getIconLocationForFolder(psf,
280 // pidl, GIL_FORSHORTCUT, wTemp, _countof(wTemp),
284 // initIcon->SetShortcutIcon(wTemp, icon_idx);
286 if (SUCCEEDED(getIconLocationForFolder(psf
,
287 pidl
, GIL_OPENICON
, wTemp
, _countof(wTemp
),
291 initIcon
->SetOpenIcon(wTemp
, icon_idx
);
296 HKEY hkey
= OpenKeyFromFileType(pidl
, L
"DefaultIcon");
298 WARN("Could not open DefaultIcon key!\n");
300 DWORD dwSize
= sizeof(wTemp
);
301 if (hkey
&& !SHQueryValueExW(hkey
, NULL
, NULL
, NULL
, wTemp
, &dwSize
))
304 if (ParseFieldW (wTemp
, 2, sNum
, 5))
305 icon_idx
= _wtoi(sNum
);
307 icon_idx
= 0; /* sometimes the icon number is missing */
308 ParseFieldW (wTemp
, 1, wTemp
, MAX_PATH
);
309 PathUnquoteSpacesW(wTemp
);
311 if (!wcscmp(L
"%1", wTemp
)) /* icon is in the file */
313 ILGetDisplayNameExW(psf
, pidl
, wTemp
, ILGDN_FORPARSING
);
316 INT ret
= ExtractIconExW(wTemp
, -1, NULL
, NULL
, 0);
319 StringCbCopyW(wTemp
, sizeof(wTemp
), swShell32Name
);
320 icon_idx
= -IDI_SHELL_EXE
;
324 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
328 initIcon
->SetNormalIcon(swShell32Name
, 0);
335 return initIcon
->QueryInterface(iid
, ppvOut
);
339 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
340 returned by Next. When the enumerator is created, it can do numerous additional operations
341 including formatting a drive, reconnecting a network share drive, and requesting a disk
342 be inserted in a removable drive.
345 /***********************************************************************
346 * IShellFolder implementation
350 public CEnumIDListBase
356 HRESULT WINAPI
Initialize(LPWSTR sPathTarget
, DWORD dwFlags
);
358 BEGIN_COM_MAP(CFileSysEnum
)
359 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
363 CFileSysEnum::CFileSysEnum()
367 CFileSysEnum::~CFileSysEnum()
371 HRESULT WINAPI
CFileSysEnum::Initialize(LPWSTR lpszPath
, DWORD dwFlags
)
373 WIN32_FIND_DATAW stffile
;
375 WCHAR szPath
[MAX_PATH
];
376 BOOL succeeded
= TRUE
;
377 static const WCHAR stars
[] = { '*','.','*',0 };
378 static const WCHAR dot
[] = { '.',0 };
379 static const WCHAR dotdot
[] = { '.','.',0 };
381 TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath
), dwFlags
);
383 if(!lpszPath
|| !lpszPath
[0]) return FALSE
;
385 wcscpy(szPath
, lpszPath
);
386 PathAddBackslashW(szPath
);
387 wcscat(szPath
,stars
);
389 hFile
= FindFirstFileW(szPath
,&stffile
);
390 if ( hFile
!= INVALID_HANDLE_VALUE
)
392 BOOL findFinished
= FALSE
;
396 if ( !(stffile
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
397 || (dwFlags
& SHCONTF_INCLUDEHIDDEN
) )
399 LPITEMIDLIST pidl
= NULL
;
401 if ( (stffile
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
402 dwFlags
& SHCONTF_FOLDERS
&&
403 strcmpW(stffile
.cFileName
, dot
) && strcmpW(stffile
.cFileName
, dotdot
))
405 pidl
= _ILCreateFromFindDataW(&stffile
);
406 succeeded
= succeeded
&& AddToEnumList(pidl
);
408 else if (!(stffile
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
409 && dwFlags
& SHCONTF_NONFOLDERS
)
411 pidl
= _ILCreateFromFindDataW(&stffile
);
412 succeeded
= succeeded
&& AddToEnumList(pidl
);
417 if (!FindNextFileW(hFile
, &stffile
))
419 if (GetLastError() == ERROR_NO_MORE_FILES
)
425 } while (succeeded
&& !findFinished
);
432 CFSFolder::CFSFolder()
434 pclsid
= (CLSID
*)&CLSID_ShellFSFolder
;
437 m_bGroupPolicyActive
= 0;
440 CFSFolder::~CFSFolder()
442 TRACE("-- destroying IShellFolder(%p)\n", this);
449 static const shvheader GenericSFHeader
[] = {
450 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
451 {IDS_SHV_COLUMN_COMMENTS
, SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 0},
452 {IDS_SHV_COLUMN_TYPE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
453 {IDS_SHV_COLUMN_SIZE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
454 {IDS_SHV_COLUMN_MODIFIED
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 12},
455 {IDS_SHV_COLUMN_ATTRIBUTES
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10}
458 #define GENERICSHELLVIEWCOLUMNS 6
460 /**************************************************************************
461 * SHELL32_CreatePidlFromBindCtx [internal]
463 * If the caller bound File System Bind Data, assume it is the
464 * find data for the path.
465 * This allows binding of paths that don't exist.
467 LPITEMIDLIST
SHELL32_CreatePidlFromBindCtx(IBindCtx
*pbc
, LPCWSTR path
)
469 IFileSystemBindData
*fsbd
= NULL
;
470 LPITEMIDLIST pidl
= NULL
;
471 IUnknown
*param
= NULL
;
472 WIN32_FIND_DATAW wfd
;
475 TRACE("%p %s\n", pbc
, debugstr_w(path
));
480 /* see if the caller bound File System Bind Data */
481 r
= pbc
->GetObjectParam((LPOLESTR
)STR_FILE_SYS_BIND_DATA
, ¶m
);
485 r
= param
->QueryInterface(IID_PPV_ARG(IFileSystemBindData
,&fsbd
));
488 r
= fsbd
->GetFindData(&wfd
);
491 lstrcpynW(&wfd
.cFileName
[0], path
, MAX_PATH
);
492 pidl
= _ILCreateFromFindDataW(&wfd
);
500 static HRESULT
SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir
, LPCWSTR KeyName
, CLSID
* pclsidFolder
)
502 WCHAR wszCLSIDValue
[CHARS_IN_GUID
];
503 WCHAR wszDesktopIni
[MAX_PATH
];
504 StringCchCopyW(wszDesktopIni
, MAX_PATH
, pwszDir
);
505 StringCchCatW(wszDesktopIni
, MAX_PATH
, L
"\\desktop.ini");
507 if (GetPrivateProfileStringW(L
".ShellClassInfo",
514 return CLSIDFromString(wszCLSIDValue
, pclsidFolder
);
519 HRESULT
SHELL32_GetFSItemAttributes(IShellFolder
* psf
, LPCITEMIDLIST pidl
, LPDWORD pdwAttributes
)
521 DWORD dwFileAttributes
, dwShellAttributes
;
523 if (!_ILIsFolder(pidl
) && !_ILIsValue(pidl
))
525 ERR("Got wrong type of pidl!\n");
526 *pdwAttributes
&= SFGAO_CANLINK
;
530 dwFileAttributes
= _ILGetFileAttributes(pidl
, NULL
, 0);
532 /* Set common attributes */
533 dwShellAttributes
= SFGAO_CANCOPY
| SFGAO_CANMOVE
| SFGAO_CANLINK
| SFGAO_CANRENAME
| SFGAO_CANDELETE
|
534 SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_FILESYSTEM
;
536 if (dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
537 dwShellAttributes
|= (SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_FILESYSANCESTOR
| SFGAO_STORAGEANCESTOR
| SFGAO_STORAGE
);
539 dwShellAttributes
|= SFGAO_STREAM
;
541 if (dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
542 dwShellAttributes
|= SFGAO_HIDDEN
;
544 if (dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
545 dwShellAttributes
|= SFGAO_READONLY
;
547 if (SFGAO_LINK
& *pdwAttributes
)
551 if (_ILGetExtension(pidl
, ext
, MAX_PATH
) && !lstrcmpiA(ext
, "lnk"))
552 dwShellAttributes
|= SFGAO_LINK
;
555 if (SFGAO_HASSUBFOLDER
& *pdwAttributes
)
557 CComPtr
<IShellFolder
> psf2
;
558 if (SUCCEEDED(psf
->BindToObject(pidl
, 0, IID_PPV_ARG(IShellFolder
, &psf2
))))
560 CComPtr
<IEnumIDList
> pEnumIL
;
561 if (SUCCEEDED(psf2
->EnumObjects(0, SHCONTF_FOLDERS
, &pEnumIL
)))
563 if (pEnumIL
->Skip(1) == S_OK
)
564 dwShellAttributes
|= SFGAO_HASSUBFOLDER
;
569 *pdwAttributes
= dwShellAttributes
;
571 TRACE ("-- 0x%08x\n", *pdwAttributes
);
575 /**************************************************************************
576 * CFSFolder::ParseDisplayName {SHELL32}
578 * Parse a display name.
581 * hwndOwner [in] Parent window for any message's
582 * pbc [in] optional FileSystemBindData context
583 * lpszDisplayName [in] Unicode displayname.
584 * pchEaten [out] (unicode) characters processed
585 * ppidl [out] complex pidl to item
586 * pdwAttributes [out] items attributes
589 * Every folder tries to parse only its own (the leftmost) pidl and creates a
590 * subfolder to evaluate the remaining parts.
591 * Now we can parse into namespaces implemented by shell extensions
593 * Behaviour on win98: lpszDisplayName=NULL -> crash
594 * lpszDisplayName="" -> returns mycoputer-pidl
597 * pdwAttributes is not set
598 * pchEaten is not set like in windows
600 HRESULT WINAPI
CFSFolder::ParseDisplayName(HWND hwndOwner
,
602 LPOLESTR lpszDisplayName
,
603 DWORD
*pchEaten
, PIDLIST_RELATIVE
*ppidl
,
604 DWORD
*pdwAttributes
)
606 HRESULT hr
= E_INVALIDARG
;
607 LPCWSTR szNext
= NULL
;
608 WCHAR szElement
[MAX_PATH
];
609 WCHAR szPath
[MAX_PATH
];
610 LPITEMIDLIST pidlTemp
= NULL
;
613 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
614 this, hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
615 pchEaten
, ppidl
, pdwAttributes
);
620 if (!lpszDisplayName
)
629 *pchEaten
= 0; /* strange but like the original */
631 if (*lpszDisplayName
)
633 /* get the next element */
634 szNext
= GetNextElementW (lpszDisplayName
, szElement
, MAX_PATH
);
636 pidlTemp
= SHELL32_CreatePidlFromBindCtx(pbc
, szElement
);
637 if (pidlTemp
!= NULL
)
639 /* We are creating an id list without ensuring that the items exist.
640 If we have a remaining path, this must be a folder.
641 We have to do it now because it is set as a file by default */
644 pidlTemp
->mkid
.abID
[0] = PT_FOLDER
;
650 /* build the full pathname to the element */
651 lstrcpynW(szPath
, sPathTarget
, MAX_PATH
- 1);
652 PathAddBackslashW(szPath
);
653 len
= wcslen(szPath
);
654 lstrcpynW(szPath
+ len
, szElement
, MAX_PATH
- len
);
657 hr
= _ILCreateFromPathW(szPath
, &pidlTemp
);
662 if (szNext
&& *szNext
)
664 /* try to analyse the next element */
665 hr
= SHELL32_ParseNextElement(this, hwndOwner
, pbc
,
666 &pidlTemp
, (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
670 /* it's the last element */
671 if (pdwAttributes
&& *pdwAttributes
)
672 hr
= SHELL32_GetFSItemAttributes(this, pidlTemp
, pdwAttributes
);
682 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl
? *ppidl
: 0, hr
);
687 /**************************************************************************
688 * CFSFolder::EnumObjects
690 * HWND hwndOwner, //[in ] Parent Window
691 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
692 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
694 HRESULT WINAPI
CFSFolder::EnumObjects(
697 LPENUMIDLIST
*ppEnumIDList
)
699 return ShellObjectCreatorInit
<CFileSysEnum
>(sPathTarget
, dwFlags
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
702 /**************************************************************************
703 * CFSFolder::BindToObject
705 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
706 * LPBC pbc, //[in ] optional FileSystemBindData context
707 * REFIID riid, //[in ] Initial Interface
708 * LPVOID* ppvObject //[out] Interface*
710 HRESULT WINAPI
CFSFolder::BindToObject(
711 PCUIDLIST_RELATIVE pidl
,
716 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl
, pbc
,
717 shdebugstr_guid(&riid
), ppvOut
);
719 CComPtr
<IShellFolder
> pSF
;
722 if (!pidlRoot
|| !ppvOut
|| !pidl
|| !pidl
->mkid
.cb
)
724 ERR("CFSFolder::BindToObject: Invalid parameters\n");
728 /* Get the pidl data */
729 FileStruct
* pData
= &_ILGetDataPointer(pidl
)->u
.file
;
730 FileStructW
* pDataW
= _ILGetFileStructW(pidl
);
734 ERR("CFSFolder::BindToObject: Invalid pidl!\n");
740 /* Create the target folder info */
741 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
742 pfti
.dwAttributes
= -1;
744 PathCombineW(pfti
.szTargetParsingName
, sPathTarget
, pDataW
->wszName
);
746 /* Get the CLSID to bind to */
748 if (_ILIsFolder(pidl
))
750 clsidFolder
= CLSID_ShellFSFolder
;
752 if ((pData
->uFileAttribs
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
)) != 0)
753 SHELL32_GetCLSIDForDirectory(pfti
.szTargetParsingName
, L
"CLSID", &clsidFolder
);
757 hr
= GetCLSIDForFileType(pidl
, L
"CLSID", &clsidFolder
);
759 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
);
764 hr
= SHELL32_BindToSF(pidlRoot
, &pfti
, pidl
, &clsidFolder
, riid
, ppvOut
);
765 if (FAILED_UNEXPECTEDLY(hr
))
768 TRACE ("-- returning (%p) %08x\n", *ppvOut
, hr
);
774 /**************************************************************************
775 * CFSFolder::BindToStorage
777 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
778 * LPBC pbc, //[in ] reserved
779 * REFIID riid, //[in ] Initial storage interface
780 * LPVOID* ppvObject //[out] Interface* returned
782 HRESULT WINAPI
CFSFolder::BindToStorage(
783 PCUIDLIST_RELATIVE pidl
,
788 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl
, pbcReserved
,
789 shdebugstr_guid (&riid
), ppvOut
);
795 /**************************************************************************
796 * CFSFolder::CompareIDs
799 HRESULT WINAPI
CFSFolder::CompareIDs(LPARAM lParam
,
800 PCUIDLIST_RELATIVE pidl1
,
801 PCUIDLIST_RELATIVE pidl2
)
803 LPPIDLDATA pData1
= _ILGetDataPointer(pidl1
);
804 LPPIDLDATA pData2
= _ILGetDataPointer(pidl2
);
805 FileStructW
* pDataW1
= _ILGetFileStructW(pidl1
);
806 FileStructW
* pDataW2
= _ILGetFileStructW(pidl2
);
807 BOOL bIsFolder1
= _ILIsFolder(pidl1
);
808 BOOL bIsFolder2
= _ILIsFolder(pidl2
);
809 LPWSTR pExtension1
, pExtension2
;
811 if (!pDataW1
|| !pDataW2
|| LOWORD(lParam
) >= GENERICSHELLVIEWCOLUMNS
)
814 /* When sorting between a File and a Folder, the Folder gets sorted first */
815 if (bIsFolder1
!= bIsFolder2
)
817 return MAKE_COMPARE_HRESULT(bIsFolder1
? -1 : 1);
821 switch (LOWORD(lParam
))
824 result
= wcsicmp(pDataW1
->wszName
, pDataW2
->wszName
);
826 case 1: /* Comments */
830 pExtension1
= PathFindExtensionW(pDataW1
->wszName
);
831 pExtension2
= PathFindExtensionW(pDataW2
->wszName
);
832 result
= wcsicmp(pExtension1
, pExtension2
);
835 result
= pData1
->u
.file
.dwFileSize
- pData2
->u
.file
.dwFileSize
;
837 case 4: /* Modified */
838 result
= pData1
->u
.file
.uFileDate
- pData2
->u
.file
.uFileDate
;
840 result
= pData1
->u
.file
.uFileTime
- pData2
->u
.file
.uFileTime
;
842 case 5: /* Attributes */
843 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
847 return SHELL32_CompareChildren(this, lParam
, pidl1
, pidl2
);
849 return MAKE_COMPARE_HRESULT(result
);
852 /**************************************************************************
853 * CFSFolder::CreateViewObject
855 HRESULT WINAPI
CFSFolder::CreateViewObject(HWND hwndOwner
,
856 REFIID riid
, LPVOID
* ppvOut
)
858 CComPtr
<IShellView
> pShellView
;
859 HRESULT hr
= E_INVALIDARG
;
861 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner
, shdebugstr_guid (&riid
),
868 BOOL bIsDropTarget
= IsEqualIID (riid
, IID_IDropTarget
);
869 BOOL bIsShellView
= !bIsDropTarget
&& IsEqualIID (riid
, IID_IShellView
);
871 if (bIsDropTarget
|| bIsShellView
)
873 DWORD dwDirAttributes
= _ILGetFileAttributes(ILFindLastID(pidlRoot
), NULL
, 0);
875 if ((dwDirAttributes
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
)) != 0)
878 hr
= SHELL32_GetCLSIDForDirectory(sPathTarget
, L
"UICLSID", &clsidFolder
);
881 CComPtr
<IPersistFolder
> spFolder
;
882 hr
= SHCoCreateInstance(NULL
, &clsidFolder
, NULL
, IID_PPV_ARG(IPersistFolder
, &spFolder
));
883 if (!FAILED_UNEXPECTEDLY(hr
))
885 hr
= spFolder
->Initialize(pidlRoot
);
887 if (!FAILED_UNEXPECTEDLY(hr
))
889 hr
= spFolder
->QueryInterface(riid
, ppvOut
);
895 // No desktop.ini, or no UICLSID present, continue as if nothing happened
903 // No UICLSID handler found, continue to the default handlers
906 hr
= CFSDropTarget_CreateInstance(sPathTarget
, riid
, ppvOut
);
908 else if (IsEqualIID (riid
, IID_IContextMenu
))
912 AddClassKeyToArray(L
"Directory\\Background", hKeys
, &cKeys
);
915 dcm
.hwnd
= hwndOwner
;
917 dcm
.pidlFolder
= pidlRoot
;
923 dcm
.punkAssociationInfo
= NULL
;
924 hr
= SHCreateDefaultContextMenu (&dcm
, riid
, ppvOut
);
926 else if (bIsShellView
)
928 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this, NULL
, this};
929 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
937 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut
);
941 /**************************************************************************
942 * CFSFolder::GetAttributesOf
945 * UINT cidl, //[in ] num elements in pidl array
946 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
947 * ULONG* rgfInOut) //[out] result array
950 HRESULT WINAPI
CFSFolder::GetAttributesOf(UINT cidl
,
951 PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
965 LPCITEMIDLIST rpidl
= ILFindLastID(pidlRoot
);
967 if (_ILIsFolder(rpidl
) || _ILIsValue(rpidl
))
969 SHELL32_GetFSItemAttributes(this, rpidl
, rgfInOut
);
971 else if (_ILIsDrive(rpidl
))
973 IShellFolder
*psfParent
= NULL
;
974 hr
= SHBindToParent(pidlRoot
, IID_PPV_ARG(IShellFolder
, &psfParent
), NULL
);
977 hr
= psfParent
->GetAttributesOf(1, &rpidl
, (SFGAOF
*)rgfInOut
);
978 psfParent
->Release();
983 ERR("Got and unknown pidl!\n");
988 while (cidl
> 0 && *apidl
)
991 if(_ILIsFolder(*apidl
) || _ILIsValue(*apidl
))
992 SHELL32_GetFSItemAttributes(this, *apidl
, rgfInOut
);
994 ERR("Got an unknown type of pidl!!!\n");
999 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
1000 *rgfInOut
&= ~SFGAO_VALIDATE
;
1002 TRACE("-- result=0x%08x\n", *rgfInOut
);
1007 /**************************************************************************
1008 * CFSFolder::GetUIObjectOf
1011 * HWND hwndOwner, //[in ] Parent window for any output
1012 * UINT cidl, //[in ] array size
1013 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
1014 * REFIID riid, //[in ] Requested Interface
1015 * UINT* prgfInOut, //[ ] reserved
1016 * LPVOID* ppvObject) //[out] Resulting Interface
1019 * This function gets asked to return "view objects" for one or more (multiple
1021 * The viewobject typically is an COM object with one of the following
1023 * IExtractIcon,IDataObject,IContextMenu
1024 * In order to support icon positions in the default Listview your DataObject
1025 * must implement the SetData method (in addition to GetData :) - the shell
1026 * passes a barely documented "Icon positions" structure to SetData when the
1027 * drag starts, and GetData's it if the drop is in another explorer window that
1028 * needs the positions.
1030 HRESULT WINAPI
CFSFolder::GetUIObjectOf(HWND hwndOwner
,
1031 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
1032 REFIID riid
, UINT
* prgfInOut
,
1036 HRESULT hr
= E_INVALIDARG
;
1038 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
1039 this, hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
1045 if (cidl
== 1 && _ILIsValue(apidl
[0]))
1047 hr
= _CreateExtensionUIObject(apidl
[0], riid
, ppvOut
);
1052 if (IsEqualIID(riid
, IID_IContextMenu
) && (cidl
>= 1))
1056 AddFSClassKeysToArray(apidl
[0], hKeys
, &cKeys
);
1059 dcm
.hwnd
= hwndOwner
;
1061 dcm
.pidlFolder
= pidlRoot
;
1067 dcm
.punkAssociationInfo
= NULL
;
1068 hr
= SHCreateDefaultContextMenu (&dcm
, riid
, &pObj
);
1070 else if (IsEqualIID (riid
, IID_IDataObject
))
1074 hr
= IDataObject_Constructor (hwndOwner
, pidlRoot
, apidl
, cidl
, TRUE
, (IDataObject
**)&pObj
);
1081 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
1083 if (_ILIsValue(apidl
[0]))
1084 hr
= _GetIconHandler(apidl
[0], riid
, (LPVOID
*)&pObj
);
1086 hr
= CFSExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
1088 else if (IsEqualIID (riid
, IID_IDropTarget
))
1090 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
1091 if (cidl
!= 1 || FAILED(hr
= this->_GetDropTarget(apidl
[0], (LPVOID
*) &pObj
)))
1093 hr
= CFSDropTarget_CreateInstance(sPathTarget
, riid
, (LPVOID
*) &pObj
);
1099 if (SUCCEEDED(hr
) && !pObj
)
1104 TRACE("(%p)->hr=0x%08x\n", this, hr
);
1108 static const WCHAR AdvancedW
[] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
1109 static const WCHAR HideFileExtW
[] = L
"HideFileExt";
1110 static const WCHAR NeverShowExtW
[] = L
"NeverShowExt";
1112 /******************************************************************************
1113 * SHELL_FS_HideExtension [Internal]
1115 * Query the registry if the filename extension of a given path should be
1119 * szPath [I] Relative or absolute path of a file
1122 * TRUE, if the filename's extension should be hidden
1125 BOOL
SHELL_FS_HideExtension(LPWSTR szPath
)
1129 DWORD dwDataSize
= sizeof (DWORD
);
1130 BOOL doHide
= FALSE
; /* The default value is FALSE (win98 at least) */
1132 if (!RegCreateKeyExW(HKEY_CURRENT_USER
, AdvancedW
, 0, 0, 0, KEY_ALL_ACCESS
, 0, &hKey
, 0)) {
1133 if (!RegQueryValueExW(hKey
, HideFileExtW
, 0, 0, (LPBYTE
) &dwData
, &dwDataSize
))
1139 LPWSTR ext
= PathFindExtensionW(szPath
);
1142 WCHAR classname
[MAX_PATH
];
1143 LONG classlen
= sizeof(classname
);
1145 if (!RegQueryValueW(HKEY_CLASSES_ROOT
, ext
, classname
, &classlen
))
1146 if (!RegOpenKeyW(HKEY_CLASSES_ROOT
, classname
, &hKey
)) {
1147 if (!RegQueryValueExW(hKey
, NeverShowExtW
, 0, NULL
, NULL
, NULL
))
1156 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath
, DWORD dwFlags
)
1158 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
1159 if (!(dwFlags
& SHGDN_FORPARSING
) &&
1160 ((dwFlags
& SHGDN_INFOLDER
) || (dwFlags
== SHGDN_NORMAL
))) {
1161 if (SHELL_FS_HideExtension(szPath
) && szPath
[0] != '.')
1162 PathRemoveExtensionW(szPath
);
1166 /**************************************************************************
1167 * CFSFolder::GetDisplayNameOf
1168 * Retrieves the display name for the specified file object or subfolder
1171 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
1172 * DWORD dwFlags, //[in ] SHGNO formatting flags
1173 * LPSTRRET lpName) //[out] Returned display name
1176 * if the name is in the pidl the ret value should be a STRRET_OFFSET
1179 HRESULT WINAPI
CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
,
1180 DWORD dwFlags
, LPSTRRET strRet
)
1183 return E_INVALIDARG
;
1185 /* If it is a complex pidl, let the child handle it */
1186 if (!_ILIsPidlSimple (pidl
)) /* complex pidl */
1188 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
1190 else if (pidl
&& !pidl
->mkid
.cb
) /* empty pidl */
1192 /* If it is an empty pidl return only the path of the folder */
1193 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
1194 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
1197 return SHSetStrRet(strRet
, sPathTarget
);
1199 return E_INVALIDARG
;
1203 LPWSTR pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
1205 return E_OUTOFMEMORY
;
1207 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
1208 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
1211 lstrcpynW(pszPath
, sPathTarget
, MAX_PATH
);
1212 PathAddBackslashW(pszPath
);
1213 len
= wcslen(pszPath
);
1215 _ILSimpleGetTextW(pidl
, pszPath
+ len
, MAX_PATH
+ 1 - len
);
1216 if (!_ILIsFolder(pidl
)) SHELL_FS_ProcessDisplayFilename(pszPath
, dwFlags
);
1218 strRet
->uType
= STRRET_WSTR
;
1219 strRet
->pOleStr
= pszPath
;
1221 TRACE ("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
1225 /**************************************************************************
1226 * CFSFolder::SetNameOf
1227 * Changes the name of a file object or subfolder, possibly changing its item
1228 * identifier in the process.
1231 * HWND hwndOwner, //[in ] Owner window for output
1232 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
1233 * LPCOLESTR lpszName, //[in ] the items new display name
1234 * DWORD dwFlags, //[in ] SHGNO formatting flags
1235 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
1237 HRESULT WINAPI
CFSFolder::SetNameOf(
1239 PCUITEMID_CHILD pidl
,
1242 PITEMID_CHILD
*pPidlOut
)
1244 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
1245 BOOL bIsFolder
= _ILIsFolder (ILFindLastID (pidl
));
1247 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner
, pidl
,
1248 debugstr_w (lpName
), dwFlags
, pPidlOut
);
1250 FileStructW
* pDataW
= _ILGetFileStructW(pidl
);
1253 ERR("Got garbage pidl\n");
1254 return E_INVALIDARG
;
1257 /* build source path */
1258 PathCombineW(szSrc
, sPathTarget
, pDataW
->wszName
);
1260 /* build destination path */
1261 if (dwFlags
== SHGDN_NORMAL
|| dwFlags
& SHGDN_INFOLDER
)
1262 PathCombineW(szDest
, sPathTarget
, lpName
);
1264 lstrcpynW(szDest
, lpName
, MAX_PATH
);
1266 if(!(dwFlags
& SHGDN_FORPARSING
) && SHELL_FS_HideExtension(szSrc
)) {
1267 WCHAR
*ext
= PathFindExtensionW(szSrc
);
1269 INT len
= wcslen(szDest
);
1270 lstrcpynW(szDest
+ len
, ext
, MAX_PATH
- len
);
1274 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc
), debugstr_w(szDest
));
1275 if (!wcscmp(szSrc
, szDest
))
1277 /* src and destination is the same */
1280 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
1285 if (MoveFileW (szSrc
, szDest
))
1290 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
1292 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
1293 SHCNF_PATHW
, szSrc
, szDest
);
1301 HRESULT WINAPI
CFSFolder::GetDefaultSearchGUID(GUID
* pguid
)
1303 FIXME ("(%p)\n", this);
1307 HRESULT WINAPI
CFSFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
1309 FIXME ("(%p)\n", this);
1313 HRESULT WINAPI
CFSFolder::GetDefaultColumn(DWORD dwRes
,
1314 ULONG
* pSort
, ULONG
* pDisplay
)
1316 TRACE ("(%p)\n", this);
1326 HRESULT WINAPI
CFSFolder::GetDefaultColumnState(UINT iColumn
,
1329 TRACE ("(%p)\n", this);
1331 if (!pcsFlags
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
1332 return E_INVALIDARG
;
1334 *pcsFlags
= GenericSFHeader
[iColumn
].pcsFlags
;
1339 HRESULT WINAPI
CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl
,
1340 const SHCOLUMNID
* pscid
, VARIANT
* pv
)
1342 FIXME ("(%p)\n", this);
1347 HRESULT WINAPI
CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl
,
1348 UINT iColumn
, SHELLDETAILS
* psd
)
1350 HRESULT hr
= E_FAIL
;
1352 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
1354 if (!psd
|| iColumn
>= GENERICSHELLVIEWCOLUMNS
)
1355 return E_INVALIDARG
;
1359 /* the header titles */
1360 psd
->fmt
= GenericSFHeader
[iColumn
].fmt
;
1361 psd
->cxChar
= GenericSFHeader
[iColumn
].cxChar
;
1362 return SHSetStrRet(&psd
->str
, GenericSFHeader
[iColumn
].colnameid
);
1367 psd
->str
.uType
= STRRET_CSTR
;
1368 /* the data from the pidl */
1372 hr
= GetDisplayNameOf (pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
1374 case 1: /* FIXME: comments */
1375 psd
->str
.cStr
[0] = 0;
1378 _ILGetFileType(pidl
, psd
->str
.cStr
, MAX_PATH
);
1381 _ILGetFileSize(pidl
, psd
->str
.cStr
, MAX_PATH
);
1384 _ILGetFileDate(pidl
, psd
->str
.cStr
, MAX_PATH
);
1386 case 5: /* attributes */
1387 _ILGetFileAttributes(pidl
, psd
->str
.cStr
, MAX_PATH
);
1395 HRESULT WINAPI
CFSFolder::MapColumnToSCID (UINT column
,
1398 FIXME ("(%p)\n", this);
1402 /************************************************************************
1403 * CFSFolder::GetClassID
1405 HRESULT WINAPI
CFSFolder::GetClassID(CLSID
* lpClassId
)
1407 TRACE ("(%p)\n", this);
1412 *lpClassId
= *pclsid
;
1417 /************************************************************************
1418 * CFSFolder::Initialize
1421 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1423 HRESULT WINAPI
CFSFolder::Initialize(PCIDLIST_ABSOLUTE pidl
)
1425 WCHAR wszTemp
[MAX_PATH
];
1427 TRACE ("(%p)->(%p)\n", this, pidl
);
1429 SHFree (pidlRoot
); /* free the old pidl */
1430 pidlRoot
= ILClone (pidl
); /* set my pidl */
1432 SHFree (sPathTarget
);
1436 if (SHGetPathFromIDListW (pidl
, wszTemp
))
1438 int len
= wcslen(wszTemp
);
1439 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1441 return E_OUTOFMEMORY
;
1442 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1445 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget
));
1449 /**************************************************************************
1450 * CFSFolder::GetCurFolder
1452 HRESULT WINAPI
CFSFolder::GetCurFolder(PIDLIST_ABSOLUTE
* pidl
)
1454 TRACE ("(%p)->(%p)\n", this, pidl
);
1459 *pidl
= ILClone(pidlRoot
);
1463 /**************************************************************************
1464 * CFSFolder::InitializeEx
1466 * FIXME: error handling
1468 HRESULT WINAPI
CFSFolder::InitializeEx(IBindCtx
* pbc
, LPCITEMIDLIST pidlRootx
,
1469 const PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1471 WCHAR wszTemp
[MAX_PATH
];
1473 TRACE("(%p)->(%p,%p,%p)\n", this, pbc
, pidlRootx
, ppfti
);
1475 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1476 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1477 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1481 if (ppfti
&& ppfti
->pidlTargetFolder
)
1482 pdump(ppfti
->pidlTargetFolder
);
1485 __SHFreeAndNil(&pidlRoot
); /* free the old */
1487 __SHFreeAndNil(&sPathTarget
);
1490 * Root path and pidl
1492 pidlRoot
= ILClone(pidlRootx
);
1495 * the target folder is spezified in csidl OR pidlTargetFolder OR
1496 * szTargetParsingName
1500 if (ppfti
->csidl
!= -1)
1502 if (SHGetSpecialFolderPathW(0, wszTemp
, ppfti
->csidl
,
1503 ppfti
->csidl
& CSIDL_FLAG_CREATE
)) {
1504 int len
= wcslen(wszTemp
);
1505 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1507 return E_OUTOFMEMORY
;
1508 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1511 else if (ppfti
->szTargetParsingName
[0])
1513 int len
= wcslen(ppfti
->szTargetParsingName
);
1514 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1516 return E_OUTOFMEMORY
;
1517 memcpy(sPathTarget
, ppfti
->szTargetParsingName
,
1518 (len
+ 1) * sizeof(WCHAR
));
1520 else if (ppfti
->pidlTargetFolder
)
1522 if (SHGetPathFromIDListW(ppfti
->pidlTargetFolder
, wszTemp
))
1524 int len
= wcslen(wszTemp
);
1525 sPathTarget
= (WCHAR
*)SHAlloc((len
+ 1) * sizeof(WCHAR
));
1527 return E_OUTOFMEMORY
;
1528 memcpy(sPathTarget
, wszTemp
, (len
+ 1) * sizeof(WCHAR
));
1533 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget
));
1535 return (sPathTarget
) ? S_OK
: E_FAIL
;
1538 HRESULT WINAPI
CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO
* ppfti
)
1540 FIXME("(%p)->(%p)\n", this, ppfti
);
1541 ZeroMemory(ppfti
, sizeof (*ppfti
));
1545 HRESULT
CFSFolder::_CreateExtensionUIObject(PCUIDLIST_RELATIVE pidl
, REFIID riid
, LPVOID
*ppvOut
)
1547 static const WCHAR formatW
[] = {'S','h','e','l','l','E','x','\\',
1548 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
1549 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
1550 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
1551 WCHAR buf
[MAX_PATH
];
1553 sprintfW(buf
, formatW
, riid
.Data1
, riid
.Data2
, riid
.Data3
,
1554 riid
.Data4
[0], riid
.Data4
[1], riid
.Data4
[2], riid
.Data4
[3],
1555 riid
.Data4
[4], riid
.Data4
[5], riid
.Data4
[6], riid
.Data4
[7]);
1560 hr
= GetCLSIDForFileType(pidl
, buf
, &clsid
);
1564 hr
= _CreateShellExtInstance(&clsid
, pidl
, riid
, ppvOut
);
1565 if (FAILED_UNEXPECTEDLY(hr
))
1571 HRESULT
CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl
, LPVOID
*ppvOut
)
1575 TRACE("CFSFolder::_GetDropTarget entered\n");
1577 if (_ILIsFolder (pidl
))
1579 CComPtr
<IShellFolder
> psfChild
;
1580 hr
= this->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
1581 if (FAILED_UNEXPECTEDLY(hr
))
1584 return psfChild
->CreateViewObject(NULL
, IID_IDropTarget
, ppvOut
);
1588 hr
= GetCLSIDForFileType(pidl
, L
"shellex\\DropHandler", &clsid
);
1592 hr
= _CreateShellExtInstance(&clsid
, pidl
, IID_IDropTarget
, ppvOut
);
1593 if (FAILED_UNEXPECTEDLY(hr
))
1599 HRESULT
CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
*ppvOut
)
1604 hr
= GetCLSIDForFileType(pidl
, L
"shellex\\IconHandler", &clsid
);
1608 hr
= _CreateShellExtInstance(&clsid
, pidl
, riid
, ppvOut
);
1609 if (FAILED_UNEXPECTEDLY(hr
))
1615 HRESULT
CFSFolder::_CreateShellExtInstance(const CLSID
*pclsid
, LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
*ppvOut
)
1618 WCHAR wszPath
[MAX_PATH
];
1620 FileStructW
* pDataW
= _ILGetFileStructW(pidl
);
1623 ERR("Got garbage pidl\n");
1624 return E_INVALIDARG
;
1627 PathCombineW(wszPath
, sPathTarget
, pDataW
->wszName
);
1629 CComPtr
<IPersistFile
> pp
;
1630 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IPersistFile
, &pp
));
1631 if (FAILED_UNEXPECTEDLY(hr
))
1634 pp
->Load(wszPath
, 0);
1636 hr
= pp
->QueryInterface(riid
, ppvOut
);
1639 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
1645 HRESULT WINAPI
CFSFolder::CallBack(IShellFolder
*psf
, HWND hwndOwner
, IDataObject
*pdtobj
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1647 if (uMsg
!= DFM_MERGECONTEXTMENU
&& uMsg
!= DFM_INVOKECOMMAND
)
1650 /* no data object means no selection */
1653 if (uMsg
== DFM_INVOKECOMMAND
&& wParam
== 0)
1655 PUITEMID_CHILD pidlChild
= ILClone(ILFindLastID(pidlRoot
));
1656 LPITEMIDLIST pidlParent
= ILClone(pidlRoot
);
1657 ILRemoveLastID(pidlParent
);
1658 HRESULT hr
= SH_ShowPropertiesDialog(sPathTarget
, pidlParent
, &pidlChild
);
1660 ERR("SH_ShowPropertiesDialog failed\n");
1664 else if (uMsg
== DFM_MERGECONTEXTMENU
)
1666 QCMINFO
*pqcminfo
= (QCMINFO
*)lParam
;
1667 HMENU hpopup
= CreatePopupMenu();
1668 _InsertMenuItemW(hpopup
, 0, TRUE
, 0, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
1669 Shell_MergeMenus(pqcminfo
->hmenu
, hpopup
, pqcminfo
->indexMenu
++, pqcminfo
->idCmdFirst
, pqcminfo
->idCmdLast
, MM_ADDSEPARATOR
);
1670 DestroyMenu(hpopup
);
1676 if (uMsg
!= DFM_INVOKECOMMAND
|| wParam
!= DFM_CMD_PROPERTIES
)
1679 return Shell_DefaultContextMenuCallBack(this, pdtobj
);
1682 static HBITMAP
DoLoadPicture(LPCWSTR pszFileName
)
1684 // create stream from file
1686 CComPtr
<IStream
> pStream
;
1687 hr
= SHCreateStreamOnFileEx(pszFileName
, STGM_READ
, FILE_ATTRIBUTE_NORMAL
,
1688 FALSE
, NULL
, &pStream
);
1694 CComPtr
<IPicture
> pPicture
;
1695 OleLoadPicture(pStream
, 0, FALSE
, IID_IPicture
, (LPVOID
*)&pPicture
);
1697 // get the bitmap handle
1700 pPicture
->get_Handle((OLE_HANDLE
*)&hbm
);
1702 // copy the bitmap handle
1703 hbm
= (HBITMAP
)CopyImage(hbm
, IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
);
1709 HRESULT WINAPI
CFSFolder::GetCustomViewInfo(ULONG unknown
, SFVM_CUSTOMVIEWINFO_DATA
*data
)
1715 if (data
->cbSize
!= sizeof(*data
))
1717 // NOTE: You have to set the cbData member before SFVM_GET_CUSTOMVIEWINFO call.
1718 return E_INVALIDARG
;
1721 data
->hbmBack
= NULL
;
1722 data
->clrText
= CLR_INVALID
;
1723 data
->clrTextBack
= CLR_INVALID
;
1725 WCHAR szPath
[MAX_PATH
], szIniFile
[MAX_PATH
];
1727 // does the folder exists?
1728 if (!SHGetPathFromIDListW(pidlRoot
, szPath
) || !PathIsDirectoryW(szPath
))
1730 return E_INVALIDARG
;
1733 // don't use custom view in network path for security
1734 if (PathIsNetworkPath(szPath
))
1736 return E_ACCESSDENIED
;
1739 // build the ini file path
1740 StringCchCopyW(szIniFile
, _countof(szIniFile
), szPath
);
1741 PathAppend(szIniFile
, L
"desktop.ini");
1743 static LPCWSTR TheGUID
= L
"{BE098140-A513-11D0-A3A4-00C04FD706EC}";
1744 static LPCWSTR Space
= L
" \t\n\r\f\v";
1746 // get info from ini file
1747 WCHAR szImage
[MAX_PATH
], szText
[64];
1750 szImage
[0] = UNICODE_NULL
;
1751 GetPrivateProfileStringW(TheGUID
, L
"IconArea_Image", L
"", szImage
, _countof(szImage
), szIniFile
);
1754 StrTrimW(szImage
, Space
);
1755 if (PathIsRelativeW(szImage
))
1757 PathAppendW(szPath
, szImage
);
1758 StringCchCopyW(szImage
, _countof(szImage
), szPath
);
1760 data
->hbmBack
= DoLoadPicture(szImage
);
1763 // load the text color
1764 szText
[0] = UNICODE_NULL
;
1765 GetPrivateProfileStringW(TheGUID
, L
"IconArea_Text", L
"", szText
, _countof(szText
), szIniFile
);
1768 StrTrimW(szText
, Space
);
1770 LPWSTR pchEnd
= NULL
;
1771 COLORREF cr
= (wcstol(szText
, &pchEnd
, 0) & 0xFFFFFF);
1773 if (pchEnd
&& !*pchEnd
)
1777 // load the text background color
1778 szText
[0] = UNICODE_NULL
;
1779 GetPrivateProfileStringW(TheGUID
, L
"IconArea_TextBackground", L
"", szText
, _countof(szText
), szIniFile
);
1782 StrTrimW(szText
, Space
);
1784 LPWSTR pchEnd
= NULL
;
1785 COLORREF cr
= (wcstol(szText
, &pchEnd
, 0) & 0xFFFFFF);
1787 if (pchEnd
&& !*pchEnd
)
1788 data
->clrTextBack
= cr
;
1791 if (data
->hbmBack
!= NULL
|| data
->clrText
!= CLR_INVALID
|| data
->clrTextBack
!= CLR_INVALID
)
1797 HRESULT WINAPI
CFSFolder::MessageSFVCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1799 HRESULT hr
= E_NOTIMPL
;
1802 case SFVM_GET_CUSTOMVIEWINFO
:
1803 hr
= GetCustomViewInfo((ULONG
)wParam
, (SFVM_CUSTOMVIEWINFO_DATA
*)lParam
);