msxml3: Support setting unlimited nesting depth for a reader.
[wine] / dlls / shell32 / shfldr_mycomp.c
1 /*
2  *    Virtual Workplace folder
3  *
4  *    Copyright 1997            Marcus Meissner
5  *    Copyright 1998, 1999, 2002    Juergen Schmied
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #define COBJMACROS
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38
39 #include "wingdi.h"
40 #include "pidl.h"
41 #include "shlguid.h"
42 #include "enumidlist.h"
43 #include "undocshell.h"
44 #include "shell32_main.h"
45 #include "shresdef.h"
46 #include "shlwapi.h"
47 #include "wine/debug.h"
48 #include "debughlp.h"
49 #include "shfldr.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL (shell);
52
53 /***********************************************************************
54 *   IShellFolder implementation
55 */
56
57 typedef struct {
58     IShellFolder2   IShellFolder2_iface;
59     IPersistFolder2 IPersistFolder2_iface;
60     LONG            ref;
61
62     /* both paths are parsible from the desktop */
63     LPITEMIDLIST pidlRoot;    /* absolute pidl */
64 } IMyComputerFolderImpl;
65
66 static const IShellFolder2Vtbl vt_ShellFolder2;
67 static const IPersistFolder2Vtbl vt_PersistFolder2;
68
69 static inline IMyComputerFolderImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
70 {
71     return CONTAINING_RECORD(iface, IMyComputerFolderImpl, IShellFolder2_iface);
72 }
73
74 static inline IMyComputerFolderImpl *impl_from_IPersistFolder2(IPersistFolder2 *iface)
75 {
76     return CONTAINING_RECORD(iface, IMyComputerFolderImpl, IPersistFolder2_iface);
77 }
78
79
80 /***********************************************************************
81 *   IShellFolder [MyComputer] implementation
82 */
83
84 static const shvheader mycomputer_header[] = {
85     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
86     {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
87     {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
88     {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
89 };
90
91 #define MYCOMPUTERSHELLVIEWCOLUMNS sizeof(mycomputer_header)/sizeof(shvheader)
92
93 /**************************************************************************
94 *    ISF_MyComputer_Constructor
95 */
96 HRESULT WINAPI ISF_MyComputer_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
97 {
98     IMyComputerFolderImpl *sf;
99
100     TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
101
102     if (!ppv)
103         return E_POINTER;
104     if (pUnkOuter)
105         return CLASS_E_NOAGGREGATION;
106
107     sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IMyComputerFolderImpl));
108     if (!sf)
109         return E_OUTOFMEMORY;
110
111     sf->ref = 0;
112     sf->IShellFolder2_iface.lpVtbl = &vt_ShellFolder2;
113     sf->IPersistFolder2_iface.lpVtbl = &vt_PersistFolder2;
114     sf->pidlRoot = _ILCreateMyComputer ();    /* my qualified pidl */
115
116     if (FAILED (IUnknown_QueryInterface (&sf->IShellFolder2_iface, riid, ppv)))
117     {
118         IUnknown_Release (&sf->IShellFolder2_iface);
119         return E_NOINTERFACE;
120     }
121
122     TRACE ("--(%p)\n", sf);
123     return S_OK;
124 }
125
126 /**************************************************************************
127  *    ISF_MyComputer_fnQueryInterface
128  *
129  * NOTES supports not IPersist/IPersistFolder
130  */
131 static HRESULT WINAPI ISF_MyComputer_fnQueryInterface (IShellFolder2 *iface,
132                REFIID riid, LPVOID *ppvObj)
133 {
134     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
135
136     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
137
138     *ppvObj = NULL;
139
140     if (IsEqualIID (riid, &IID_IUnknown) ||
141         IsEqualIID (riid, &IID_IShellFolder) ||
142         IsEqualIID (riid, &IID_IShellFolder2))
143     {
144         *ppvObj = This;
145     }
146     else if (IsEqualIID (riid, &IID_IPersist) ||
147              IsEqualIID (riid, &IID_IPersistFolder) ||
148              IsEqualIID (riid, &IID_IPersistFolder2))
149     {
150         *ppvObj = &This->IPersistFolder2_iface;
151     }
152
153     if (*ppvObj)
154     {
155         IUnknown_AddRef ((IUnknown *) (*ppvObj));
156         TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
157         return S_OK;
158     }
159     TRACE ("-- Interface: E_NOINTERFACE\n");
160     return E_NOINTERFACE;
161 }
162
163 static ULONG WINAPI ISF_MyComputer_fnAddRef (IShellFolder2 * iface)
164 {
165     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
166     ULONG refCount = InterlockedIncrement(&This->ref);
167
168     TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
169
170     return refCount;
171 }
172
173 static ULONG WINAPI ISF_MyComputer_fnRelease (IShellFolder2 * iface)
174 {
175     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
176     ULONG refCount = InterlockedDecrement(&This->ref);
177
178     TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
179
180     if (!refCount)
181     {
182         TRACE ("-- destroying IShellFolder(%p)\n", This);
183         SHFree (This->pidlRoot);
184         LocalFree (This);
185     }
186     return refCount;
187 }
188
189 /**************************************************************************
190 *    ISF_MyComputer_fnParseDisplayName
191 */
192 static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName (IShellFolder2 *iface,
193                HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
194                DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
195 {
196     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
197     HRESULT hr = E_INVALIDARG;
198     LPCWSTR szNext = NULL;
199     WCHAR szElement[MAX_PATH];
200     LPITEMIDLIST pidlTemp = NULL;
201     CLSID clsid;
202
203     TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", This,
204           hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
205           pchEaten, ppidl, pdwAttributes);
206
207     *ppidl = 0;
208     if (pchEaten)
209         *pchEaten = 0;        /* strange but like the original */
210
211     /* handle CLSID paths */
212     if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
213     {
214         szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
215         TRACE ("-- element: %s\n", debugstr_w (szElement));
216         SHCLSIDFromStringW (szElement + 2, &clsid);
217         pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
218     }
219     /* do we have an absolute path name ? */
220     else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
221               lpszDisplayName[2] == (WCHAR) '\\')
222     {
223         szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
224         /* make drive letter uppercase to enable PIDL comparison */
225         szElement[0] = toupper(szElement[0]);
226         pidlTemp = _ILCreateDrive (szElement);
227     }
228
229     if (szNext && *szNext)
230     {
231         hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc, &pidlTemp,
232                               (LPOLESTR) szNext, pchEaten, pdwAttributes);
233     }
234     else
235     {
236         if (pdwAttributes && *pdwAttributes)
237             SHELL32_GetItemAttributes ((IShellFolder*)&This->IShellFolder2_iface, pidlTemp,
238                     pdwAttributes);
239         hr = S_OK;
240     }
241
242     *ppidl = pidlTemp;
243
244     TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
245
246     return hr;
247 }
248
249 /* retrieve a map of drives that should be displayed */
250 static DWORD get_drive_map(void)
251 {
252     static const WCHAR policiesW[] = {'S','o','f','t','w','a','r','e','\\',
253                                       'M','i','c','r','o','s','o','f','t','\\',
254                                       'W','i','n','d','o','w','s','\\',
255                                       'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
256                                       'P','o','l','i','c','i','e','s','\\',
257                                       'E','x','p','l','o','r','e','r',0};
258     static const WCHAR nodrivesW[] = {'N','o','D','r','i','v','e','s',0};
259     static DWORD drive_mask, init_done;
260
261     if (!init_done)
262     {
263         DWORD type, size, data, mask = 0;
264         HKEY hkey;
265
266         if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, policiesW, &hkey ))
267         {
268             size = sizeof(data);
269             if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
270                 mask |= data;
271             RegCloseKey( hkey );
272         }
273         if (!RegOpenKeyW( HKEY_CURRENT_USER, policiesW, &hkey ))
274         {
275             size = sizeof(data);
276             if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
277                 mask |= data;
278             RegCloseKey( hkey );
279         }
280         drive_mask = mask;
281         init_done = 1;
282     }
283
284     return GetLogicalDrives() & ~drive_mask;
285 }
286
287 /**************************************************************************
288  *  CreateMyCompEnumList()
289  */
290 static const WCHAR MyComputer_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
291  '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
292  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
293  'o','r','e','r','\\','M','y','C','o','m','p','u','t','e','r','\\','N','a','m',
294  'e','s','p','a','c','e','\0' };
295
296 static BOOL CreateMyCompEnumList(IEnumIDList *list, DWORD dwFlags)
297 {
298     BOOL ret = TRUE;
299
300     TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
301
302     /* enumerate the folders */
303     if (dwFlags & SHCONTF_FOLDERS)
304     {
305         WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
306         DWORD dwDrivemap = get_drive_map();
307         HKEY hkey;
308         UINT i;
309
310         while (ret && wszDriveName[0]<='Z')
311         {
312             if(dwDrivemap & 0x00000001L)
313                 ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
314             wszDriveName[0]++;
315             dwDrivemap = dwDrivemap >> 1;
316         }
317
318         TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",list);
319         for (i=0; i<2; i++) {
320             if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
321                                       MyComputer_NameSpaceW, 0, KEY_READ, &hkey))
322             {
323                 WCHAR iid[50];
324                 int i=0;
325
326                 while (ret)
327                 {
328                     DWORD size;
329                     LONG r;
330
331                     size = sizeof(iid) / sizeof(iid[0]);
332                     r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
333                     if (ERROR_SUCCESS == r)
334                     {
335                         /* FIXME: shell extensions, shouldn't the type be
336                          * PT_SHELLEXT? */
337                         ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
338                         i++;
339                     }
340                     else if (ERROR_NO_MORE_ITEMS == r)
341                         break;
342                     else
343                         ret = FALSE;
344                 }
345                 RegCloseKey(hkey);
346             }
347         }
348     }
349     return ret;
350 }
351
352 /**************************************************************************
353 *        ISF_MyComputer_fnEnumObjects
354 */
355 static HRESULT WINAPI ISF_MyComputer_fnEnumObjects (IShellFolder2 *iface,
356                HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
357 {
358     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
359
360     TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This,
361           hwndOwner, dwFlags, ppEnumIDList);
362
363     *ppEnumIDList = IEnumIDList_Constructor();
364     if (*ppEnumIDList)
365         CreateMyCompEnumList(*ppEnumIDList, dwFlags);
366
367     TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
368
369     return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
370 }
371
372 /**************************************************************************
373 *        ISF_MyComputer_fnBindToObject
374 */
375 static HRESULT WINAPI ISF_MyComputer_fnBindToObject (IShellFolder2 *iface,
376                LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
377 {
378     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
379
380     TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This,
381           pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
382
383     return SHELL32_BindToChild (This->pidlRoot, NULL, pidl, riid, ppvOut);
384 }
385
386 /**************************************************************************
387 *    ISF_MyComputer_fnBindToStorage
388 */
389 static HRESULT WINAPI ISF_MyComputer_fnBindToStorage (IShellFolder2 * iface,
390                LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
391 {
392     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
393
394     FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This,
395           pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
396
397     *ppvOut = NULL;
398     return E_NOTIMPL;
399 }
400
401 /**************************************************************************
402 *     ISF_MyComputer_fnCompareIDs
403 */
404
405 static HRESULT WINAPI ISF_MyComputer_fnCompareIDs (IShellFolder2 *iface,
406                LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
407 {
408     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
409     HRESULT hr;
410
411     TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
412     hr = SHELL32_CompareIDs ((IShellFolder*)&This->IShellFolder2_iface, lParam, pidl1, pidl2);
413     TRACE ("-- 0x%08x\n", hr);
414     return hr;
415 }
416
417 /**************************************************************************
418 *    ISF_MyComputer_fnCreateViewObject
419 */
420 static HRESULT WINAPI ISF_MyComputer_fnCreateViewObject (IShellFolder2 *iface,
421                HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
422 {
423     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
424     LPSHELLVIEW pShellView;
425     HRESULT hr = E_INVALIDARG;
426
427     TRACE("(%p)->(hwnd=%p,%s,%p)\n", This,
428           hwndOwner, shdebugstr_guid (riid), ppvOut);
429
430     if (!ppvOut)
431         return hr;
432
433     *ppvOut = NULL;
434
435     if (IsEqualIID (riid, &IID_IDropTarget))
436     {
437         WARN ("IDropTarget not implemented\n");
438         hr = E_NOTIMPL;
439     }
440     else if (IsEqualIID (riid, &IID_IContextMenu))
441     {
442         WARN ("IContextMenu not implemented\n");
443         hr = E_NOTIMPL;
444     }
445     else if (IsEqualIID (riid, &IID_IShellView))
446     {
447         pShellView = IShellView_Constructor ((IShellFolder *) iface);
448         if (pShellView)
449         {
450             hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
451             IShellView_Release (pShellView);
452         }
453     }
454     TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
455     return hr;
456 }
457
458 /**************************************************************************
459 *  ISF_MyComputer_fnGetAttributesOf
460 */
461 static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf (IShellFolder2 * iface,
462                 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
463 {
464     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
465     HRESULT hr = S_OK;
466
467     TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
468            This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
469
470     if (!rgfInOut)
471         return E_INVALIDARG;
472     if (cidl && !apidl)
473         return E_INVALIDARG;
474
475     if (*rgfInOut == 0)
476         *rgfInOut = ~0;
477     
478     if(cidl == 0){
479         IShellFolder *psfParent = NULL;
480         LPCITEMIDLIST rpidl = NULL;
481
482         hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
483         if(SUCCEEDED(hr)) {
484             SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
485             IShellFolder_Release(psfParent);
486         }
487     } else {
488         while (cidl > 0 && *apidl) {
489             pdump (*apidl);
490             SHELL32_GetItemAttributes ((IShellFolder*)&This->IShellFolder2_iface, *apidl, rgfInOut);
491             apidl++;
492             cidl--;
493         }
494     }
495     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
496     *rgfInOut &= ~SFGAO_VALIDATE;
497
498     TRACE ("-- result=0x%08x\n", *rgfInOut);
499     return hr;
500 }
501
502 /**************************************************************************
503 *    ISF_MyComputer_fnGetUIObjectOf
504 *
505 * PARAMETERS
506 *  hwndOwner [in]  Parent window for any output
507 *  cidl      [in]  array size
508 *  apidl     [in]  simple pidl array
509 *  riid      [in]  Requested Interface
510 *  prgfInOut [   ] reserved
511 *  ppvObject [out] Resulting Interface
512 *
513 */
514 static HRESULT WINAPI ISF_MyComputer_fnGetUIObjectOf (IShellFolder2 * iface,
515                 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
516                 UINT * prgfInOut, LPVOID * ppvOut)
517 {
518     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
519
520     LPITEMIDLIST pidl;
521     IUnknown *pObj = NULL;
522     HRESULT hr = E_INVALIDARG;
523
524     TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", This,
525           hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
526
527     if (!ppvOut)
528         return hr;
529
530     *ppvOut = NULL;
531
532     if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1))
533     {
534         pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
535                                               This->pidlRoot, apidl, cidl);
536         hr = S_OK;
537     }
538     else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
539     {
540         pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
541                                               This->pidlRoot, apidl, cidl);
542         hr = S_OK;
543     }
544     else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
545     {
546         pidl = ILCombine (This->pidlRoot, apidl[0]);
547         pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
548         SHFree (pidl);
549         hr = S_OK;
550     }
551     else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
552     {
553         pidl = ILCombine (This->pidlRoot, apidl[0]);
554         pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
555         SHFree (pidl);
556         hr = S_OK;
557     }
558     else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
559     {
560         hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
561                                           (LPVOID *) &pObj);
562     }
563     else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
564               IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
565     {
566         pidl = ILCombine (This->pidlRoot, apidl[0]);
567         hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
568         SHFree (pidl);
569     }
570     else 
571         hr = E_NOINTERFACE;
572
573     if (SUCCEEDED(hr) && !pObj)
574         hr = E_OUTOFMEMORY;
575
576     *ppvOut = pObj;
577     TRACE ("(%p)->hr=0x%08x\n", This, hr);
578     return hr;
579 }
580
581 /**************************************************************************
582 *    ISF_MyComputer_fnGetDisplayNameOf
583 */
584 static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface,
585                LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
586 {
587     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
588
589     LPWSTR pszPath;
590     HRESULT hr = S_OK;
591
592     TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
593     pdump (pidl);
594
595     if (!strRet)
596         return E_INVALIDARG;
597
598     pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
599     if (!pszPath)
600         return E_OUTOFMEMORY;
601
602     pszPath[0] = 0;
603
604     if (!pidl->mkid.cb)
605     {
606         /* parsing name like ::{...} */
607         pszPath[0] = ':';
608         pszPath[1] = ':';
609         SHELL32_GUIDToStringW(&CLSID_MyComputer, &pszPath[2]);
610     }
611     else if (_ILIsPidlSimple(pidl))    
612     {
613         /* take names of special folders only if its only this folder */
614         if (_ILIsSpecialFolder(pidl))
615         {
616             GUID const *clsid;
617
618             clsid = _ILGetGUIDPointer (pidl);
619             if (clsid)
620             {
621                 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
622                 {
623                     static const WCHAR clsidW[] =
624                      { 'C','L','S','I','D','\\',0 };
625                     static const WCHAR shellfolderW[] =
626                      { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
627                     static const WCHAR wantsForParsingW[] =
628                      { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
629                      'g',0 };
630                     int bWantsForParsing = FALSE;
631                     WCHAR szRegPath[100];
632                     LONG r;
633
634                     /*
635                      * We can only get a filesystem path from a shellfolder
636                      * if the value WantsFORPARSING exists in
637                      *      CLSID\\{...}\\shellfolder 
638                      * exception: the MyComputer folder has this keys not
639                      *            but like any filesystem backed
640                      *            folder it needs these behaviour
641                      *
642                      * Get the "WantsFORPARSING" flag from the registry
643                      */
644
645                     lstrcpyW (szRegPath, clsidW);
646                     SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
647                     lstrcatW (szRegPath, shellfolderW);
648                     r = SHGetValueW (HKEY_CLASSES_ROOT, szRegPath, 
649                                      wantsForParsingW, NULL, NULL, NULL);
650                     if (r == ERROR_SUCCESS)
651                         bWantsForParsing = TRUE;
652
653                     if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
654                         bWantsForParsing)
655                     {
656                         /*
657                          * We need the filesystem path to the destination folder
658                          * Only the folder itself can know it
659                          */
660                         hr = SHELL32_GetDisplayNameOfChild (iface, pidl,
661                                                 dwFlags, pszPath, MAX_PATH);
662                     }
663                     else
664                     {
665                         LPWSTR p = pszPath;
666
667                         /* parsing name like ::{...} */
668                         p[0] = ':';
669                         p[1] = ':';
670                         p += 2;
671                         p += SHELL32_GUIDToStringW(&CLSID_MyComputer, p);
672
673                         /* \:: */
674                         p[0] = '\\';
675                         p[1] = ':';
676                         p[2] = ':';
677                         p += 3;
678                         SHELL32_GUIDToStringW(clsid, p);
679                     }
680                 }
681                 else
682                 {
683                     /* user friendly name */
684                     HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
685                 }
686             }
687             else
688             {
689                 /* append my own path */
690                 _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);
691             }
692         }
693         else if (_ILIsDrive(pidl))
694         {        
695             _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);    /* append my own path */
696
697             /* long view "lw_name (C:)" */
698             if (!(dwFlags & SHGDN_FORPARSING))
699             {
700                 DWORD dwVolumeSerialNumber, dwMaximumComponetLength, dwFileSystemFlags;
701                 WCHAR wszDrive[18] = {0};
702                 static const WCHAR wszOpenBracket[] = {' ','(',0};
703                 static const WCHAR wszCloseBracket[] = {')',0};
704
705                 GetVolumeInformationW (pszPath, wszDrive,
706                            sizeof(wszDrive)/sizeof(wszDrive[0]) - 6,
707                            &dwVolumeSerialNumber,
708                            &dwMaximumComponetLength, &dwFileSystemFlags, NULL, 0);
709                 strcatW (wszDrive, wszOpenBracket);
710                 lstrcpynW (wszDrive + strlenW(wszDrive), pszPath, 3);
711                 strcatW (wszDrive, wszCloseBracket);
712                 strcpyW (pszPath, wszDrive);
713             }
714         }
715         else 
716         {
717             /* Neither a shell namespace extension nor a drive letter. */
718             ERR("Wrong pidl type\n");
719             CoTaskMemFree(pszPath);
720             return E_INVALIDARG;
721         }
722     }
723     else
724     {
725         /* Complex pidl. Let the child folder do the work */
726         hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
727     }
728
729     if (SUCCEEDED (hr))
730     {
731         /* Win9x always returns ANSI strings, NT always returns Unicode strings */
732         if (GetVersion() & 0x80000000)
733         {
734             strRet->uType = STRRET_CSTR;
735             if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
736                     NULL, NULL))
737                 strRet->u.cStr[0] = '\0';
738             CoTaskMemFree(pszPath);
739         }
740         else
741         {
742             strRet->uType = STRRET_WSTR;
743             strRet->u.pOleStr = pszPath;
744         }
745     }
746     else
747         CoTaskMemFree(pszPath);
748
749     TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
750     return hr;
751 }
752
753 /**************************************************************************
754 *  ISF_MyComputer_fnSetNameOf
755 *  Changes the name of a file object or subfolder, possibly changing its item
756 *  identifier in the process.
757 *
758 * PARAMETERS
759 *  hwndOwner  [in]   Owner window for output
760 *  pidl       [in]   simple pidl of item to change
761 *  lpszName   [in]   the items new display name
762 *  dwFlags    [in]   SHGNO formatting flags
763 *  ppidlOut   [out]  simple pidl returned
764 */
765 static HRESULT WINAPI ISF_MyComputer_fnSetNameOf (
766                IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl,
767                LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
768 {
769     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
770     FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This,
771            hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
772     return E_FAIL;
773 }
774
775 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultSearchGUID (
776                IShellFolder2 * iface, GUID * pguid)
777 {
778     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
779     FIXME ("(%p)\n", This);
780     return E_NOTIMPL;
781 }
782 static HRESULT WINAPI ISF_MyComputer_fnEnumSearches (
783                IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
784 {
785     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
786     FIXME ("(%p)\n", This);
787     return E_NOTIMPL;
788 }
789 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumn (
790                IShellFolder2 *iface, DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
791 {
792     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
793
794     TRACE ("(%p)\n", This);
795
796     if (pSort)
797          *pSort = 0;
798     if (pDisplay)
799         *pDisplay = 0;
800     return S_OK;
801 }
802 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumnState (
803                IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
804 {
805     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
806
807     TRACE ("(%p)->(%d %p)\n", This, iColumn, pcsFlags);
808
809     if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
810         return E_INVALIDARG;
811
812     *pcsFlags = mycomputer_header[iColumn].pcsFlags;
813
814     return S_OK;
815 }
816
817 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsEx (IShellFolder2 * iface,
818                LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
819 {
820     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
821     FIXME ("(%p)\n", This);
822     return E_NOTIMPL;
823 }
824
825 /* FIXME: drive size >4GB is rolling over */
826 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsOf (IShellFolder2 *iface,
827                LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
828 {
829     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
830     char szPath[MAX_PATH];
831     ULARGE_INTEGER ulBytes;
832     HRESULT hr = S_OK;
833
834     TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
835
836     if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
837         return E_INVALIDARG;
838
839     if (!pidl)
840         return SHELL32_GetColumnDetails(mycomputer_header, iColumn, psd);
841
842     psd->str.u.cStr[0] = 0;
843     psd->str.uType = STRRET_CSTR;
844
845     switch (iColumn)
846     {
847         case 0:        /* name */
848             hr = IShellFolder_GetDisplayNameOf (iface, pidl,
849                        SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
850             break;
851         case 1:        /* type */
852             _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
853             break;
854         case 2:        /* total size */
855             if (_ILIsDrive (pidl))
856             {
857                 _ILSimpleGetText (pidl, szPath, MAX_PATH);
858                 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
859                 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
860             }
861             break;
862         case 3:        /* free size */
863             if (_ILIsDrive (pidl))
864             {
865                 _ILSimpleGetText (pidl, szPath, MAX_PATH);
866                 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
867                 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
868             }
869             break;
870     }
871
872     return hr;
873 }
874
875 static HRESULT WINAPI ISF_MyComputer_fnMapColumnToSCID (
876                IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
877 {
878     IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
879     FIXME ("(%p)\n", This);
880     return E_NOTIMPL;
881 }
882
883 static const IShellFolder2Vtbl vt_ShellFolder2 =
884 {
885     ISF_MyComputer_fnQueryInterface,
886     ISF_MyComputer_fnAddRef,
887     ISF_MyComputer_fnRelease,
888     ISF_MyComputer_fnParseDisplayName,
889     ISF_MyComputer_fnEnumObjects,
890     ISF_MyComputer_fnBindToObject,
891     ISF_MyComputer_fnBindToStorage,
892     ISF_MyComputer_fnCompareIDs,
893     ISF_MyComputer_fnCreateViewObject,
894     ISF_MyComputer_fnGetAttributesOf,
895     ISF_MyComputer_fnGetUIObjectOf,
896     ISF_MyComputer_fnGetDisplayNameOf,
897     ISF_MyComputer_fnSetNameOf,
898     /* ShellFolder2 */
899     ISF_MyComputer_fnGetDefaultSearchGUID,
900     ISF_MyComputer_fnEnumSearches,
901     ISF_MyComputer_fnGetDefaultColumn,
902     ISF_MyComputer_fnGetDefaultColumnState,
903     ISF_MyComputer_fnGetDetailsEx,
904     ISF_MyComputer_fnGetDetailsOf,
905     ISF_MyComputer_fnMapColumnToSCID
906 };
907
908 /************************************************************************
909  *    IMCFldr_PersistFolder2_QueryInterface
910  */
911 static HRESULT WINAPI IMCFldr_PersistFolder2_QueryInterface (
912                IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObj)
913 {
914     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
915     TRACE ("(%p)\n", This);
916     return IUnknown_QueryInterface (&This->IShellFolder2_iface, iid, ppvObj);
917 }
918
919 /************************************************************************
920  *    IMCFldr_PersistFolder2_AddRef
921  */
922 static ULONG WINAPI IMCFldr_PersistFolder2_AddRef (IPersistFolder2 * iface)
923 {
924     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
925     TRACE ("(%p)->(count=%u)\n", This, This->ref);
926     return IUnknown_AddRef (&This->IShellFolder2_iface);
927 }
928
929 /************************************************************************
930  *    ISFPersistFolder_Release
931  */
932 static ULONG WINAPI IMCFldr_PersistFolder2_Release (IPersistFolder2 * iface)
933 {
934     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
935     TRACE ("(%p)->(count=%u)\n", This, This->ref);
936     return IUnknown_Release (&This->IShellFolder2_iface);
937 }
938
939 /************************************************************************
940  *    IMCFldr_PersistFolder2_GetClassID
941  */
942 static HRESULT WINAPI IMCFldr_PersistFolder2_GetClassID (
943                IPersistFolder2 * iface, CLSID * lpClassId)
944 {
945     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
946
947     TRACE ("(%p)\n", This);
948
949     if (!lpClassId)
950     return E_POINTER;
951     *lpClassId = CLSID_MyComputer;
952
953     return S_OK;
954 }
955
956 /************************************************************************
957  *    IMCFldr_PersistFolder2_Initialize
958  *
959  * NOTES: it makes no sense to change the pidl
960  */
961 static HRESULT WINAPI IMCFldr_PersistFolder2_Initialize (
962                IPersistFolder2 * iface, LPCITEMIDLIST pidl)
963 {
964     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
965     TRACE ("(%p)->(%p)\n", This, pidl);
966     return E_NOTIMPL;
967 }
968
969 /**************************************************************************
970  *    IPersistFolder2_fnGetCurFolder
971  */
972 static HRESULT WINAPI IMCFldr_PersistFolder2_GetCurFolder (
973                IPersistFolder2 * iface, LPITEMIDLIST * pidl)
974 {
975     IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
976
977     TRACE ("(%p)->(%p)\n", This, pidl);
978
979     if (!pidl)
980         return E_POINTER;
981     *pidl = ILClone (This->pidlRoot);
982     return S_OK;
983 }
984
985 static const IPersistFolder2Vtbl vt_PersistFolder2 =
986 {
987     IMCFldr_PersistFolder2_QueryInterface,
988     IMCFldr_PersistFolder2_AddRef,
989     IMCFldr_PersistFolder2_Release,
990     IMCFldr_PersistFolder2_GetClassID,
991     IMCFldr_PersistFolder2_Initialize,
992     IMCFldr_PersistFolder2_GetCurFolder
993 };