[SHELL32] Shell extension support for files.
[reactos.git] / reactos / dll / win32 / shell32 / folders / CFSFolder.cpp
1
2 /*
3 * file system folder
4 *
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL (shell);
26
27 HKEY OpenKeyFromFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName)
28 {
29 HKEY hkey;
30
31 if (!_ILIsValue(pidl))
32 {
33 ERR("Invalid pidl!\n");
34 return NULL;
35 }
36
37 FileStructW* pDataW = _ILGetFileStructW(pidl);
38 if (!pDataW)
39 {
40 ERR("Invalid pidl!\n");
41 return NULL;
42 }
43
44 LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
45 if (!pExtension || *pExtension == NULL)
46 {
47 WARN("No extension for %S!\n", pDataW->wszName);
48 return NULL;
49 }
50
51 WCHAR FullName[MAX_PATH];
52 DWORD dwSize = sizeof(FullName);
53 wsprintf(FullName, L"%s\\%s", pExtension, KeyName);
54
55 LONG res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey);
56 if (!res)
57 return hkey;
58
59 res = RegGetValueW(HKEY_CLASSES_ROOT, pExtension, NULL, RRF_RT_REG_SZ, NULL, FullName, &dwSize);
60 if (res)
61 {
62 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);
63 return NULL;
64 }
65
66 wcscat(FullName, L"\\");
67 wcscat(FullName, KeyName);
68
69 hkey = NULL;
70 res = RegOpenKeyExW(HKEY_CLASSES_ROOT, FullName, 0, KEY_READ, &hkey);
71 if (res)
72 WARN("Could not open key %S for extension %S\n", KeyName, pExtension);
73
74 return hkey;
75 }
76
77 HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
78 {
79 HKEY hkeyProgId = OpenKeyFromFileType(pidl, KeyName);
80 if (!hkeyProgId)
81 {
82 WARN("OpenKeyFromFileType failed for key %S\n", KeyName);
83 return S_FALSE;
84 }
85
86 WCHAR wszCLSIDValue[CHARS_IN_GUID];
87 DWORD dwSize = sizeof(wszCLSIDValue);
88 if (RegGetValueW(hkeyProgId, NULL, NULL, RRF_RT_REG_SZ, NULL, wszCLSIDValue, &dwSize))
89 {
90 ERR("OpenKeyFromFileType succeeded but RegGetValueW failed\n");
91 return S_FALSE;
92 }
93
94 #if 0
95 {
96 res = RegGetValueW(HKEY_LOCAL_MACHINE,
97 L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
98 wszCLSIDValue,
99 RRF_RT_REG_SZ,
100 NULL,
101 NULL,
102 NULL);
103 if (res != ERROR_SUCCESS)
104 {
105 ERR("DropHandler extension %S not approved\n", wszName);
106 return E_ACCESSDENIED;
107 }
108 }
109 #endif
110
111 HRESULT hres = CLSIDFromString (wszCLSIDValue, pclsid);
112 if (FAILED_UNEXPECTEDLY(hres))
113 return hres;
114
115 return S_OK;
116 }
117
118 static HRESULT getIconLocationForFolder(IShellFolder * psf, LPCITEMIDLIST pidl, UINT uFlags,
119 LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
120 {
121 static const WCHAR shellClassInfo[] = { '.', 'S', 'h', 'e', 'l', 'l', 'C', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 };
122 static const WCHAR iconFile[] = { 'I', 'c', 'o', 'n', 'F', 'i', 'l', 'e', 0 };
123 static const WCHAR clsid[] = { 'C', 'L', 'S', 'I', 'D', 0 };
124 static const WCHAR clsid2[] = { 'C', 'L', 'S', 'I', 'D', '2', 0 };
125 static const WCHAR iconIndex[] = { 'I', 'c', 'o', 'n', 'I', 'n', 'd', 'e', 'x', 0 };
126 static const WCHAR wszDesktopIni[] = { 'd','e','s','k','t','o','p','.','i','n','i',0 };
127 int icon_idx;
128
129 if (!(uFlags & GIL_DEFAULTICON) && (_ILGetFileAttributes(ILFindLastID(pidl), NULL, 0) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0 )
130 {
131 WCHAR wszFolderPath[MAX_PATH];
132
133 if (!ILGetDisplayNameExW(psf, pidl, wszFolderPath, 0))
134 return FALSE;
135
136 PathAppendW(wszFolderPath, wszDesktopIni);
137
138 if (PathFileExistsW(wszFolderPath))
139 {
140 WCHAR wszPath[MAX_PATH];
141 WCHAR wszCLSIDValue[CHARS_IN_GUID];
142
143 if (GetPrivateProfileStringW(shellClassInfo, iconFile, NULL, wszPath, MAX_PATH, wszFolderPath))
144 {
145 ExpandEnvironmentStringsW(wszPath, szIconFile, cchMax);
146
147 *piIndex = GetPrivateProfileIntW(shellClassInfo, iconIndex, 0, wszFolderPath);
148 return S_OK;
149 }
150 else if (GetPrivateProfileStringW(shellClassInfo, clsid, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
151 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
152 {
153 *piIndex = icon_idx;
154 return S_OK;
155 }
156 else if (GetPrivateProfileStringW(shellClassInfo, clsid2, NULL, wszCLSIDValue, CHARS_IN_GUID, wszFolderPath) &&
157 HCR_GetIconW(wszCLSIDValue, szIconFile, NULL, cchMax, &icon_idx))
158 {
159 *piIndex = icon_idx;
160 return S_OK;
161 }
162 }
163 }
164
165 static const WCHAR folder[] = { 'F', 'o', 'l', 'd', 'e', 'r', 0 };
166
167 if (!HCR_GetIconW(folder, szIconFile, NULL, cchMax, &icon_idx))
168 {
169 lstrcpynW(szIconFile, swShell32Name, cchMax);
170 icon_idx = -IDI_SHELL_FOLDER;
171 }
172
173 if (uFlags & GIL_OPENICON)
174 *piIndex = icon_idx < 0 ? icon_idx - 1 : icon_idx + 1;
175 else
176 *piIndex = icon_idx;
177
178 return S_OK;
179 }
180
181 HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut)
182 {
183 CComPtr<IDefaultExtractIconInit> initIcon;
184 HRESULT hr;
185 int icon_idx = 0;
186 UINT flags = 0; // FIXME: Use it!
187 WCHAR wTemp[MAX_PATH] = L"";
188
189 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
190 if (FAILED(hr))
191 return hr;
192
193 if (_ILIsFolder (pidl))
194 {
195 if (SUCCEEDED(getIconLocationForFolder(psf,
196 pidl, 0, wTemp, _countof(wTemp),
197 &icon_idx,
198 &flags)))
199 {
200 initIcon->SetNormalIcon(wTemp, icon_idx);
201 // FIXME: if/when getIconLocationForFolder does something for
202 // GIL_FORSHORTCUT, code below should be uncommented. and
203 // the following line removed.
204 initIcon->SetShortcutIcon(wTemp, icon_idx);
205 }
206 if (SUCCEEDED(getIconLocationForFolder(psf,
207 pidl, GIL_DEFAULTICON, wTemp, _countof(wTemp),
208 &icon_idx,
209 &flags)))
210 {
211 initIcon->SetDefaultIcon(wTemp, icon_idx);
212 }
213 // if (SUCCEEDED(getIconLocationForFolder(psf,
214 // pidl, GIL_FORSHORTCUT, wTemp, _countof(wTemp),
215 // &icon_idx,
216 // &flags)))
217 // {
218 // initIcon->SetShortcutIcon(wTemp, icon_idx);
219 // }
220 if (SUCCEEDED(getIconLocationForFolder(psf,
221 pidl, GIL_OPENICON, wTemp, _countof(wTemp),
222 &icon_idx,
223 &flags)))
224 {
225 initIcon->SetOpenIcon(wTemp, icon_idx);
226 }
227 }
228 else
229 {
230 HKEY hkey = OpenKeyFromFileType(pidl, L"DefaultIcon");
231 if (!hkey)
232 WARN("Could not open DefaultIcon key!\n");
233
234 DWORD dwSize = sizeof(wTemp);
235 if (hkey && !SHQueryValueExW(hkey, NULL, NULL, NULL, wTemp, &dwSize))
236 {
237 WCHAR sNum[5];
238 if (ParseFieldW (wTemp, 2, sNum, 5))
239 icon_idx = _wtoi(sNum);
240 else
241 icon_idx = 0; /* sometimes the icon number is missing */
242 ParseFieldW (wTemp, 1, wTemp, MAX_PATH);
243 PathUnquoteSpacesW(wTemp);
244
245 if (!wcscmp(L"%1", wTemp)) /* icon is in the file */
246 {
247 ILGetDisplayNameExW(psf, pidl, wTemp, 0);
248 icon_idx = 0;
249 }
250
251 initIcon->SetNormalIcon(wTemp, icon_idx);
252 }
253 else
254 {
255 initIcon->SetNormalIcon(swShell32Name, 0);
256 }
257 }
258
259 return initIcon->QueryInterface(iid, ppvOut);
260 }
261
262 /*
263 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
264 returned by Next. When the enumerator is created, it can do numerous additional operations
265 including formatting a drive, reconnecting a network share drive, and requesting a disk
266 be inserted in a removable drive.
267 */
268
269 /***********************************************************************
270 * IShellFolder implementation
271 */
272
273 class CFileSysEnum :
274 public CEnumIDListBase
275 {
276 private:
277 public:
278 CFileSysEnum();
279 ~CFileSysEnum();
280 HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags);
281
282 BEGIN_COM_MAP(CFileSysEnum)
283 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
284 END_COM_MAP()
285 };
286
287 CFileSysEnum::CFileSysEnum()
288 {
289 }
290
291 CFileSysEnum::~CFileSysEnum()
292 {
293 }
294
295 HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR lpszPath, DWORD dwFlags)
296 {
297 WIN32_FIND_DATAW stffile;
298 HANDLE hFile;
299 WCHAR szPath[MAX_PATH];
300 BOOL succeeded = TRUE;
301 static const WCHAR stars[] = { '*','.','*',0 };
302 static const WCHAR dot[] = { '.',0 };
303 static const WCHAR dotdot[] = { '.','.',0 };
304
305 TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags);
306
307 if(!lpszPath || !lpszPath[0]) return FALSE;
308
309 wcscpy(szPath, lpszPath);
310 PathAddBackslashW(szPath);
311 wcscat(szPath,stars);
312
313 hFile = FindFirstFileW(szPath,&stffile);
314 if ( hFile != INVALID_HANDLE_VALUE )
315 {
316 BOOL findFinished = FALSE;
317
318 do
319 {
320 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
321 || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
322 {
323 LPITEMIDLIST pidl = NULL;
324
325 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
326 dwFlags & SHCONTF_FOLDERS &&
327 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
328 {
329 pidl = _ILCreateFromFindDataW(&stffile);
330 succeeded = succeeded && AddToEnumList(pidl);
331 }
332 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
333 && dwFlags & SHCONTF_NONFOLDERS)
334 {
335 pidl = _ILCreateFromFindDataW(&stffile);
336 succeeded = succeeded && AddToEnumList(pidl);
337 }
338 }
339 if (succeeded)
340 {
341 if (!FindNextFileW(hFile, &stffile))
342 {
343 if (GetLastError() == ERROR_NO_MORE_FILES)
344 findFinished = TRUE;
345 else
346 succeeded = FALSE;
347 }
348 }
349 } while (succeeded && !findFinished);
350 FindClose(hFile);
351 }
352
353 return succeeded;
354 }
355
356 CFSFolder::CFSFolder()
357 {
358 pclsid = (CLSID *)&CLSID_ShellFSFolder;
359 sPathTarget = NULL;
360 pidlRoot = NULL;
361 m_bGroupPolicyActive = 0;
362 }
363
364 CFSFolder::~CFSFolder()
365 {
366 TRACE("-- destroying IShellFolder(%p)\n", this);
367
368 SHFree(pidlRoot);
369 SHFree(sPathTarget);
370 }
371
372
373 static const shvheader GenericSFHeader[] = {
374 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
375 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 0},
376 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
377 {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
378 {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12},
379 {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}
380 };
381
382 #define GENERICSHELLVIEWCOLUMNS 6
383
384 /**************************************************************************
385 * SHELL32_CreatePidlFromBindCtx [internal]
386 *
387 * If the caller bound File System Bind Data, assume it is the
388 * find data for the path.
389 * This allows binding of paths that don't exist.
390 */
391 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
392 {
393 IFileSystemBindData *fsbd = NULL;
394 LPITEMIDLIST pidl = NULL;
395 IUnknown *param = NULL;
396 WIN32_FIND_DATAW wfd;
397 HRESULT r;
398
399 TRACE("%p %s\n", pbc, debugstr_w(path));
400
401 if (!pbc)
402 return NULL;
403
404 /* see if the caller bound File System Bind Data */
405 r = pbc->GetObjectParam((LPOLESTR)STR_FILE_SYS_BIND_DATA, &param);
406 if (FAILED(r))
407 return NULL;
408
409 r = param->QueryInterface(IID_PPV_ARG(IFileSystemBindData,&fsbd));
410 if (SUCCEEDED(r))
411 {
412 r = fsbd->GetFindData(&wfd);
413 if (SUCCEEDED(r))
414 {
415 lstrcpynW(&wfd.cFileName[0], path, MAX_PATH);
416 pidl = _ILCreateFromFindDataW(&wfd);
417 }
418 fsbd->Release();
419 }
420
421 return pidl;
422 }
423
424 void SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, CLSID* pclsidFolder)
425 {
426 WCHAR wszCLSIDValue[CHARS_IN_GUID];
427 WCHAR wszDesktopIni[MAX_PATH];
428 StringCchCopyW(wszDesktopIni, MAX_PATH, pwszDir);
429 StringCchCatW(wszDesktopIni, MAX_PATH, L"\\desktop.ini");
430
431 if (GetPrivateProfileStringW(L".ShellClassInfo",
432 L"CLSID",
433 L"",
434 wszCLSIDValue,
435 CHARS_IN_GUID,
436 wszDesktopIni))
437 {
438 CLSIDFromString (wszCLSIDValue, pclsidFolder);
439 }
440 }
441
442
443 static const DWORD dwSupportedAttr=
444 SFGAO_CANCOPY | /*0x00000001 */
445 SFGAO_CANMOVE | /*0x00000002 */
446 SFGAO_CANLINK | /*0x00000004 */
447 SFGAO_CANRENAME | /*0x00000010 */
448 SFGAO_CANDELETE | /*0x00000020 */
449 SFGAO_HASPROPSHEET | /*0x00000040 */
450 SFGAO_DROPTARGET | /*0x00000100 */
451 SFGAO_LINK | /*0x00010000 */
452 SFGAO_READONLY | /*0x00040000 */
453 SFGAO_HIDDEN | /*0x00080000 */
454 SFGAO_FILESYSANCESTOR | /*0x10000000 */
455 SFGAO_FOLDER | /*0x20000000 */
456 SFGAO_FILESYSTEM | /*0x40000000 */
457 SFGAO_HASSUBFOLDER; /*0x80000000 */
458
459 HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
460 {
461 DWORD dwFileAttributes, dwShellAttributes;
462
463 if (!_ILIsFolder(pidl) && !_ILIsValue(pidl))
464 {
465 ERR("Got wrong type of pidl!\n");
466 *pdwAttributes &= SFGAO_CANLINK;
467 return S_OK;
468 }
469
470 if (*pdwAttributes & ~dwSupportedAttr)
471 {
472 WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes & ~dwSupportedAttr));
473 *pdwAttributes &= dwSupportedAttr;
474 }
475
476 dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0);
477
478 /* Set common attributes */
479 dwShellAttributes = *pdwAttributes;
480 dwShellAttributes |= SFGAO_FILESYSTEM | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE |
481 SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANCOPY;
482
483 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
484 {
485 dwShellAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
486 }
487 else
488 dwShellAttributes &= ~(SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
489
490 if (dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
491 dwShellAttributes |= SFGAO_HIDDEN;
492 else
493 dwShellAttributes &= ~SFGAO_HIDDEN;
494
495 if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
496 dwShellAttributes |= SFGAO_READONLY;
497 else
498 dwShellAttributes &= ~SFGAO_READONLY;
499
500 if (SFGAO_LINK & *pdwAttributes)
501 {
502 char ext[MAX_PATH];
503
504 if (!_ILGetExtension(pidl, ext, MAX_PATH) || lstrcmpiA(ext, "lnk"))
505 dwShellAttributes &= ~SFGAO_LINK;
506 }
507
508 if (SFGAO_HASSUBFOLDER & *pdwAttributes)
509 {
510 CComPtr<IShellFolder> psf2;
511 if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_PPV_ARG(IShellFolder, &psf2))))
512 {
513 CComPtr<IEnumIDList> pEnumIL;
514 if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL)))
515 {
516 if (pEnumIL->Skip(1) != S_OK)
517 dwShellAttributes &= ~SFGAO_HASSUBFOLDER;
518 }
519 }
520 }
521
522 *pdwAttributes &= dwShellAttributes;
523
524 TRACE ("-- 0x%08x\n", *pdwAttributes);
525 return S_OK;
526 }
527
528 /**************************************************************************
529 * CFSFolder::ParseDisplayName {SHELL32}
530 *
531 * Parse a display name.
532 *
533 * PARAMS
534 * hwndOwner [in] Parent window for any message's
535 * pbc [in] optional FileSystemBindData context
536 * lpszDisplayName [in] Unicode displayname.
537 * pchEaten [out] (unicode) characters processed
538 * ppidl [out] complex pidl to item
539 * pdwAttributes [out] items attributes
540 *
541 * NOTES
542 * Every folder tries to parse only its own (the leftmost) pidl and creates a
543 * subfolder to evaluate the remaining parts.
544 * Now we can parse into namespaces implemented by shell extensions
545 *
546 * Behaviour on win98: lpszDisplayName=NULL -> crash
547 * lpszDisplayName="" -> returns mycoputer-pidl
548 *
549 * FIXME
550 * pdwAttributes is not set
551 * pchEaten is not set like in windows
552 */
553 HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner,
554 LPBC pbc,
555 LPOLESTR lpszDisplayName,
556 DWORD *pchEaten, PIDLIST_RELATIVE *ppidl,
557 DWORD *pdwAttributes)
558 {
559 HRESULT hr = E_INVALIDARG;
560 LPCWSTR szNext = NULL;
561 WCHAR szElement[MAX_PATH];
562 WCHAR szPath[MAX_PATH];
563 LPITEMIDLIST pidlTemp = NULL;
564 DWORD len;
565
566 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
567 this, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
568 pchEaten, ppidl, pdwAttributes);
569
570 if (!ppidl)
571 return E_INVALIDARG;
572
573 if (!lpszDisplayName)
574 {
575 *ppidl = NULL;
576 return E_INVALIDARG;
577 }
578
579 *ppidl = NULL;
580
581 if (pchEaten)
582 *pchEaten = 0; /* strange but like the original */
583
584 if (*lpszDisplayName)
585 {
586 /* get the next element */
587 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
588
589 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement);
590 if (pidlTemp != NULL)
591 {
592 /* We are creating an id list without ensuring that the items exist.
593 If we have a remaining path, this must be a folder.
594 We have to do it now because it is set as a file by default */
595 if (szNext)
596 {
597 pidlTemp->mkid.abID[0] = PT_FOLDER;
598 }
599 hr = S_OK;
600 }
601 else
602 {
603 /* build the full pathname to the element */
604 lstrcpynW(szPath, sPathTarget, MAX_PATH - 1);
605 PathAddBackslashW(szPath);
606 len = wcslen(szPath);
607 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
608
609 /* get the pidl */
610 hr = _ILCreateFromPathW(szPath, &pidlTemp);
611 }
612
613 if (SUCCEEDED(hr))
614 {
615 if (szNext && *szNext)
616 {
617 /* try to analyse the next element */
618 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
619 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
620 }
621 else
622 {
623 /* it's the last element */
624 if (pdwAttributes && *pdwAttributes)
625 hr = SHELL32_GetFSItemAttributes(this, pidlTemp, pdwAttributes);
626 }
627 }
628 }
629
630 if (SUCCEEDED(hr))
631 *ppidl = pidlTemp;
632 else
633 *ppidl = NULL;
634
635 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr);
636
637 return hr;
638 }
639
640 /**************************************************************************
641 * CFSFolder::EnumObjects
642 * PARAMETERS
643 * HWND hwndOwner, //[in ] Parent Window
644 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
645 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
646 */
647 HRESULT WINAPI CFSFolder::EnumObjects(
648 HWND hwndOwner,
649 DWORD dwFlags,
650 LPENUMIDLIST *ppEnumIDList)
651 {
652 return ShellObjectCreatorInit<CFileSysEnum>(sPathTarget, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
653 }
654
655 /**************************************************************************
656 * CFSFolder::BindToObject
657 * PARAMETERS
658 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
659 * LPBC pbc, //[in ] optional FileSystemBindData context
660 * REFIID riid, //[in ] Initial Interface
661 * LPVOID* ppvObject //[out] Interface*
662 */
663 HRESULT WINAPI CFSFolder::BindToObject(
664 PCUIDLIST_RELATIVE pidl,
665 LPBC pbc,
666 REFIID riid,
667 LPVOID * ppvOut)
668 {
669 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc,
670 shdebugstr_guid(&riid), ppvOut);
671
672 CComPtr<IShellFolder> pSF;
673 HRESULT hr;
674
675 if (!pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb)
676 {
677 ERR("CFSFolder::BindToObject: Invalid parameters\n");
678 return E_INVALIDARG;
679 }
680
681 if (!_ILIsFolder(pidl) && !_ILIsValue(pidl))
682 {
683 ERR("CFSFolder::BindToObject: Invalid pidl!\n");
684 return E_INVALIDARG;
685 }
686
687 /* Get the pidl data */
688 FileStruct* pData = &_ILGetDataPointer(pidl)->u.file;
689 FileStructW* pDataW = _ILGetFileStructW(pidl);
690
691 if (!pDataW)
692 {
693 ERR("CFSFolder::BindToObject: Invalid pidl!\n");
694 return E_INVALIDARG;
695 }
696
697 *ppvOut = NULL;
698
699 /* Create the target folder info */
700 PERSIST_FOLDER_TARGET_INFO pfti = {0};
701 pfti.dwAttributes = -1;
702 pfti.csidl = -1;
703 PathCombineW(pfti.szTargetParsingName, sPathTarget, pDataW->wszName);
704
705 /* Get the CLSID to bind to */
706 CLSID clsidFolder;
707 if (_ILIsFolder(pidl))
708 {
709 clsidFolder = CLSID_ShellFSFolder;
710
711 if ((pData->uFileAttribs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
712 SHELL32_GetCLSIDForDirectory(pfti.szTargetParsingName, &clsidFolder);
713 }
714 else
715 {
716 hr = GetCLSIDForFileType(pidl, L"CLSID", &clsidFolder);
717 if (hr == S_FALSE)
718 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
719 if (hr != S_OK)
720 return hr;
721 }
722
723 hr = SHELL32_BindToSF(pidlRoot, &pfti, pidl, &clsidFolder, riid, ppvOut);
724 if (FAILED_UNEXPECTEDLY(hr))
725 return hr;
726
727 TRACE ("-- returning (%p) %08x\n", *ppvOut, hr);
728
729 return S_OK;
730
731 }
732
733 /**************************************************************************
734 * CFSFolder::BindToStorage
735 * PARAMETERS
736 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
737 * LPBC pbc, //[in ] reserved
738 * REFIID riid, //[in ] Initial storage interface
739 * LPVOID* ppvObject //[out] Interface* returned
740 */
741 HRESULT WINAPI CFSFolder::BindToStorage(
742 PCUIDLIST_RELATIVE pidl,
743 LPBC pbcReserved,
744 REFIID riid,
745 LPVOID *ppvOut)
746 {
747 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved,
748 shdebugstr_guid (&riid), ppvOut);
749
750 *ppvOut = NULL;
751 return E_NOTIMPL;
752 }
753
754 /**************************************************************************
755 * CFSFolder::CompareIDs
756 */
757
758 HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
759 PCUIDLIST_RELATIVE pidl1,
760 PCUIDLIST_RELATIVE pidl2)
761 {
762 LPPIDLDATA pData1 = _ILGetDataPointer(pidl1);
763 LPPIDLDATA pData2 = _ILGetDataPointer(pidl2);
764 FileStructW* pDataW1 = _ILGetFileStructW(pidl1);
765 FileStructW* pDataW2 = _ILGetFileStructW(pidl2);
766 BOOL bIsFolder1 = _ILIsFolder(pidl1);
767 BOOL bIsFolder2 = _ILIsFolder(pidl2);
768 LPWSTR pExtension1, pExtension2;
769
770 if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS)
771 return E_INVALIDARG;
772
773 /* When sorting between a File and a Folder, the Folder gets sorted first */
774 if (bIsFolder1 != bIsFolder2)
775 {
776 return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
777 }
778
779 int result;
780 switch (LOWORD(lParam))
781 {
782 case 0: /* Name */
783 result = wcsicmp(pDataW1->wszName, pDataW2->wszName);
784 break;
785 case 1: /* Comments */
786 result = 0;
787 break;
788 case 2: /* Type */
789 pExtension1 = PathFindExtensionW(pDataW1->wszName);
790 pExtension2 = PathFindExtensionW(pDataW2->wszName);
791 result = wcsicmp(pExtension1, pExtension2);
792 break;
793 case 3: /* Size */
794 result = pData1->u.file.dwFileSize - pData2->u.file.dwFileSize;
795 break;
796 case 4: /* Modified */
797 result = pData1->u.file.uFileDate - pData2->u.file.uFileDate;
798 if (result == 0)
799 result = pData1->u.file.uFileTime - pData2->u.file.uFileTime;
800 break;
801 case 5: /* Attributes */
802 return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
803 }
804
805 if (result == 0)
806 return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
807
808 return MAKE_COMPARE_HRESULT(result);
809 }
810
811 /**************************************************************************
812 * CFSFolder::CreateViewObject
813 */
814 HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
815 REFIID riid, LPVOID * ppvOut)
816 {
817 CComPtr<IShellView> pShellView;
818 HRESULT hr = E_INVALIDARG;
819
820 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid (&riid),
821 ppvOut);
822
823 if (ppvOut)
824 {
825 *ppvOut = NULL;
826
827 if (IsEqualIID (riid, IID_IDropTarget))
828 hr = CFSDropTarget_CreateInstance(sPathTarget, riid, ppvOut);
829 else if (IsEqualIID (riid, IID_IContextMenu))
830 {
831 HKEY hKeys[16];
832 UINT cKeys = 0;
833 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
834
835 DEFCONTEXTMENU dcm;
836 dcm.hwnd = hwndOwner;
837 dcm.pcmcb = this;
838 dcm.pidlFolder = pidlRoot;
839 dcm.psf = this;
840 dcm.cidl = 0;
841 dcm.apidl = NULL;
842 dcm.cKeys = cKeys;
843 dcm.aKeys = hKeys;
844 dcm.punkAssociationInfo = NULL;
845 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
846 }
847 else if (IsEqualIID (riid, IID_IShellView))
848 {
849 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
850 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
851 }
852 }
853 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
854 return hr;
855 }
856
857 /**************************************************************************
858 * CFSFolder::GetAttributesOf
859 *
860 * PARAMETERS
861 * UINT cidl, //[in ] num elements in pidl array
862 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
863 * ULONG* rgfInOut) //[out] result array
864 *
865 */
866 HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
867 PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
868 {
869 HRESULT hr = S_OK;
870
871 if (!rgfInOut)
872 return E_INVALIDARG;
873 if (cidl && !apidl)
874 return E_INVALIDARG;
875
876 if (*rgfInOut == 0)
877 *rgfInOut = ~0;
878
879 if(cidl == 0)
880 {
881 LPCITEMIDLIST rpidl = ILFindLastID(pidlRoot);
882
883 if (_ILIsFolder(rpidl) || _ILIsValue(rpidl))
884 {
885 SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut);
886 }
887 else if (_ILIsDrive(rpidl))
888 {
889 IShellFolder *psfParent = NULL;
890 hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), NULL);
891 if(SUCCEEDED(hr))
892 {
893 hr = psfParent->GetAttributesOf(1, &rpidl, (SFGAOF*)rgfInOut);
894 psfParent->Release();
895 }
896 }
897 else
898 {
899 ERR("Got and unknown pidl!\n");
900 }
901 }
902 else
903 {
904 while (cidl > 0 && *apidl)
905 {
906 pdump(*apidl);
907 if(_ILIsFolder(*apidl) || _ILIsValue(*apidl))
908 SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut);
909 else
910 ERR("Got an unknown type of pidl!!!\n");
911 apidl++;
912 cidl--;
913 }
914 }
915 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
916 *rgfInOut &= ~SFGAO_VALIDATE;
917
918 TRACE("-- result=0x%08x\n", *rgfInOut);
919
920 return hr;
921 }
922
923 /**************************************************************************
924 * CFSFolder::GetUIObjectOf
925 *
926 * PARAMETERS
927 * HWND hwndOwner, //[in ] Parent window for any output
928 * UINT cidl, //[in ] array size
929 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
930 * REFIID riid, //[in ] Requested Interface
931 * UINT* prgfInOut, //[ ] reserved
932 * LPVOID* ppvObject) //[out] Resulting Interface
933 *
934 * NOTES
935 * This function gets asked to return "view objects" for one or more (multiple
936 * select) items:
937 * The viewobject typically is an COM object with one of the following
938 * interfaces:
939 * IExtractIcon,IDataObject,IContextMenu
940 * In order to support icon positions in the default Listview your DataObject
941 * must implement the SetData method (in addition to GetData :) - the shell
942 * passes a barely documented "Icon positions" structure to SetData when the
943 * drag starts, and GetData's it if the drop is in another explorer window that
944 * needs the positions.
945 */
946 HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
947 UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
948 REFIID riid, UINT * prgfInOut,
949 LPVOID * ppvOut)
950 {
951 LPVOID pObj = NULL;
952 HRESULT hr = E_INVALIDARG;
953
954 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
955 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
956
957 if (ppvOut)
958 {
959 *ppvOut = NULL;
960
961 if (cidl == 1)
962 {
963 hr = _CreateExtensionUIObject(apidl[0], riid, ppvOut);
964 if(hr != S_FALSE)
965 return hr;
966 }
967
968 if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
969 {
970 HKEY hKeys[16];
971 UINT cKeys = 0;
972 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys);
973
974 DEFCONTEXTMENU dcm;
975 dcm.hwnd = hwndOwner;
976 dcm.pcmcb = this;
977 dcm.pidlFolder = pidlRoot;
978 dcm.psf = this;
979 dcm.cidl = cidl;
980 dcm.apidl = apidl;
981 dcm.cKeys = cKeys;
982 dcm.aKeys = hKeys;
983 dcm.punkAssociationInfo = NULL;
984 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
985 }
986 else if (IsEqualIID (riid, IID_IDataObject))
987 {
988 if (cidl >= 1)
989 {
990 hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
991 }
992 else
993 {
994 hr = E_INVALIDARG;
995 }
996 }
997 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
998 {
999 hr = _GetIconHandler(apidl[0], riid, (LPVOID*)&pObj);
1000 if (hr != S_OK)
1001 hr = CFSExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
1002 }
1003 else if (IsEqualIID (riid, IID_IDropTarget))
1004 {
1005 /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
1006 if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj)))
1007 {
1008 hr = CFSDropTarget_CreateInstance(sPathTarget, riid, (LPVOID*) &pObj);
1009 }
1010 }
1011 else
1012 hr = E_NOINTERFACE;
1013
1014 if (SUCCEEDED(hr) && !pObj)
1015 hr = E_OUTOFMEMORY;
1016
1017 *ppvOut = pObj;
1018 }
1019 TRACE("(%p)->hr=0x%08x\n", this, hr);
1020 return hr;
1021 }
1022
1023 static const WCHAR AdvancedW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
1024 static const WCHAR HideFileExtW[] = L"HideFileExt";
1025 static const WCHAR NeverShowExtW[] = L"NeverShowExt";
1026
1027 /******************************************************************************
1028 * SHELL_FS_HideExtension [Internal]
1029 *
1030 * Query the registry if the filename extension of a given path should be
1031 * hidden.
1032 *
1033 * PARAMS
1034 * szPath [I] Relative or absolute path of a file
1035 *
1036 * RETURNS
1037 * TRUE, if the filename's extension should be hidden
1038 * FALSE, otherwise.
1039 */
1040 BOOL SHELL_FS_HideExtension(LPWSTR szPath)
1041 {
1042 HKEY hKey;
1043 DWORD dwData;
1044 DWORD dwDataSize = sizeof (DWORD);
1045 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
1046
1047 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
1048 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
1049 doHide = dwData;
1050 RegCloseKey (hKey);
1051 }
1052
1053 if (!doHide) {
1054 LPWSTR ext = PathFindExtensionW(szPath);
1055
1056 if (*ext != '\0') {
1057 WCHAR classname[MAX_PATH];
1058 LONG classlen = sizeof(classname);
1059
1060 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
1061 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
1062 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
1063 doHide = TRUE;
1064 RegCloseKey(hKey);
1065 }
1066 }
1067 }
1068 return doHide;
1069 }
1070
1071 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
1072 {
1073 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
1074 if (!(dwFlags & SHGDN_FORPARSING) &&
1075 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
1076 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
1077 PathRemoveExtensionW(szPath);
1078 }
1079 }
1080
1081 /**************************************************************************
1082 * CFSFolder::GetDisplayNameOf
1083 * Retrieves the display name for the specified file object or subfolder
1084 *
1085 * PARAMETERS
1086 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
1087 * DWORD dwFlags, //[in ] SHGNO formatting flags
1088 * LPSTRRET lpName) //[out] Returned display name
1089 *
1090 * FIXME
1091 * if the name is in the pidl the ret value should be a STRRET_OFFSET
1092 */
1093
1094 HRESULT WINAPI CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl,
1095 DWORD dwFlags, LPSTRRET strRet)
1096 {
1097 if (!strRet)
1098 return E_INVALIDARG;
1099
1100 /* If it is a complex pidl, let the child handle it */
1101 if (!_ILIsPidlSimple (pidl)) /* complex pidl */
1102 {
1103 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
1104 }
1105 else if (pidl && !pidl->mkid.cb) /* empty pidl */
1106 {
1107 /* If it is an empty pidl return only the path of the folder */
1108 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
1109 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
1110 sPathTarget)
1111 {
1112 return SHSetStrRet(strRet, sPathTarget);
1113 }
1114 return E_INVALIDARG;
1115 }
1116
1117 int len = 0;
1118 LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
1119 if (!pszPath)
1120 return E_OUTOFMEMORY;
1121
1122 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
1123 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
1124 sPathTarget)
1125 {
1126 lstrcpynW(pszPath, sPathTarget, MAX_PATH);
1127 PathAddBackslashW(pszPath);
1128 len = wcslen(pszPath);
1129 }
1130 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
1131 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
1132
1133 strRet->uType = STRRET_WSTR;
1134 strRet->pOleStr = pszPath;
1135
1136 TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
1137 return S_OK;
1138 }
1139
1140 /**************************************************************************
1141 * CFSFolder::SetNameOf
1142 * Changes the name of a file object or subfolder, possibly changing its item
1143 * identifier in the process.
1144 *
1145 * PARAMETERS
1146 * HWND hwndOwner, //[in ] Owner window for output
1147 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
1148 * LPCOLESTR lpszName, //[in ] the items new display name
1149 * DWORD dwFlags, //[in ] SHGNO formatting flags
1150 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
1151 */
1152 HRESULT WINAPI CFSFolder::SetNameOf(
1153 HWND hwndOwner,
1154 PCUITEMID_CHILD pidl,
1155 LPCOLESTR lpName,
1156 DWORD dwFlags,
1157 PITEMID_CHILD *pPidlOut)
1158 {
1159 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
1160 LPWSTR ptr;
1161 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
1162
1163 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
1164 debugstr_w (lpName), dwFlags, pPidlOut);
1165
1166 /* build source path */
1167 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
1168 ptr = PathAddBackslashW (szSrc);
1169 if (ptr)
1170 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
1171
1172 /* build destination path */
1173 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
1174 lstrcpynW(szDest, sPathTarget, MAX_PATH);
1175 ptr = PathAddBackslashW (szDest);
1176 if (ptr)
1177 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
1178 } else
1179 lstrcpynW(szDest, lpName, MAX_PATH);
1180
1181 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
1182 WCHAR *ext = PathFindExtensionW(szSrc);
1183 if(*ext != '\0') {
1184 INT len = wcslen(szDest);
1185 lstrcpynW(szDest + len, ext, MAX_PATH - len);
1186 }
1187 }
1188
1189 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
1190 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
1191 {
1192 /* src and destination is the same */
1193 HRESULT hr = S_OK;
1194 if (pPidlOut)
1195 hr = _ILCreateFromPathW(szDest, pPidlOut);
1196
1197 return hr;
1198 }
1199
1200
1201 if (MoveFileW (szSrc, szDest))
1202 {
1203 HRESULT hr = S_OK;
1204
1205 if (pPidlOut)
1206 hr = _ILCreateFromPathW(szDest, pPidlOut);
1207
1208 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
1209 SHCNF_PATHW, szSrc, szDest);
1210
1211 return hr;
1212 }
1213
1214 return E_FAIL;
1215 }
1216
1217 HRESULT WINAPI CFSFolder::GetDefaultSearchGUID(GUID * pguid)
1218 {
1219 FIXME ("(%p)\n", this);
1220 return E_NOTIMPL;
1221 }
1222
1223 HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum)
1224 {
1225 FIXME ("(%p)\n", this);
1226 return E_NOTIMPL;
1227 }
1228
1229 HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes,
1230 ULONG * pSort, ULONG * pDisplay)
1231 {
1232 TRACE ("(%p)\n", this);
1233
1234 if (pSort)
1235 *pSort = 0;
1236 if (pDisplay)
1237 *pDisplay = 0;
1238
1239 return S_OK;
1240 }
1241
1242 HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn,
1243 DWORD * pcsFlags)
1244 {
1245 TRACE ("(%p)\n", this);
1246
1247 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
1248 return E_INVALIDARG;
1249
1250 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
1251
1252 return S_OK;
1253 }
1254
1255 HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl,
1256 const SHCOLUMNID * pscid, VARIANT * pv)
1257 {
1258 FIXME ("(%p)\n", this);
1259
1260 return E_NOTIMPL;
1261 }
1262
1263 HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
1264 UINT iColumn, SHELLDETAILS * psd)
1265 {
1266 HRESULT hr = E_FAIL;
1267
1268 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
1269
1270 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
1271 return E_INVALIDARG;
1272
1273 if (!pidl)
1274 {
1275 /* the header titles */
1276 psd->fmt = GenericSFHeader[iColumn].fmt;
1277 psd->cxChar = GenericSFHeader[iColumn].cxChar;
1278 return SHSetStrRet(&psd->str, GenericSFHeader[iColumn].colnameid);
1279 }
1280 else
1281 {
1282 hr = S_OK;
1283 psd->str.uType = STRRET_CSTR;
1284 /* the data from the pidl */
1285 switch (iColumn)
1286 {
1287 case 0: /* name */
1288 hr = GetDisplayNameOf (pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
1289 break;
1290 case 1: /* FIXME: comments */
1291 psd->str.cStr[0] = 0;
1292 break;
1293 case 2: /* type */
1294 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
1295 break;
1296 case 3: /* size */
1297 _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
1298 break;
1299 case 4: /* date */
1300 _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH);
1301 break;
1302 case 5: /* attributes */
1303 _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH);
1304 break;
1305 }
1306 }
1307
1308 return hr;
1309 }
1310
1311 HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column,
1312 SHCOLUMNID * pscid)
1313 {
1314 FIXME ("(%p)\n", this);
1315 return E_NOTIMPL;
1316 }
1317
1318 /************************************************************************
1319 * CFSFolder::GetClassID
1320 */
1321 HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId)
1322 {
1323 TRACE ("(%p)\n", this);
1324
1325 if (!lpClassId)
1326 return E_POINTER;
1327
1328 *lpClassId = *pclsid;
1329
1330 return S_OK;
1331 }
1332
1333 /************************************************************************
1334 * CFSFolder::Initialize
1335 *
1336 * NOTES
1337 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1338 */
1339 HRESULT WINAPI CFSFolder::Initialize(LPCITEMIDLIST pidl)
1340 {
1341 WCHAR wszTemp[MAX_PATH];
1342
1343 TRACE ("(%p)->(%p)\n", this, pidl);
1344
1345 SHFree (pidlRoot); /* free the old pidl */
1346 pidlRoot = ILClone (pidl); /* set my pidl */
1347
1348 SHFree (sPathTarget);
1349 sPathTarget = NULL;
1350
1351 /* set my path */
1352 if (SHGetPathFromIDListW (pidl, wszTemp))
1353 {
1354 int len = wcslen(wszTemp);
1355 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1356 if (!sPathTarget)
1357 return E_OUTOFMEMORY;
1358 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1359 }
1360
1361 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget));
1362 return S_OK;
1363 }
1364
1365 /**************************************************************************
1366 * CFSFolder::GetCurFolder
1367 */
1368 HRESULT WINAPI CFSFolder::GetCurFolder(LPITEMIDLIST * pidl)
1369 {
1370 TRACE ("(%p)->(%p)\n", this, pidl);
1371
1372 if (!pidl)
1373 return E_POINTER;
1374
1375 *pidl = ILClone(pidlRoot);
1376 return S_OK;
1377 }
1378
1379 /**************************************************************************
1380 * CFSFolder::InitializeEx
1381 *
1382 * FIXME: error handling
1383 */
1384 HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx,
1385 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1386 {
1387 WCHAR wszTemp[MAX_PATH];
1388
1389 TRACE("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti);
1390 if (ppfti)
1391 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1392 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1393 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1394 ppfti->csidl);
1395
1396 pdump (pidlRootx);
1397 if (ppfti && ppfti->pidlTargetFolder)
1398 pdump(ppfti->pidlTargetFolder);
1399
1400 if (pidlRoot)
1401 __SHFreeAndNil(&pidlRoot); /* free the old */
1402 if (sPathTarget)
1403 __SHFreeAndNil(&sPathTarget);
1404
1405 /*
1406 * Root path and pidl
1407 */
1408 pidlRoot = ILClone(pidlRootx);
1409
1410 /*
1411 * the target folder is spezified in csidl OR pidlTargetFolder OR
1412 * szTargetParsingName
1413 */
1414 if (ppfti)
1415 {
1416 if (ppfti->csidl != -1)
1417 {
1418 if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl,
1419 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1420 int len = wcslen(wszTemp);
1421 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1422 if (!sPathTarget)
1423 return E_OUTOFMEMORY;
1424 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1425 }
1426 }
1427 else if (ppfti->szTargetParsingName[0])
1428 {
1429 int len = wcslen(ppfti->szTargetParsingName);
1430 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1431 if (!sPathTarget)
1432 return E_OUTOFMEMORY;
1433 memcpy(sPathTarget, ppfti->szTargetParsingName,
1434 (len + 1) * sizeof(WCHAR));
1435 }
1436 else if (ppfti->pidlTargetFolder)
1437 {
1438 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp))
1439 {
1440 int len = wcslen(wszTemp);
1441 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1442 if (!sPathTarget)
1443 return E_OUTOFMEMORY;
1444 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1445 }
1446 }
1447 }
1448
1449 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget));
1450 pdump(pidlRoot);
1451 return (sPathTarget) ? S_OK : E_FAIL;
1452 }
1453
1454 HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti)
1455 {
1456 FIXME("(%p)->(%p)\n", this, ppfti);
1457 ZeroMemory(ppfti, sizeof (*ppfti));
1458 return E_NOTIMPL;
1459 }
1460
1461 HRESULT CFSFolder::_CreateExtensionUIObject(PCUIDLIST_RELATIVE pidl, REFIID riid, LPVOID *ppvOut)
1462 {
1463 static const WCHAR formatW[] = {'S','h','e','l','l','E','x','\\',
1464 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
1465 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
1466 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
1467 WCHAR buf[MAX_PATH];
1468
1469 sprintfW(buf, formatW, riid.Data1, riid.Data2, riid.Data3,
1470 riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
1471 riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
1472
1473 CLSID clsid;
1474 HRESULT hr;
1475
1476 hr = GetCLSIDForFileType(pidl, buf, &clsid);
1477 if (hr != S_OK)
1478 return hr;
1479
1480 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut);
1481 if (FAILED_UNEXPECTEDLY(hr))
1482 return hr;
1483
1484 return S_OK;
1485 }
1486
1487 HRESULT CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut)
1488 {
1489 HRESULT hr;
1490
1491 TRACE("CFSFolder::_GetDropTarget entered\n");
1492
1493 if (_ILIsFolder (pidl))
1494 {
1495 CComPtr<IShellFolder> psfChild;
1496 hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
1497 if (FAILED_UNEXPECTEDLY(hr))
1498 return hr;
1499
1500 return psfChild->CreateViewObject(NULL, IID_IDropTarget, ppvOut);
1501 }
1502
1503 CLSID clsid;
1504 hr = GetCLSIDForFileType(pidl, L"shellex\\DropHandler", &clsid);
1505 if (hr != S_OK)
1506 return hr;
1507
1508 hr = _CreateShellExtInstance(&clsid, pidl, IID_IDropTarget, ppvOut);
1509 if (FAILED_UNEXPECTEDLY(hr))
1510 return S_FALSE;
1511
1512 return S_OK;
1513 }
1514
1515 HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
1516 {
1517 CLSID clsid;
1518 HRESULT hr;
1519
1520 hr = GetCLSIDForFileType(pidl, L"shellex\\IconHandler", &clsid);
1521 if (hr != S_OK)
1522 return hr;
1523
1524 hr = _CreateShellExtInstance(&clsid, pidl, riid, ppvOut);
1525 if (FAILED_UNEXPECTEDLY(hr))
1526 return S_FALSE;
1527
1528 return S_OK;
1529 }
1530
1531 HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
1532 {
1533 HRESULT hr;
1534 WCHAR wszPath[MAX_PATH];
1535
1536 FileStructW* pDataW = _ILGetFileStructW(pidl);
1537 if (!pDataW)
1538 {
1539 ERR("Got garbage pidl\n");
1540 return E_INVALIDARG;
1541 }
1542
1543 PathCombineW(wszPath, sPathTarget, pDataW->wszName);
1544
1545 CComPtr<IPersistFile> pp;
1546 hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp));
1547 if (FAILED_UNEXPECTEDLY(hr))
1548 return hr;
1549
1550 pp->Load(wszPath, 0);
1551
1552 hr = pp->QueryInterface(riid, ppvOut);
1553 if (hr != S_OK)
1554 {
1555 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
1556 return hr;
1557 }
1558 return hr;
1559 }
1560
1561 HRESULT WINAPI CFSFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
1562 {
1563 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
1564 return S_OK;
1565
1566 /* no data object means no selection */
1567 if (!pdtobj)
1568 {
1569 if (uMsg == DFM_INVOKECOMMAND && wParam == 0)
1570 {
1571 PUITEMID_CHILD pidlChild = ILClone(ILFindLastID(pidlRoot));
1572 LPITEMIDLIST pidlParent = ILClone(pidlRoot);
1573 ILRemoveLastID(pidlParent);
1574 HRESULT hr = SH_ShowPropertiesDialog(sPathTarget, pidlParent, &pidlChild);
1575 if (FAILED(hr))
1576 ERR("SH_ShowPropertiesDialog failed\n");
1577 ILFree(pidlChild);
1578 ILFree(pidlParent);
1579 }
1580 else if (uMsg == DFM_MERGECONTEXTMENU)
1581 {
1582 QCMINFO *pqcminfo = (QCMINFO *)lParam;
1583 HMENU hpopup = CreatePopupMenu();
1584 _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
1585 Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
1586 DestroyMenu(hpopup);
1587 }
1588
1589 return S_OK;
1590 }
1591
1592 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
1593 return S_OK;
1594
1595 PIDLIST_ABSOLUTE pidlFolder;
1596 PUITEMID_CHILD *apidl;
1597 UINT cidl;
1598 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
1599 if (FAILED_UNEXPECTEDLY(hr))
1600 return hr;
1601
1602 if (cidl > 1)
1603 ERR("SHMultiFileProperties is not yet implemented\n");
1604
1605 STRRET strFile;
1606 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile);
1607 if (SUCCEEDED(hr))
1608 {
1609 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl);
1610 if (FAILED(hr))
1611 ERR("SH_ShowPropertiesDialog failed\n");
1612 }
1613 else
1614 {
1615 ERR("Failed to get display name\n");
1616 }
1617
1618 SHFree(pidlFolder);
1619 _ILFreeaPidl(apidl, cidl);
1620
1621 return hr;
1622 }