Sync to Wine-0_9_3:
[reactos.git] / reactos / lib / shell32 / shfldr_desktop.c
index 5e8b13d..74f7200 100644 (file)
@@ -60,16 +60,14 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell);
 */
 
 typedef struct {
-    IShellFolder2Vtbl *lpVtbl;
-    DWORD ref;
+    const IShellFolder2Vtbl *lpVtbl;
+    LONG ref;
 
     CLSID *pclsid;
 
     /* both paths are parsible from the desktop */
-    LPSTR sPathTarget;        /* complete path to target used for enumeration and ChangeNotify */
-    LPITEMIDLIST pidlRoot;    /* absolute pidl */
-
-    int dwAttributes;        /* attributes returned by GetAttributesOf FIXME: use it */
+    LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
+    LPITEMIDLIST pidlRoot;  /* absolute pidl */
 
     UINT cfShellIDList;        /* clipboardformat for IDropTarget */
     BOOL fAcceptFmt;        /* flag for pending Drop */
@@ -78,8 +76,6 @@ typedef struct {
 #define _IUnknown_(This)    (IShellFolder*)&(This->lpVtbl)
 #define _IShellFolder_(This)    (IShellFolder*)&(This->lpVtbl)
 
-static struct IShellFolder2Vtbl vt_MCFldr_ShellFolder2;
-
 static shvheader DesktopSFHeader[] = {
     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
     {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
@@ -90,45 +86,6 @@ static shvheader DesktopSFHeader[] = {
 
 #define DESKTOPSHELLVIEWCOLUMNS 5
 
-/**************************************************************************
- *    ISF_Desktop_Constructor
- */
-HRESULT WINAPI ISF_Desktop_Constructor (
-                IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
-{
-    IGenericSFImpl *sf;
-    char szMyPath[MAX_PATH];
-
-    TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
-
-    if (!ppv)
-        return E_POINTER;
-    if (pUnkOuter)
-        return CLASS_E_NOAGGREGATION;
-
-    if (!SHGetSpecialFolderPathA (0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE))
-        return E_UNEXPECTED;
-
-    sf = (IGenericSFImpl *) LocalAlloc (GMEM_ZEROINIT, sizeof (IGenericSFImpl));
-    if (!sf)
-        return E_OUTOFMEMORY;
-
-    sf->ref = 0;
-    sf->lpVtbl = &vt_MCFldr_ShellFolder2;
-    sf->pidlRoot = _ILCreateDesktop ();    /* my qualified pidl */
-    sf->sPathTarget = SHAlloc (strlen (szMyPath) + 1);
-    lstrcpyA (sf->sPathTarget, szMyPath);
-
-    if (!SUCCEEDED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv)))
-    {
-        IUnknown_Release (_IUnknown_ (sf));
-        return E_NOINTERFACE;
-    }
-
-    TRACE ("--(%p)\n", sf);
-    return S_OK;
-}
-
 /**************************************************************************
  *    ISF_Desktop_fnQueryInterface
  *
@@ -253,13 +210,11 @@ static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
             LPWSTR pathPtr;
 
             /* build a complete path to create a simple pidl */
-            MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szPath,
-             sizeof(szPath) / sizeof(szPath[0]));
+            lstrcpynW(szPath, This->sPathTarget, MAX_PATH);
             pathPtr = PathAddBackslashW(szPath);
             if (pathPtr)
             {
-                lstrcpynW(pathPtr, lpszDisplayName,
-                          sizeof(szPath)/sizeof(szPath[0]) - (pathPtr - szPath));
+                lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
                 hr = _ILCreateFromPathW(szPath, &pidlTemp);
             }
             else
@@ -310,42 +265,43 @@ static BOOL CreateDesktopEnumList(IEnumIDList *list, DWORD dwFlags)
     BOOL ret = TRUE;
     WCHAR szPath[MAX_PATH];
 
-    TRACE("(%p)->(flags=0x%08lx) \n",list,dwFlags);
+    TRACE("(%p)->(flags=0x%08lx)\n", list, dwFlags);
 
     /* enumerate the root folders */
     if (dwFlags & SHCONTF_FOLDERS)
     {
         HKEY hkey;
-        LONG r;
+        UINT i;
 
         /* create the pidl for This item */
         ret = AddToEnumList(list, _ILCreateMyComputer());
 
-        r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW,
-                          0, KEY_READ, &hkey);
-        if (ret && ERROR_SUCCESS == r)
-        {
-            WCHAR iid[50];
-            int i=0;
-            BOOL moreKeys = TRUE;
-
-            while (ret && moreKeys)
+        for (i=0; i<2; i++) {
+            if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+                                      Desktop_NameSpaceW, 0, KEY_READ, &hkey))
             {
-                DWORD size;
+                WCHAR iid[50];
+                int i=0;
 
-                size = sizeof (iid);
-                r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
-                if (ERROR_SUCCESS == r)
+                while (ret)
                 {
-                    ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
-                    i++;
+                    DWORD size;
+                    LONG r;
+
+                    size = sizeof (iid);
+                    r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
+                    if (ERROR_SUCCESS == r)
+                    {
+                        ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
+                        i++;
+                    }
+                    else if (ERROR_NO_MORE_ITEMS == r)
+                        break;
+                    else
+                        ret = FALSE;
                 }
-                else if (ERROR_NO_MORE_ITEMS == r)
-                    moreKeys = FALSE;
-                else
-                    ret = FALSE;
+                RegCloseKey(hkey);
             }
-            RegCloseKey(hkey);
         }
     }
 
@@ -387,7 +343,7 @@ static HRESULT WINAPI ISF_Desktop_fnBindToObject (IShellFolder2 * iface,
     TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
            This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
 
-    return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid, ppvOut);
+    return SHELL32_BindToChild( This->pidlRoot, This->sPathTarget, pidl, riid, ppvOut );
 }
 
 /**************************************************************************
@@ -469,23 +425,42 @@ static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf (IShellFolder2 * iface,
 {
     IGenericSFImpl *This = (IGenericSFImpl *)iface;
     HRESULT hr = S_OK;
+    static const DWORD dwDesktopAttributes = 
+        SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
+        SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
+    static const DWORD dwMyComputerAttributes = 
+        SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
+        SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
 
-    TRACE ("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",
-           This, cidl, apidl, *rgfInOut);
+    TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n",
+           This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
 
-    if (!cidl || !apidl || !rgfInOut)
+    if (!rgfInOut)
+        return E_INVALIDARG;
+    if (cidl && !apidl)
         return E_INVALIDARG;
 
     if (*rgfInOut == 0)
         *rgfInOut = ~0;
-
-    while (cidl > 0 && *apidl)
-    {
-        pdump (*apidl);
-        SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
-        apidl++;
-        cidl--;
+    
+    if(cidl == 0) {
+        *rgfInOut &= dwDesktopAttributes; 
+    } else {
+        while (cidl > 0 && *apidl) {
+            pdump (*apidl);
+            if (_ILIsDesktop(*apidl)) { 
+                *rgfInOut &= dwDesktopAttributes;
+            } else if (_ILIsMyComputer(*apidl)) {
+                *rgfInOut &= dwMyComputerAttributes;
+            } else {
+                SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
+            }
+            apidl++;
+            cidl--;
+        }
     }
+    /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+    *rgfInOut &= ~SFGAO_VALIDATE;
 
     TRACE ("-- result=0x%08lx\n", *rgfInOut);
 
@@ -520,20 +495,9 @@ static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
     if (!ppvOut)
         return hr;
 
-    if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
-    {
-        pObj = (LPUNKNOWN) IDataObject_Constructor( hwndOwner,
-                                                  This->pidlRoot, apidl, cidl);
-        hr = S_OK;
-    }
-    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);
-    }
-    else if (IsEqualIID (riid, &IID_IContextMenu))
+    *ppvOut = NULL;
+
+    if (IsEqualIID (riid, &IID_IContextMenu))
     {
         if (cidl > 0)
             pObj = (LPUNKNOWN) ISvItemCm_Constructor( (IShellFolder *) iface, This->pidlRoot, apidl, cidl);
@@ -541,6 +505,12 @@ static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
             pObj = (LPUNKNOWN) ISvBgCm_Constructor( (IShellFolder *) iface, TRUE);
         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]);
@@ -560,6 +530,13 @@ static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
         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);
+    }
     else
         hr = E_NOINTERFACE;
 
@@ -581,33 +558,49 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
                 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
 {
     IGenericSFImpl *This = (IGenericSFImpl *)iface;
-    CHAR szPath[MAX_PATH];
-    GUID const *clsid;
     HRESULT hr = S_OK;
 
-    *szPath = '\0';
-
     TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
     pdump (pidl);
 
     if (!strRet)
         return E_INVALIDARG;
 
+    strRet->uType = STRRET_CSTR;
     if (_ILIsDesktop (pidl))
     {
         if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
-            (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING))
+            (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
         {
-            lstrcpyA (szPath, This->sPathTarget);
+            BOOL defCharUsed;
+
+            WideCharToMultiByte( CP_ACP, 0, This->sPathTarget, -1,
+                                 strRet->u.cStr, MAX_PATH, NULL, &defCharUsed );
+            if (defCharUsed)
+            {
+                strRet->u.pOleStr = SHAlloc((lstrlenW(This->sPathTarget)+1) *
+                 sizeof(WCHAR));
+                if (!strRet->u.pOleStr)
+                    hr = E_OUTOFMEMORY;
+                else
+                {
+                    strcpyW(strRet->u.pOleStr, This->sPathTarget);
+                    strRet->uType = STRRET_WSTR;
+                }
+            }
         }
         else
-            HCR_GetClassNameA(&CLSID_ShellDesktop, szPath, MAX_PATH);
+        {
+            HCR_GetClassNameA(&CLSID_ShellDesktop, strRet->u.cStr, MAX_PATH);
+        }
     }
     else if (_ILIsPidlSimple (pidl))
     {
+        GUID const *clsid;
+
         if ((clsid = _ILGetGUIDPointer (pidl)))
         {
-            if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
+            if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
             {
                 int bWantsForParsing;
 
@@ -620,7 +613,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
                  */
                 if (IsEqualIID (clsid, &CLSID_MyComputer))
                 {
-                    bWantsForParsing = 1;
+                    bWantsForParsing = TRUE;
                 }
                 else
                 {
@@ -654,43 +647,52 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
                      * Only the folder itself can know it
                      */
                     hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
-                                                        szPath, MAX_PATH);
+                                                        strRet->u.cStr,
+                                                        MAX_PATH);
                 }
                 else
                 {
                     /* parsing name like ::{...} */
-                    lstrcpyA (szPath, "::");
-                    SHELL32_GUIDToStringA (clsid, &szPath[2]);
+                    lstrcpyA (strRet->u.cStr, "::");
+                    SHELL32_GUIDToStringA (clsid, &strRet->u.cStr[2]);
                 }
             }
             else
             {
                 /* user friendly name */
-                HCR_GetClassNameA (clsid, szPath, MAX_PATH);
+                HCR_GetClassNameA (clsid, strRet->u.cStr, MAX_PATH);
             }
         }
         else
         {
-            /* file system folder */
-            _ILSimpleGetText (pidl, szPath, MAX_PATH);
+            int cLen = 0;
+                
+            /* file system folder or file rooted at the desktop */
+            if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
+                (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
+            {
+                WideCharToMultiByte(CP_ACP, 0, This->sPathTarget, -1, strRet->u.cStr, MAX_PATH,
+                                    NULL, NULL);
+                PathAddBackslashA(strRet->u.cStr);
+                cLen = lstrlenA(strRet->u.cStr);
+            }
+    
+            _ILSimpleGetText (pidl, strRet->u.cStr + cLen, MAX_PATH - cLen);
 
             if (!_ILIsFolder(pidl))
-            SHELL_FS_ProcessDisplayFilename(szPath, dwFlags);
+                SHELL_FS_ProcessDisplayFilename(strRet->u.cStr, dwFlags);
         }
     }
     else
     {
         /* a complex pidl, let the subfolder do the work */
-        hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags, szPath, MAX_PATH);
+        hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
+         strRet->u.cStr, MAX_PATH);
     }
 
