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