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