shfldr_mycomp.c 32.1 KB
Newer Older
1
/*
2
 *    Virtual Workplace folder
3
 *
4 5
 *    Copyright 1997            Marcus Meissner
 *    Copyright 1998, 1999, 2002    Juergen Schmied
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 23 24 25 26
 */

#include "config.h"
#include "wine/port.h"

#include <stdlib.h>
#include <string.h>
27
#include <stdarg.h>
28 29
#include <stdio.h>

30
#define COBJMACROS
31 32
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
33

34
#include "winerror.h"
35
#include "windef.h"
36 37 38
#include "winbase.h"
#include "winreg.h"

39
#include "wingdi.h"
40
#include "pidl.h"
41
#include "shlguid.h"
42
#include "enumidlist.h"
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#include "undocshell.h"
#include "shell32_main.h"
#include "shresdef.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "debughlp.h"
#include "shfldr.h"

WINE_DEFAULT_DEBUG_CHANNEL (shell);

/***********************************************************************
*   IShellFolder implementation
*/

typedef struct {
58
    const IShellFolder2Vtbl   *lpVtbl;
Mike McCormack's avatar
Mike McCormack committed
59
    LONG                ref;
60
    const IPersistFolder2Vtbl *lpVtblPersistFolder2;
61 62

    /* both paths are parsible from the desktop */
63
    LPITEMIDLIST pidlRoot;    /* absolute pidl */
64 65
} IGenericSFImpl;

66 67
static const IShellFolder2Vtbl vt_ShellFolder2;
static const IPersistFolder2Vtbl vt_PersistFolder2;
68

69 70 71 72 73
static inline IGenericSFImpl *impl_from_IPersistFolder2( IPersistFolder2 *iface )
{
    return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpVtblPersistFolder2));
}

74 75

/*
76
  converts This to an interface pointer
77
*/
78 79 80
#define _IUnknown_(This)    (IUnknown*)&(This->lpVtbl)
#define _IShellFolder_(This)    (IShellFolder*)&(This->lpVtbl)
#define _IShellFolder2_(This)    (IShellFolder2*)&(This->lpVtbl)
81

82 83 84
#define _IPersist_(This)    (IPersist*)&(This->lpVtblPersistFolder2)
#define _IPersistFolder_(This)    (IPersistFolder*)&(This->lpVtblPersistFolder2)
#define _IPersistFolder2_(This)    (IPersistFolder2*)&(This->lpVtblPersistFolder2)
85 86 87 88 89

/***********************************************************************
*   IShellFolder [MyComputer] implementation
*/