-    if (SUCCEEDED (hr))
-    {
-        strRet->uType = STRRET_CSTR;
-        lstrcpynA (strRet->u.cStr, szPath, MAX_PATH);
-    }
-
-    TRACE ("-- (%p)->(%s,0x%08lx)\n", This, szPath, hr);
+    TRACE ("-- (%p)->(%s,0x%08lx)\n", This,
+     strRet->uType == STRRET_CSTR ? strRet->u.cStr :
+     debugstr_w(strRet->u.pOleStr), hr);
     return hr;
 }
 
@@ -778,7 +780,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
 {
     IGenericSFImpl *This = (IGenericSFImpl *)iface;
 
-    HRESULT hr = E_FAIL;
+    HRESULT hr = S_OK;
 
     TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
 
@@ -796,6 +798,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
     }
 
     /* the data from the pidl */
+    psd->str.uType = STRRET_CSTR;
     switch (iColumn)
     {
     case 0:        /* name */
@@ -815,8 +818,6 @@ static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
         _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
         break;
     }
-    hr = S_OK;
-    psd->str.uType = STRRET_CSTR;
 
     return hr;
 }
@@ -829,7 +830,7 @@ static HRESULT WINAPI ISF_Desktop_fnMapColumnToSCID (
     return E_NOTIMPL;
 }
 
