richedit: Prevented underlining the end of paragraph character.
[wine] / dlls / shell32 / shfldr_desktop.c
index 935877e..aeb6e4b 100644 (file)
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "config.h"
@@ -60,16 +60,12 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell);
 */
 
 typedef struct {
-    IShellFolder2Vtbl *lpVtbl;
-    DWORD ref;
-
-    CLSID *pclsid;
+    const IShellFolder2Vtbl *lpVtbl;
+    LONG ref;
 
     /* 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,9 +74,7 @@ typedef struct {
 #define _IUnknown_(This)    (IShellFolder*)&(This->lpVtbl)
 #define _IShellFolder_(This)    (IShellFolder*)&(This->lpVtbl)
 
-static struct IShellFolder2Vtbl vt_MCFldr_ShellFolder2;
-
-static shvheader DesktopSFHeader[] = {
+static const shvheader DesktopSFHeader[] = {
     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
     {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
     {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
@@ -90,45 +84,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
  *
@@ -162,32 +117,12 @@ static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
 
 static ULONG WINAPI ISF_Desktop_fnAddRef (IShellFolder2 * iface)
 {
-    IGenericSFImpl *This = (IGenericSFImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE ("(%p)->(count=%lu)\n", This, refCount - 1);
-
-    return refCount;
+    return 2; /* non-heap based object */
 }
 
 static ULONG WINAPI ISF_Desktop_fnRelease (IShellFolder2 * iface)
 {
-    IGenericSFImpl *This = (IGenericSFImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE ("(%p)->(count=%lu)\n", This, refCount + 1);
-
-    if (!refCount)
-    {
-        TRACE ("-- destroying IShellFolder(%p)\n", This);
-        if (This->pidlRoot)
-            SHFree (This->pidlRoot);
-        if (This->sPathTarget)
-            SHFree (This->sPathTarget);
-        LocalFree ((HLOCAL) This);
-        return 0;
-    }
-    return refCount;
+    return 1; /* non-heap based object */
 }
 
 /**************************************************************************
@@ -229,8 +164,11 @@ static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
     }
     else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
     {
-        /* it's a filesystem path with a drive. Let MyComputer parse it */
-        pidlTemp = _ILCreateMyComputer ();
+        /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
+        if (UNIXFS_is_rooted_at_desktop()) 
+            pidlTemp = _ILCreateGuid(PT_GUID, &CLSID_UnixDosFolder);
+        else
+            pidlTemp = _ILCreateMyComputer ();
         szNext = lpszDisplayName;
     }
     else if (PathIsUNCW(lpszDisplayName))
@@ -253,13 +191,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
@@ -291,7 +227,7 @@ static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
 
     *ppidl = pidlTemp;
 
-    TRACE ("(%p)->(-- ret=0x%08lx)\n", This, hr);
+    TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
 
     return hr;
 }
@@ -310,42 +246,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%08x)\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) / sizeof (iid[0]);
+                    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);
         }
     }
 
@@ -364,7 +301,7 @@ static HRESULT WINAPI ISF_Desktop_fnEnumObjects (IShellFolder2 * iface,
 {
     IGenericSFImpl *This = (IGenericSFImpl *)iface;
 
-    TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n",
+    TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n",
            This, hwndOwner, dwFlags, ppEnumIDList);
 
     *ppEnumIDList = IEnumIDList_Constructor();
@@ -387,7 +324,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,25 +406,44 @@ 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%08x))\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);
+    TRACE ("-- result=0x%08x\n", *rgfInOut);
 
     return hr;
 }
@@ -569,7 +525,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
         hr = E_OUTOFMEMORY;
 
     *ppvOut = pObj;
-    TRACE ("(%p)->hr=0x%08lx\n", This, hr);
+    TRACE ("(%p)->hr=0x%08x\n", This, hr);
     return hr;
 }
 
@@ -583,33 +539,34 @@ 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;
+    LPWSTR pszPath;
 
-    *szPath = '\0';
-
-    TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
+    TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
     pdump (pidl);
 
     if (!strRet)
         return E_INVALIDARG;
 