90
static const shvheader MyComputerSFHeader[] = {
91 92 93 94 95 96 97 98 99
    {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
    {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
    {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
    {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
};

#define MYCOMPUTERSHELLVIEWCOLUMNS 4

/**************************************************************************
100
*    ISF_MyComputer_Constructor
101 102 103 104 105 106 107 108
*/
HRESULT WINAPI ISF_MyComputer_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
{
    IGenericSFImpl *sf;

    TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));

    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 125
    {
        IUnknown_Release (_IUnknown_ (sf));
        return E_NOINTERFACE;
126 127 128 129 130 131 132
    }

    TRACE ("--(%p)\n", sf);
    return S_OK;
}

/**************************************************************************
133
 *    ISF_MyComputer_fnQueryInterface
134 135 136
 *
 * NOTES supports not IPersist/IPersistFolder
 */
137 138
static HRESULT WINAPI ISF_MyComputer_fnQueryInterface (IShellFolder2 *iface,
               REFIID riid, LPVOID *ppvObj)
139
{
140
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
141 142 143 144 145 146

    TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);

    *ppvObj = NULL;

    if (IsEqualIID (riid, &IID_IUnknown) ||
147 148 149 150 151 152 153 154 155 156
        IsEqualIID (riid, &IID_IShellFolder) ||
        IsEqualIID (riid, &IID_IShellFolder2))
    {
        *ppvObj = This;
    }
    else if (IsEqualIID (riid, &IID_IPersist) ||
             IsEqualIID (riid, &IID_IPersistFolder) ||
             IsEqualIID (riid, &IID_IPersistFolder2))
    {
        *ppvObj = _IPersistFolder2_ (This);
157 158
    }

159 160 161 162 163
    if (*ppvObj)
    {
        IUnknown_AddRef ((IUnknown *) (*ppvObj));
        TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
        return S_OK;
164 165 166 167 168 169 170
    }
    TRACE ("-- Interface: E_NOINTERFACE\n");
    return E_NOINTERFACE;
}

static ULONG WINAPI ISF_MyComputer_fnAddRef (IShellFolder2 * iface)
{
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 180
}

static ULONG WINAPI ISF_MyComputer_fnRelease (IShellFolder2 * iface)
{
181
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
182
    ULONG refCount = InterlockedDecrement(&This->ref);
183

184
    TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
185

186 187
    if (!refCount)
    {
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 199 200
static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName (IShellFolder2 *iface,
               HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
               DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
201
{
202
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
203
    HRESULT hr = E_INVALIDARG;
204 205
    LPCWSTR szNext = NULL;
    WCHAR szElement[MAX_PATH];
206 207
    LPITEMIDLIST pidlTemp = NULL;
    CLSID clsid;
208

209 210 211
    TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", This,
          hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
          pchEaten, ppidl, pdwAttributes);
212 213 214

    *ppidl = 0;
    if (pchEaten)
215
        *pchEaten = 0;        /* strange but like the original */
216

217
    /* handle CLSID paths */
218 219 220 221 222 223
    if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
    {
        szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
        TRACE ("-- element: %s\n", debugstr_w (szElement));
        SHCLSIDFromStringW (szElement + 2, &clsid);
        pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
224
    }
225
    /* do we have an absolute path name ? */
226 227 228 229 230 231 232
    else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
              lpszDisplayName[2] == (WCHAR) '\\')
    {
        szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
        /* make drive letter uppercase to enable PIDL comparison */
        szElement[0] = toupper(szElement[0]);
        pidlTemp = _ILCreateDrive (szElement);
233
    }
234

235 236 237 238 239 240 241 242 243 244 245
    if (szNext && *szNext)
    {
        hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc, &pidlTemp,
                              (LPOLESTR) szNext, pchEaten, pdwAttributes);
    }
    else
    {
        if (pdwAttributes && *pdwAttributes)
            SHELL32_GetItemAttributes (_IShellFolder_ (This),
                                       pidlTemp, pdwAttributes);
        hr = S_OK;
246 247
    }

248 249
    *ppidl = pidlTemp;

250
    TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
251 252 253 254

    return hr;
}

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
/* retrieve a map of drives that should be displayed */
static DWORD get_drive_map(void)
{
    static const WCHAR policiesW[] = {'S','o','f','t','w','a','r','e','\\',
                                      'M','i','c','r','o','s','o','f','t','\\',
                                      'W','i','n','d','o','w','s','\\',
                                      'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
                                      'P','o','l','i','c','i','e','s','\\',
                                      'E','x','p','l','o','r','e','r',0};
    static const WCHAR nodrivesW[] = {'N','o','D','r','i','v','e','s',0};
    static DWORD drive_mask, init_done;

    if (!init_done)
    {
        DWORD type, size, data, mask = 0;
        HKEY hkey;

        if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, policiesW, &hkey ))
        {
            size = sizeof(data);
            if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
                mask |= data;
            RegCloseKey( hkey );
        }
        if (!RegOpenKeyW( HKEY_CURRENT_USER, policiesW, &hkey ))
        {
            size = sizeof(data);
            if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
                mask |= data;
            RegCloseKey( hkey );
        }
        drive_mask = mask;
        init_done = 1;
    }

    return GetLogicalDrives() & ~drive_mask;
}

293 294 295
/**************************************************************************
 *  CreateMyCompEnumList()
 */
296 297 298 299 300 301
static const WCHAR MyComputer_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
 'o','r','e','r','\\','M','y','C','o','m','p','u','t','e','r','\\','N','a','m',
 'e','s','p','a','c','e','\0' };

