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