+    pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
+    if (!pszPath)
+        return E_OUTOFMEMORY;
+
     if (_ILIsDesktop (pidl))
     {
         if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
-            (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING))
-        {
-            lstrcpyA (szPath, This->sPathTarget);
-        }
+            (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+            strcpyW(pszPath, This->sPathTarget);
         else
-            HCR_GetClassNameA(&CLSID_ShellDesktop, szPath, MAX_PATH);
+            HCR_GetClassNameW(&CLSID_ShellDesktop, pszPath, 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;
 
@@ -622,7 +579,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
                  */
                 if (IsEqualIID (clsid, &CLSID_MyComputer))
                 {
-                    bWantsForParsing = 1;
+                    bWantsForParsing = TRUE;
                 }
                 else
                 {
@@ -656,43 +613,72 @@ static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
                      * Only the folder itself can know it
                      */
                     hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
-                                                        szPath, MAX_PATH);
+                                                        pszPath,
+                                                        MAX_PATH);
                 }
                 else
                 {
                     /* parsing name like ::{...} */
-                    lstrcpyA (szPath, "::");
-                    SHELL32_GUIDToStringA (clsid, &szPath[2]);
+                    pszPath[0] = ':';
+                    pszPath[1] = ':';
+                    SHELL32_GUIDToStringW (clsid, &pszPath[2]);
                 }
             }
             else
             {
                 /* user friendly name */
-                HCR_GetClassNameA (clsid, szPath, MAX_PATH);
+                HCR_GetClassNameW (clsid, pszPath, 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))
+            {
+                lstrcpynW(pszPath, This->sPathTarget, MAX_PATH - 1);
+                PathAddBackslashW(pszPath);
+                cLen = lstrlenW(pszPath);
+            }
+
+            _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
 
             if (!_ILIsFolder(pidl))
-            SHELL_FS_ProcessDisplayFilename(szPath, dwFlags);
+                SHELL_FS_ProcessDisplayFilename(pszPath, 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,
+                                            pszPath, MAX_PATH);
     }
 
-    if (SUCCEEDED (hr))
+    if (SUCCEEDED(hr))
     {
-        strRet->uType = STRRET_CSTR;
-        lstrcpynA (strRet->u.cStr, szPath, MAX_PATH);
+        /* 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;
+        }
     }
+    else
+        CoTaskMemFree(pszPath);
 
-    TRACE ("-- (%p)->(%s,0x%08lx)\n", This, szPath, hr);
+    TRACE ("-- (%p)->(%s,0x%08x)\n", This,
+     strRet->uType == STRRET_CSTR ? strRet->u.cStr :
+     debugstr_w(strRet->u.pOleStr), hr);
     return hr;
 }
 
@@ -714,7 +700,7 @@ static HRESULT WINAPI ISF_Desktop_fnSetNameOf (IShellFolder2 * iface,
 {
     IGenericSFImpl *This = (IGenericSFImpl *)iface;
 
-    FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This, hwndOwner, pidl,
+    FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
            debugstr_w (lpName), dwFlags, pPidlOut);
 
     return E_FAIL;
@@ -780,7 +766,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);
 
@@ -798,6 +784,7 @@ static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
     }
 
     /* the data from the pidl */
+    psd->str.uType = STRRET_CSTR;
     switch (iColumn)
     {
     case 0:        /* name */
@@ -817,8 +804,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;
 }
@@ -831,7 +816,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,
@@ -855,3 +840,48 @@ 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)
+{
+    static IGenericSFImpl *cached_sf;
+    WCHAR szMyPath[MAX_PATH];
+
+    TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
+
+    if (!ppv)
+        return E_POINTER;
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
+
+    if (!cached_sf)
+    {
+        IGenericSFImpl *sf;
+
+        if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
+            return E_UNEXPECTED;
+
+        sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
+        if (!sf)
+            return E_OUTOFMEMORY;
+
+        sf->ref = 1;
+        sf->lpVtbl = &vt_MCFldr_ShellFolder2;
+        sf->pidlRoot = _ILCreateDesktop();    /* my qualified pidl */
+        sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
+        lstrcpyW( sf->sPathTarget, szMyPath );
+
+        if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
+        {
+            /* some other thread already been here */
+            SHFree( sf->pidlRoot );
+            SHFree( sf->sPathTarget );
+            LocalFree( sf );
+        }
+    }
+
+    return IUnknown_QueryInterface( _IUnknown_(cached_sf), riid, ppv );
+}