302 303 304 305
static BOOL CreateMyCompEnumList(IEnumIDList *list, DWORD dwFlags)
{
    BOOL ret = TRUE;

306
    TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
307

308 309
    /* enumerate the folders */
    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 320
                ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
            wszDriveName[0]++;
321 322 323 324
            dwDrivemap = dwDrivemap >> 1;
        }

        TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",list);
325 326 327
        for (i=0; i<2; i++) {
            if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
                                      MyComputer_NameSpaceW, 0, KEY_READ, &hkey))
328
            {
329 330
                WCHAR iid[50];
                int i=0;
331

332
                while (ret)
333
                {
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
                    DWORD size;
                    LONG r;

                    size = sizeof(iid) / sizeof(iid[0]);
                    r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
                    if (ERROR_SUCCESS == r)
                    {
                        /* FIXME: shell extensions, shouldn't the type be
                         * PT_SHELLEXT? */
                        ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
                        i++;
                    }
                    else if (ERROR_NO_MORE_ITEMS == r)
                        break;
                    else
                        ret = FALSE;
350
                }
351
                RegCloseKey(hkey);
352 353 354 355 356 357
            }
        }
    }
    return ret;
}

358
/**************************************************************************
359
*        ISF_MyComputer_fnEnumObjects
360
*/
361 362
static HRESULT WINAPI ISF_MyComputer_fnEnumObjects (IShellFolder2 *iface,
               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 370 371
    *ppEnumIDList = IEnumIDList_Constructor();
    if (*ppEnumIDList)
        CreateMyCompEnumList(*ppEnumIDList, dwFlags);
372 373 374 375 376 377 378

    TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);

    return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
}

