[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shlfolder.cpp
index b205c03..57dc15f 100644 (file)
@@ -149,7 +149,7 @@ HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc,
  *   In this case the absolute path is built from pidlChild (eg. C:)
  */
 static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
-                LPCITEMIDLIST pidlChild, REFCLSID clsid, LPVOID * ppvOut)
+                LPCITEMIDLIST pidlChild, REFCLSID clsid, IShellFolder** ppsfOut)
 {
     HRESULT hr;
     CComPtr<IShellFolder> pShellFolder;
@@ -163,8 +163,7 @@ static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
         CComPtr<IPersistFolder> ppf;
         CComPtr<IPersistFolder3> ppf3;
 
-        if ((_ILIsFolder(pidlChild) || _ILIsDrive(pidlChild)) &&
-            SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3))))
+        if (SUCCEEDED(pShellFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3))))
         {
             PERSIST_FOLDER_TARGET_INFO ppfti;
 
@@ -198,15 +197,35 @@ static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
         ILFree (pidlAbsolute);
     }
 
-    *ppvOut = pShellFolder.Detach();
+    *ppsfOut = pShellFolder.Detach();
 
-    TRACE ("-- (%p) ret=0x%08x\n", *ppvOut, hr);
+    TRACE ("-- (%p) ret=0x%08x\n", *ppsfOut, hr);
 
     return hr;
 }
 
+void SHELL32_GetCLSIDForDirectory(LPCWSTR pathRoot, LPCITEMIDLIST pidl, CLSID* pclsidFolder)
+{
+    static const WCHAR wszDotShellClassInfo[] = {
+        '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0 };
+    static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
+    WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath;
+
+    /* see if folder CLSID should be overridden by desktop.ini file */
+    if (pathRoot) {
+        lstrcpynW(wszFolderPath, pathRoot, MAX_PATH);
+        pwszPathTail = PathAddBackslashW(wszFolderPath);
+    }
+
+    _ILSimpleGetTextW(pidl,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath));
+
+    if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath,
+        wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID))
+        CLSIDFromString (wszCLSIDValue, pclsidFolder);
+}
+
 /***********************************************************************
- *    SHELL32_BindToChild [Internal]
+ *    SHELL32_BindToFS [Internal]
  *
  * Common code for IShellFolder_BindToObject.
  *
@@ -222,49 +241,40 @@ static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot,
  *  This function makes special assumptions on the shell namespace, which
  *  means you probably can't use it for your IShellFolder implementation.
  */
-HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot,
+HRESULT SHELL32_BindToFS (LPCITEMIDLIST pidlRoot,
                              LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut)
 {
-    static const WCHAR wszDotShellClassInfo[] = {
-        '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0 };
-
-    GUID const *clsid;
     CComPtr<IShellFolder> pSF;
     HRESULT hr;
-    LPITEMIDLIST pidlChild;
+    LPCITEMIDLIST pidlChild;
 
     if (!pidlRoot || !ppvOut || !pidlComplete || !pidlComplete->mkid.cb)
         return E_INVALIDARG;
 
+    if (_ILIsValue(pidlComplete))
+    {
+        ERR("Binding to file is unimplemented\n");
+        return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    }
+    if (!_ILIsFolder(pidlComplete) && !_ILIsDrive(pidlComplete))
+    {
+        ERR("Got an unknown type of pidl!\n");
+        return E_FAIL;
+    }
+
     *ppvOut = NULL;
 
-    pidlChild = ILCloneFirst (pidlComplete);
-
-    if ((clsid = _ILGetGUIDPointer (pidlChild))) {
-        /* virtual folder */
-        hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, *clsid, (LPVOID *)&pSF);
-    } else {
-        /* file system folder */
-        CLSID clsidFolder = CLSID_ShellFSFolder;
-        static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
-        WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath;
-
-        /* see if folder CLSID should be overridden by desktop.ini file */
-        if (pathRoot) {
-            lstrcpynW(wszFolderPath, pathRoot, MAX_PATH);
-            pwszPathTail = PathAddBackslashW(wszFolderPath);
-        }
+    pidlChild = (_ILIsPidlSimple (pidlComplete)) ? pidlComplete : ILCloneFirst (pidlComplete);
 
-        _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath));
+    CLSID clsidFolder = CLSID_ShellFSFolder;
+    DWORD attributes = _ILGetFileAttributes(ILFindLastID(pidlChild), NULL, 0);
+    if ((attributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)) != 0)
+        SHELL32_GetCLSIDForDirectory(pathRoot, pidlChild, &clsidFolder);
 