-static IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
+static const IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
 {
     ISF_Desktop_fnQueryInterface,
     ISF_Desktop_fnAddRef,
@@ -853,3 +854,44 @@ static IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
     ISF_Desktop_fnGetDetailsOf,
     ISF_Desktop_fnMapColumnToSCID
 };
+
+/**************************************************************************
+ *    ISF_Desktop_Constructor
+ */
+HRESULT WINAPI ISF_Desktop_Constructor (
+                IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
+{
+    IGenericSFImpl *sf;
+    WCHAR szMyPath[MAX_PATH];
+    HRESULT r;
+
+    TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
+
+    if (!ppv)
+        return E_POINTER;
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
+        return E_UNEXPECTED;
+
+    sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
+    if (!sf)
+        return E_OUTOFMEMORY;
+
+    sf->ref = 0;
+    sf->lpVtbl = &vt_MCFldr_ShellFolder2;
+    sf->pidlRoot = _ILCreateDesktop();    /* my qualified pidl */
+    sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
+    lstrcpyW( sf->sPathTarget, szMyPath );
+
+    r = IUnknown_QueryInterface( _IUnknown_(sf), riid, ppv );
+    if (!SUCCEEDED (r))
+    {
+        IUnknown_Release( _IUnknown_(sf) );
+        return r;
+    }
+
+    TRACE ("--(%p)\n", sf);
+    return S_OK;
+}