/**************************************************************************
379
*        ISF_MyComputer_fnBindToObject
380
*/
381 382
static HRESULT WINAPI ISF_MyComputer_fnBindToObject (IShellFolder2 *iface,
               LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
383
{
384
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
385

386 387
    TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This,
          pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
388 389 390 391 392

    return SHELL32_BindToChild (This->pidlRoot, NULL, pidl, riid, ppvOut);
}

/**************************************************************************
393
*    ISF_MyComputer_fnBindToStorage
394
*/
395 396
static HRESULT WINAPI ISF_MyComputer_fnBindToStorage (IShellFolder2 * iface,
               LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
397
{
398
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
399

400 401
    FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This,
          pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
402 403 404 405 406 407

    *ppvOut = NULL;
    return E_NOTIMPL;
}

/**************************************************************************
408
*     ISF_MyComputer_fnCompareIDs
409 410
*/

411 412
static HRESULT WINAPI ISF_MyComputer_fnCompareIDs (IShellFolder2 *iface,
               LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
413
{
414
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
415 416 417 418 419 420 421 422 423
    int nReturn;

    TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
    nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
    TRACE ("-- %i\n", nReturn);
    return nReturn;
}

/**************************************************************************
424
*    ISF_MyComputer_fnCreateViewObject
425
*/
426 427
static HRESULT WINAPI ISF_MyComputer_fnCreateViewObject (IShellFolder2 *iface,
               HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
428
{
429
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
430 431 432
    LPSHELLVIEW pShellView;
    HRESULT hr = E_INVALIDARG;

433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    TRACE("(%p)->(hwnd=%p,%s,%p)\n", This,
          hwndOwner, shdebugstr_guid (riid), ppvOut);

    if (!ppvOut)
        return hr;

    *ppvOut = NULL;

    if (IsEqualIID (riid, &IID_IDropTarget))
    {
        WARN ("IDropTarget not implemented\n");
        hr = E_NOTIMPL;
    }
    else if (IsEqualIID (riid, &IID_IContextMenu))
    {
        WARN ("IContextMenu not implemented\n");
        hr = E_NOTIMPL;
    }
    else if (IsEqualIID (riid, &IID_IShellView))
    {
        pShellView = IShellView_Constructor ((IShellFolder *) iface);
        if (pShellView)
        {
            hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
            IShellView_Release (pShellView);
        }
459 460 461 462 463 464 465 466
    }
    TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
    return hr;
}

/**************************************************************************
*  ISF_MyComputer_fnGetAttributesOf
*/
467 468
static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf (IShellFolder2 * iface,
                UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
469
{
470
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
471 472
    HRESULT hr = S_OK;

473
    TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
474
           This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
475

476 477 478
    if (!rgfInOut)
        return E_INVALIDARG;
    if (cidl && !apidl)
479
        return E_INVALIDARG;
480

481
    if (*rgfInOut == 0)
482
        *rgfInOut = ~0;
483 484 485 486 487
    
    if(cidl == 0){
        IShellFolder *psfParent = NULL;
        LPCITEMIDLIST rpidl = NULL;

488
        hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
489
        if(SUCCEEDED(hr)) {
490
            SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
491 492
            IShellFolder_Release(psfParent);
        }
493 494 495 496 497 498 499
    } else {
        while (cidl > 0 && *apidl) {
            pdump (*apidl);
            SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
            apidl++;
            cidl--;
        }
500
    }
501 502
    /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
    *rgfInOut &= ~SFGAO_VALIDATE;
503

504
    TRACE ("-- result=0x%08x\n", *rgfInOut);
505 506 507 508
    return hr;
}

/**************************************************************************
509
*    ISF_MyComputer_fnGetUIObjectOf
510 511
*
* PARAMETERS
512 513 514 515 516 517
*  hwndOwner [in]  Parent window for any output
*  cidl      [in]  array size
*  apidl     [in]  simple pidl array
*  riid      [in]  Requested Interface
*  prgfInOut [   ] reserved
*  ppvObject [out] Resulting Interface
518 519
*
*/
520 521 522
static HRESULT WINAPI ISF_MyComputer_fnGetUIObjectOf (IShellFolder2 * iface,
                HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
                UINT * prgfInOut, LPVOID * ppvOut)
523
{
524
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
525 526 527 528 529

    LPITEMIDLIST pidl;
    IUnknown *pObj = NULL;
    HRESULT hr = E_INVALIDARG;

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", This,
          hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);

    if (!ppvOut)
        return hr;

    *ppvOut = NULL;

    if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1))
    {
        pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
                                              This->pidlRoot, apidl, cidl);
        hr = S_OK;
    }
    else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
    {
        pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
                                              This->pidlRoot, apidl, cidl);
        hr = S_OK;
    }
    else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
    {
        pidl = ILCombine (This->pidlRoot, apidl[0]);
        pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
        SHFree (pidl);
        hr = S_OK;
    }
    else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
    {
        pidl = ILCombine (This->pidlRoot, apidl[0]);
        pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
        SHFree (pidl);
        hr = S_OK;
    }
    else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
    {
        hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
                                          (LPVOID *) &pObj);
    }
    else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
              IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
    {
        pidl = ILCombine (This->pidlRoot, apidl[0]);
        hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
        SHFree (pidl);
575
    }
576 577 578 579 580 581 582
    else 
        hr = E_NOINTERFACE;

    if (SUCCEEDED(hr) && !pObj)
        hr = E_OUTOFMEMORY;

    *ppvOut = pObj;
583
    TRACE ("(%p)->hr=0x%08x\n", This, hr);
584 585 586 587
    return hr;
}

/**************************************************************************
588
*    ISF_MyComputer_fnGetDisplayNameOf
589
*/
590 591
static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface,
               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 600 601
    pdump (pidl);

    if (!strRet)
602
        return E_INVALIDARG;
603

604 605 606 607 608
    pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
    if (!pszPath)
        return E_OUTOFMEMORY;

    pszPath[0] = 0;
609

