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