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