610 611 612
    if (!pidl->mkid.cb)
    {
        /* parsing name like ::{...} */
613 614 615
        pszPath[0] = ':';
        pszPath[1] = ':';
        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 623 624 625 626
        {
            GUID const *clsid;

            clsid = _ILGetGUIDPointer (pidl);
            if (clsid)
            {
627
                if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
628
                {
629 630 631 632 633 634 635
                    static const WCHAR clsidW[] =
                     { 'C','L','S','I','D','\\',0 };
                    static const WCHAR shellfolderW[] =
                     { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
                    static const WCHAR wantsForParsingW[] =
                     { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
                     'g',0 };
636
                    int bWantsForParsing = FALSE;
637
                    WCHAR szRegPath[100];
638 639 640 641 642 643 644 645 646 647 648 649 650
                    LONG r;

                    /*
                     * We can only get a filesystem path from a shellfolder
                     * if the value WantsFORPARSING exists in
                     *      CLSID\\{...}\\shellfolder 
                     * exception: the MyComputer folder has this keys not
                     *            but like any filesystem backed
                     *            folder it needs these behaviour
                     *
                     * Get the "WantsFORPARSING" flag from the registry
                     */

651 652 653 654 655
                    lstrcpyW (szRegPath, clsidW);
                    SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
                    lstrcatW (szRegPath, shellfolderW);
                    r = SHGetValueW (HKEY_CLASSES_ROOT, szRegPath, 
                                     wantsForParsingW, NULL, NULL, NULL);
656 657 658 659 660 661 662 663 664 665 666
                    if (r == ERROR_SUCCESS)
                        bWantsForParsing = TRUE;

                    if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
                        bWantsForParsing)
                    {
                        /*
                         * We need the filesystem path to the destination folder
                         * Only the folder itself can know it
                         */
                        hr = SHELL32_GetDisplayNameOfChild (iface, pidl,
667
                                                dwFlags, pszPath, MAX_PATH);
668 669 670
                    }
                    else
                    {
671
                        LPWSTR p = pszPath;
672 673

                        /* parsing name like ::{...} */
674 675 676 677 678 679 680 681 682
                        p[0] = ':';
                        p[1] = ':';
                        p += 2;
                        p += SHELL32_GUIDToStringW(&CLSID_MyComputer, p);

                        /* \:: */
                        p[0] = '\\';
                        p[1] = ':';
                        p[2] = ':';
683
                        p += 3;
684
                        SHELL32_GUIDToStringW(clsid, p);
685 686 687 688 689
                    }
                }
                else
                {
                    /* user friendly name */
690
                    HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
691 692 693 694 695
                }
            }
            else
            {
                /* append my own path */
696
                _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);
697 698
            }
        }
699 700
        else if (_ILIsDrive(pidl))
        {        
701
            _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);    /* append my own path */
702

703 704 705 706
            /* long view "lw_name (C:)" */
            if (!(dwFlags & SHGDN_FORPARSING))
            {
                DWORD dwVolumeSerialNumber, dwMaximumComponetLength, dwFileSystemFlags;
707 708 709
                WCHAR wszDrive[18] = {0};
                static const WCHAR wszOpenBracket[] = {' ','(',0};
                static const WCHAR wszCloseBracket[] = {')',0};
710

711
                GetVolumeInformationW (pszPath, wszDrive,
712
                           sizeof(wszDrive)/sizeof(wszDrive[0]) - 6,
713 714
                           &dwVolumeSerialNumber,
                           &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 724
            /* Neither a shell namespace extension nor a drive letter. */
            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 736
    if (SUCCEEDED (hr))
    {
737 738 739 740 741 742 743 744 745 746 747 748 749 750
        /* Win9x always returns ANSI strings, NT always returns Unicode strings */
        if (GetVersion() & 0x80000000)
        {
            strRet->uType = STRRET_CSTR;
            if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
                    NULL, NULL))
                strRet->u.cStr[0] = '\0';
            CoTaskMemFree(pszPath);
        }
        else
        {
            strRet->uType = STRRET_WSTR;
            strRet->u.pOleStr = pszPath;
        }
751
    }
752 753
    else
        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 761 762 763 764
}