-        if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath,
-            wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID))
-            CLSIDFromString (wszCLSIDValue, &clsidFolder);
+    hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, clsidFolder, &pSF);
 
-        hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild,
-                                     clsidFolder, (LPVOID *)&pSF);
-    }
-    ILFree (pidlChild);
+    if (pidlChild != pidlComplete)
+        ILFree ((LPITEMIDLIST)pidlChild);
 
     if (SUCCEEDED (hr)) {
         if (_ILIsPidlSimple (pidlComplete)) {
@@ -290,27 +300,41 @@ HRESULT SHELL32_BindToGuidItem(LPCITEMIDLIST pidlRoot,
     CComPtr<IPersistFolder> pFolder;
     HRESULT hr;
 
+    if (!pidlRoot || !ppvOut || !pidl || !pidl->mkid.cb)
+        return E_INVALIDARG;
+
+    *ppvOut = NULL;
+
     GUID *pGUID = _ILGetGUIDPointer(pidl);
     if (!pGUID)
     {
         ERR("SHELL32_BindToGuidItem called for non guid item!\n");
-        return E_FAIL;
+        return E_INVALIDARG;
     }
 
     hr = SHCoCreateInstance(NULL, pGUID, NULL, IID_PPV_ARG(IPersistFolder, &pFolder));
     if (FAILED(hr))
         return hr;
 
-    hr = pFolder->Initialize(ILCombine(pidlRoot, pidl));
-    if (FAILED(hr))
-        return hr;
-
     if (_ILIsPidlSimple (pidl))
     {
+        hr = pFolder->Initialize(ILCombine(pidlRoot, pidl));
+        if (FAILED(hr))
+            return hr;
+
         return pFolder->QueryInterface(riid, ppvOut);
     }
     else
     {
+        LPITEMIDLIST pidlChild = ILCloneFirst (pidl);
+        if (!pidlChild)
+            return E_OUTOFMEMORY;
+
+        hr = pFolder->Initialize(ILCombine(pidlRoot, pidlChild));
+        ILFree(pidlChild);
+        if (FAILED(hr))
+            return hr;
+
         CComPtr<IShellFolder> psf;
         hr = pFolder->QueryInterface(IID_PPV_ARG(IShellFolder, &psf));
         if (FAILED(hr))
@@ -335,56 +359,47 @@ HRESULT SHELL32_BindToGuidItem(LPCITEMIDLIST pidlRoot,
  * virtual folders with the registry key WantsFORPARSING set.
  */
 HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf,
-                       LPCITEMIDLIST pidl, DWORD dwFlags, LPWSTR szOut, DWORD dwOutLen)
+                       LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
 {
-    LPITEMIDLIST pidlFirst;
-    HRESULT hr = E_INVALIDARG;
-
-    TRACE ("(%p)->(pidl=%p 0x%08x %p 0x%08x)\n", psf, pidl, dwFlags, szOut, dwOutLen);
-    pdump (pidl);
+    LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
+    if (!pidlFirst)
+        return E_OUTOFMEMORY;
 
-    pidlFirst = ILCloneFirst(pidl);
-    if (pidlFirst)
+    CComPtr<IShellFolder> psfChild;
+    HRESULT hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+    if (SUCCEEDED (hr))
     {
-        CComPtr<IShellFolder> psfChild;
-
-        hr = psf->BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
-        if (SUCCEEDED (hr))
-        {
-            STRRET strTemp;
-            LPITEMIDLIST pidlNext = ILGetNext (pidl);
+        hr = psfChild->GetDisplayNameOf(ILGetNext (pidl), dwFlags, strRet);
+    }
+    ILFree (pidlFirst);
 
-            hr = psfChild->GetDisplayNameOf(pidlNext, dwFlags, &strTemp);
-            if (SUCCEEDED (hr))
-            {
-                if(!StrRetToStrNW (szOut, dwOutLen, &strTemp, pidlNext))
-                    hr = E_FAIL;
-            }
-        }
-        ILFree (pidlFirst);
-    } else
-        hr = E_OUTOFMEMORY;
+    return hr;
+}
 
-    TRACE ("-- ret=0x%08x %s\n", hr, debugstr_w(szOut));
+HRESULT HCR_GetClassName(REFIID riid, LPSTRRET strRet)
+{
+    BOOL bRet;
+    WCHAR wstrName[MAX_PATH+1];
+    bRet = HCR_GetClassNameW(CLSID_MyDocuments, wstrName, MAX_PATH);
+    if (!bRet)
+        return E_FAIL;
 
-    return hr;
+    return SHSetStrRet(strRet, wstrName);
 }
 
 HRESULT SHELL32_GetDisplayNameOfGUIDItem(IShellFolder2* psf, LPCWSTR pszFolderPath, PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
 {
-    HRESULT hr = S_OK;
+    HRESULT hr;
     GUID const *clsid = _ILGetGUIDPointer (pidl);
 
     if (!strRet)
         return E_INVALIDARG;
 
-    LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
-    if (!pszPath)
-        return E_OUTOFMEMORY;
-
-    if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
+    /* First of all check if we need to query the name from the child item */
+    if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING && 
+        GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL)
     {
-        int bWantsForParsing;
+        int bWantsForParsing = FALSE;
 
         /*
             * We can only get a filesystem path from a shellfolder if the
@@ -408,32 +423,38 @@ HRESULT SHELL32_GetDisplayNameOfGUIDItem(IShellFolder2* psf, LPCWSTR pszFolderPa
             }
         }
 
-        if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
-                bWantsForParsing)
+        if (bWantsForParsing)
         {
             /*
-                * we need the filesystem path to the destination folder.
-                * Only the folder itself can know it
-                */
-            hr = SHELL32_GetDisplayNameOfChild (psf, pidl, dwFlags,
-                                                pszPath,
-                                                MAX_PATH);
+             * we need the filesystem path to the destination folder.
+             * Only the folder itself can know it
+             */
+            return SHELL32_GetDisplayNameOfChild (psf, pidl, dwFlags, strRet);
         }
-        else
-        {
-            wcscpy(pszPath, pszFolderPath);
-            PWCHAR pItemName = &pszPath[wcslen(pszPath)];
+    }
 
-            /* parsing name like ::{...} */
-            pItemName[0] = ':';
-            pItemName[1] = ':';
-            SHELL32_GUIDToStringW (*clsid, &pItemName[2]);
-        }
+    /* Allocate the buffer for the result */
+    LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+    if (!pszPath)
+        return E_OUTOFMEMORY;
+
+    hr = S_OK;
+
+    if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
+    {
+        wcscpy(pszPath, pszFolderPath);
+        PWCHAR pItemName = &pszPath[wcslen(pszPath)];
+
+        /* parsing name like ::{...} */
+        pItemName[0] = ':';
+        pItemName[1] = ':';
+        SHELL32_GUIDToStringW (*clsid, &pItemName[2]);
     }
     else
     {
         /* user friendly name */
-        HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
+        if (!HCR_GetClassNameW (*clsid, pszPath, MAX_PATH))
+            hr = E_FAIL;
     }
 
     if (SUCCEEDED(hr))
@@ -588,106 +609,151 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW
     return S_OK;
 }
 
-HRESULT SHELL32_GetItemAttributes (IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
+HRESULT SHELL32_CompareDetails(IShellFolder2* isf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
 {
-    TRACE ("0x%08x\n", *pdwAttributes);
+    SHELLDETAILS sd;
+    WCHAR wszItem1[MAX_PATH], wszItem2[MAX_PATH];
 
-    if (*pdwAttributes & ~dwSupportedAttr)
+    isf->GetDetailsOf(pidl1, lParam, &sd);
+    StrRetToBufW(&sd.str, pidl1, wszItem1, MAX_PATH);
+    isf->GetDetailsOf(pidl2, lParam, &sd);
+    StrRetToBufW(&sd.str, pidl2, wszItem2, MAX_PATH);
+    int ret = wcsicmp(wszItem1, wszItem2);
+
+    return MAKE_COMPARE_HRESULT(ret);
+}
+
+HRESULT SHELL32_CompareGuidItems(IShellFolder2* isf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+{
+    if (pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0)
     {
-        WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes & ~dwSupportedAttr));
-        *pdwAttributes &= dwSupportedAttr;
+        ERR("Got an empty pidl!\n");
+        return E_INVALIDARG;
     }
 
-    if (_ILIsSpecialFolder(pidl))
+    BOOL bIsGuidFolder1 = _ILIsSpecialFolder(pidl1);
+    BOOL bIsGuidFolder2 = _ILIsSpecialFolder(pidl2);
+
+    if (!bIsGuidFolder1 && !bIsGuidFolder2)
     {
-        return SHELL32_GetGuidItemAttributes(psf, pidl, pdwAttributes);
+        ERR("Got no guid pidl!\n");
+        return E_INVALIDARG;
     }
-    else if(_ILIsFolder(pidl) || _ILIsValue(pidl))
+    else if (bIsGuidFolder1 && bIsGuidFolder2)
     {
-        return SHELL32_GetFSItemAttributes(psf, pidl, pdwAttributes);
+        return SHELL32_CompareDetails(isf, lParam, pidl1, pidl2);
+    }
+
+    /* Guid folders come first compared to everything else */
+    return MAKE_COMPARE_HRESULT(bIsGuidFolder1 ? -1 : 1);
+}
+
+HRESULT SH_ParseGuidDisplayName(IShellFolder2 * pFolder,
+                                HWND hwndOwner,
+                                LPBC pbc,
+                                LPOLESTR lpszDisplayName,
+                                DWORD *pchEaten,
+                                PIDLIST_RELATIVE *ppidl,
+                                DWORD *pdwAttributes)
+{
+    LPITEMIDLIST pidl;
+
+    if (!lpszDisplayName || !ppidl)
+        return E_INVALIDARG;
+
+    *ppidl = 0;
+
+    if (pchEaten)
+        *pchEaten = 0;
+
+    UINT cch = wcslen(lpszDisplayName);
+    if (cch < 39 || lpszDisplayName[0] != L':' || lpszDisplayName[1] != L':')
+        return E_FAIL;
+
+    pidl = _ILCreateGuidFromStrW(lpszDisplayName + 2);
+    if (pidl == NULL)
+        return E_FAIL;
+
+    if (cch < 41)
+    {
+        *ppidl = pidl;
+        if (pdwAttributes && *pdwAttributes)
+        {
+            SHELL32_GetGuidItemAttributes(pFolder, *ppidl, pdwAttributes);
+        }
     }
     else
     {
-        /* Set common attributes */
-        ERR("We got a pidl that is neither a guid or an FS item!!! Type=0x%x\n",pidl->mkid.abID[0]);
-        *pdwAttributes &= SFGAO_CANLINK;
+        HRESULT hr = SHELL32_ParseNextElement(pFolder, hwndOwner, pbc, &pidl, lpszDisplayName + 41, pchEaten, pdwAttributes);
+        if (SUCCEEDED(hr))
+        {
+            *ppidl = pidl;
+        }
+        return hr;
     }
 
-    TRACE ("-- 0x%08x\n", *pdwAttributes);
     return S_OK;
 }
 
-/***********************************************************************
- *  SHELL32_CompareIDs
- */
-HRESULT SHELL32_CompareIDs(IShellFolder * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+HRESULT SHELL32_SetNameOfGuidItem(PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
 {
-    int type1,
-        type2;
-    char szTemp1[MAX_PATH];
-    char szTemp2[MAX_PATH];
-    HRESULT nReturn;
-    LPITEMIDLIST firstpidl;
-    LPITEMIDLIST nextpidl1;
-    LPITEMIDLIST nextpidl2;
-    CComPtr<IShellFolder> psf;
-
-    /* test for empty pidls */
-    BOOL isEmpty1 = _ILIsDesktop(pidl1);
-    BOOL isEmpty2 = _ILIsDesktop(pidl2);
-
-    if (isEmpty1 && isEmpty2)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
-    if (isEmpty1)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
-    if (isEmpty2)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
-
-    /* test for different types. Sort order is the PT_* constant */
-    type1 = _ILGetDataPointer(pidl1)->type;
-    type2 = _ILGetDataPointer(pidl2)->type;
-    if (type1 < type2)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
-    else if (type1 > type2)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
-
-    /* test for name of pidl */
-    _ILSimpleGetText(pidl1, szTemp1, MAX_PATH);
-    _ILSimpleGetText(pidl2, szTemp2, MAX_PATH);
-    nReturn = lstrcmpiA(szTemp1, szTemp2);
-    if (nReturn < 0)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
-    else if (nReturn > 0)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
-
-    /* test of complex pidls */
-    firstpidl = ILCloneFirst(pidl1);
-    nextpidl1 = ILGetNext(pidl1);
-    nextpidl2 = ILGetNext(pidl2);
-
-    /* optimizing: test special cases and bind not deeper */
-    /* the deeper shellfolder would do the same */
-    isEmpty1 = _ILIsDesktop(nextpidl1);
-    isEmpty2 = _ILIsDesktop(nextpidl2);
-
-    if (isEmpty1 && isEmpty2) 
+    GUID const *clsid = _ILGetGUIDPointer (pidl);
+    LPOLESTR pStr;
+    HRESULT hr;
+    WCHAR szName[100];
+
+    if (!clsid)
     {
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
+        ERR("Pidl is not reg item!\n");
+        return E_FAIL;
     }
-    else if (isEmpty1) 
+
+    hr = StringFromCLSID(*clsid, &pStr);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr);
+
+    DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR);
+    LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData);
+
+    CoTaskMemFree(pStr);
+
+    if (res == ERROR_SUCCESS)
     {
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (WORD) -1);
+        *pPidlOut = ILClone(pidl);
+        return S_OK;
     }
-    else if (isEmpty2)
+
+    return E_FAIL;
+}
+
+HRESULT SHELL32_GetDetailsOfGuidItem(IShellFolder2* psf, PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+    GUID const *clsid = _ILGetGUIDPointer (pidl);
+
+    if (!clsid)
     {
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1);
-        /* optimizing end */
+        ERR("Pidl is not reg item!\n");
+        return E_FAIL;
     }
-    else if (SUCCEEDED(iface->BindToObject(firstpidl, NULL, IID_PPV_ARG(IShellFolder, &psf)))) {
-        nReturn = psf->CompareIDs(lParam, nextpidl1, nextpidl2);
+
+    switch(iColumn)
+    {
+        case 0:        /* name */
+            return psf->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+        case 1:        /* comment */
+            HKEY hKey;
+            if (HCR_RegOpenClassIDKey(*clsid, &hKey))
+            {
+                psd->str.cStr[0] = 0x00;
+                psd->str.uType = STRRET_CSTR;
+                RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL);
+                RegCloseKey(hKey);
+                return S_OK;
+            }
     }
-    ILFree(firstpidl);
-    return nReturn;
+    return E_FAIL;
 }
 
 /***********************************************************************