/**************************************************************************
*  ISF_MyComputer_fnSetNameOf
*  Changes the name of a file object or subfolder, possibly changing its item
*  identifier in the process.
*
* PARAMETERS
765 766 767 768 769
*  hwndOwner  [in]   Owner window for output
*  pidl       [in]   simple pidl of item to change
*  lpszName   [in]   the items new display name
*  dwFlags    [in]   SHGNO formatting flags
*  ppidlOut   [out]  simple pidl returned
770
*/
771 772 773
static HRESULT WINAPI ISF_MyComputer_fnSetNameOf (
               IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl,
               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 779 780
    return E_FAIL;
}

781 782
static HRESULT WINAPI ISF_MyComputer_fnGetDefaultSearchGUID (
               IShellFolder2 * iface, GUID * pguid)
783
{
784
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
785 786 787
    FIXME ("(%p)\n", This);
    return E_NOTIMPL;
}
788 789
static HRESULT WINAPI ISF_MyComputer_fnEnumSearches (
               IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
790
{
791
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
792 793 794
    FIXME ("(%p)\n", This);
    return E_NOTIMPL;
}
795 796
static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumn (
               IShellFolder2 *iface, DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
797
{
798
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
799 800 801

    TRACE ("(%p)\n", This);

802 803 804 805
    if (pSort)
         *pSort = 0;
    if (pDisplay)
        *pDisplay = 0;
806 807
    return S_OK;
}
808 809
static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumnState (
               IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
810
{
811
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
812 813 814

    TRACE ("(%p)\n", This);

815 816
    if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
        return E_INVALIDARG;
817 818 819
    *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
    return S_OK;
}
820 821 822

static HRESULT WINAPI ISF_MyComputer_fnGetDetailsEx (IShellFolder2 * iface,
               LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
823
{
824
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
825 826 827 828 829
    FIXME ("(%p)\n", This);
    return E_NOTIMPL;
}

/* FIXME: drive size >4GB is rolling over */
830 831
static HRESULT WINAPI ISF_MyComputer_fnGetDetailsOf (IShellFolder2 * iface,
               LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
832
{
833
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
834 835 836 837 838
    HRESULT hr;

    TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);

    if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
        return E_INVALIDARG;

    if (!pidl)
    {
        psd->fmt = MyComputerSFHeader[iColumn].fmt;
        psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
        psd->str.uType = STRRET_CSTR;
        LoadStringA (shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
                     psd->str.u.cStr, MAX_PATH);
        return S_OK;
    }
    else
    {
        char szPath[MAX_PATH];
        ULARGE_INTEGER ulBytes;

        psd->str.u.cStr[0] = 0x00;
        psd->str.uType = STRRET_CSTR;
        switch (iColumn)
        {
        case 0:        /* name */
            hr = IShellFolder_GetDisplayNameOf (iface, pidl,
                       SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
            break;
        case 1:        /* type */
            _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
            break;
        case 2:        /* total size */
            if (_ILIsDrive (pidl))
            {
                _ILSimpleGetText (pidl, szPath, MAX_PATH);
                GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
                StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
            }
            break;
        case 3:        /* free size */
            if (_ILIsDrive (pidl))
            {
                _ILSimpleGetText (pidl, szPath, MAX_PATH);
                GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
                StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
            }
            break;
        }
        hr = S_OK;
884 885 886 887
    }

    return hr;
}
888 889 890

static HRESULT WINAPI ISF_MyComputer_fnMapColumnToSCID (
               IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
891
{
892
    IGenericSFImpl *This = (IGenericSFImpl *)iface;
893 894 895 896
    FIXME ("(%p)\n", This);
    return E_NOTIMPL;
}

897
static const IShellFolder2Vtbl vt_ShellFolder2 =
898
{
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
    ISF_MyComputer_fnQueryInterface,
    ISF_MyComputer_fnAddRef,
    ISF_MyComputer_fnRelease,
    ISF_MyComputer_fnParseDisplayName,
    ISF_MyComputer_fnEnumObjects,
    ISF_MyComputer_fnBindToObject,
    ISF_MyComputer_fnBindToStorage,
    ISF_MyComputer_fnCompareIDs,
    ISF_MyComputer_fnCreateViewObject,
    ISF_MyComputer_fnGetAttributesOf,
    ISF_MyComputer_fnGetUIObjectOf,
    ISF_MyComputer_fnGetDisplayNameOf,
    ISF_MyComputer_fnSetNameOf,
    /* ShellFolder2 */
    ISF_MyComputer_fnGetDefaultSearchGUID,
    ISF_MyComputer_fnEnumSearches,
    ISF_MyComputer_fnGetDefaultColumn,
    ISF_MyComputer_fnGetDefaultColumnState,
    ISF_MyComputer_fnGetDetailsEx,
    ISF_MyComputer_fnGetDetailsOf,
    ISF_MyComputer_fnMapColumnToSCID
920 921 922
};

/************************************************************************
923
 *    IMCFldr_PersistFolder2_QueryInterface
924
 */
925 926
static HRESULT WINAPI IMCFldr_PersistFolder2_QueryInterface (
               IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObj)
927
{
928
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
929 930 931 932 933 934 935

    TRACE ("(%p)\n", This);

    return IUnknown_QueryInterface (_IUnknown_ (This), iid, ppvObj);
}

/************************************************************************
936
 *    IMCFldr_PersistFolder2_AddRef
937 938 939
 */
static ULONG WINAPI IMCFldr_PersistFolder2_AddRef (IPersistFolder2 * iface)
{
940
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
941

942
    TRACE ("(%p)->(count=%u)\n", This, This->ref);
943 944 945 946 947

    return IUnknown_AddRef (_IUnknown_ (This));
}

/************************************************************************
948
 *    ISFPersistFolder_Release
949 950 951
 */
static ULONG WINAPI IMCFldr_PersistFolder2_Release (IPersistFolder2 * iface)
{
952
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
953

954
    TRACE ("(%p)->(count=%u)\n", This, This->ref);
955 956 957 958 959

    return IUnknown_Release (_IUnknown_ (This));
}

/************************************************************************
960
 *    IMCFldr_PersistFolder2_GetClassID
961
 */
962 963
static HRESULT WINAPI IMCFldr_PersistFolder2_GetClassID (
               IPersistFolder2 * iface, CLSID * lpClassId)
964
{
965
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
966 967 968 969

    TRACE ("(%p)\n", This);

    if (!lpClassId)
970
    return E_POINTER;
971 972 973 974 975 976
    *lpClassId = CLSID_MyComputer;

    return S_OK;
}

/************************************************************************
977
 *    IMCFldr_PersistFolder2_Initialize
978 979 980
 *
 * NOTES: it makes no sense to change the pidl
 */
981 982
static HRESULT WINAPI IMCFldr_PersistFolder2_Initialize (
               IPersistFolder2 * iface, LPCITEMIDLIST pidl)
983
{
984
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
985 986 987 988 989
    TRACE ("(%p)->(%p)\n", This, pidl);
    return E_NOTIMPL;
}

/**************************************************************************
990
 *    IPersistFolder2_fnGetCurFolder
991
 */
992 993
static HRESULT WINAPI IMCFldr_PersistFolder2_GetCurFolder (
               IPersistFolder2 * iface, LPITEMIDLIST * pidl)
994
{
995
    IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
996 997 998 999

    TRACE ("(%p)->(%p)\n", This, pidl);

    if (!pidl)
1000
        return E_POINTER;
1001 1002 1003 1004
    *pidl = ILClone (This->pidlRoot);
    return S_OK;
}

1005
static const IPersistFolder2Vtbl vt_PersistFolder2 =
1006
{
1007 1008 1009 1010 1011 1012
    IMCFldr_PersistFolder2_QueryInterface,
    IMCFldr_PersistFolder2_AddRef,
    IMCFldr_PersistFolder2_Release,
    IMCFldr_PersistFolder2_GetClassID,
    IMCFldr_PersistFolder2_Initialize,
    IMCFldr_PersistFolder2_GetCurFolder
1013
};