Bug 837932 - Update dir svc media paths for Win7 and up - media dirs should point to Library default save locations. r=bsmedberg
authorJim Mathies <jmathies@mozilla.com>
Mon, 11 Feb 2013 13:03:54 -0600
changeset 121532 0d714dcba97926e367d655d152568dc132997fe8
parent 121531 99e8b116dd0973ee7ef888eabb0a01ca4ea3b840
child 121533 50df17d70386a66712e708873de7cdea130b6410
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbsmedberg
bugs837932
milestone21.0a1
Bug 837932 - Update dir svc media paths for Win7 and up - media dirs should point to Library default save locations. r=bsmedberg
xpcom/io/SpecialSystemDirectory.cpp
xpcom/io/SpecialSystemDirectory.h
xpcom/io/nsDirectoryService.cpp
xpcom/io/nsDirectoryServiceAtomList.h
xpcom/io/nsDirectoryServiceDefs.h
--- a/xpcom/io/SpecialSystemDirectory.cpp
+++ b/xpcom/io/SpecialSystemDirectory.cpp
@@ -1,25 +1,29 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SpecialSystemDirectory.h"
 #include "nsString.h"
 #include "nsDependentString.h"
+#include "nsAutoPtr.h"
 
 #if defined(XP_WIN)
 
 #include <windows.h>
 #include <shlobj.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <direct.h>
+#include <shlobj.h>
+#include <knownfolders.h>
+#include <guiddef.h>
 
 #elif defined(XP_OS2)
 
 #define MAX_PATH _MAX_PATH
 #define INCL_WINWORKPLACE
 #define INCL_DOSMISC
 #define INCL_DOSMODULEMGR
 #define INCL_DOSPROCESS
@@ -96,19 +100,18 @@ static nsresult GetKnownFolder(GUID* gui
     nsresult rv = NS_NewLocalFile(nsDependentString(path),
                                   true,
                                   aFile);
 
     CoTaskMemFree(path);
     return rv;
 }
 
-//----------------------------------------------------------------------------------------
-static nsresult GetWindowsFolder(int folder, nsIFile** aFile)
-//----------------------------------------------------------------------------------------
+static nsresult
+GetWindowsFolder(int folder, nsIFile** aFile)
 {
     WCHAR path_orig[MAX_PATH + 3];
     WCHAR *path = path_orig+1;
     HRESULT result = SHGetSpecialFolderPathW(NULL, path, folder, true);
 
     if (!SUCCEEDED(result))
         return NS_ERROR_FAILURE;
 
@@ -118,16 +121,75 @@ static nsresult GetWindowsFolder(int fol
     {
         path[len]   = L'\\';
         path[++len] = L'\0';
     }
 
     return NS_NewLocalFile(nsDependentString(path, len), true, aFile);
 }
 
+__inline HRESULT
+SHLoadLibraryFromKnownFolder(REFKNOWNFOLDERID aFolderId, DWORD aMode,
+                             REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+    IShellLibrary *plib;
+    HRESULT hr = CoCreateInstance(CLSID_ShellLibrary, NULL,
+                                  CLSCTX_INPROC_SERVER,
+                                  IID_PPV_ARGS(&plib));
+    if (SUCCEEDED(hr)) {
+        hr = plib->LoadLibraryFromKnownFolder(aFolderId, aMode);
+        if (SUCCEEDED(hr)) {
+            hr = plib->QueryInterface(riid, ppv);
+        }
+        plib->Release();
+    }
+    return hr;
+}
+
+/*
+ * Check to see if we're on Win7 and up, and if so, returns the default
+ * save-to location for the Windows Library passed in through aFolderId.
+ * Otherwise falls back on pre-win7 GetWindowsFolder.
+ */
+static nsresult
+GetLibrarySaveToPath(int aFallbackFolderId, REFKNOWNFOLDERID aFolderId,
+                     nsIFile** aFile)
+{
+    // Skip off checking for library support if the os is Vista or lower.
+    DWORD dwVersion = GetVersion();
+    if ((DWORD)(LOBYTE(LOWORD(dwVersion))) < 6 ||
+        ((DWORD)(LOBYTE(LOWORD(dwVersion))) == 6 &&
+         (DWORD)(HIBYTE(LOWORD(dwVersion))) == 0))
+      return GetWindowsFolder(aFallbackFolderId, aFile);
+
+    nsRefPtr<IShellLibrary> shellLib;
+    nsRefPtr<IShellItem> savePath;
+    HRESULT hr =
+        SHLoadLibraryFromKnownFolder(aFolderId, STGM_READ,
+                                     IID_IShellLibrary, getter_AddRefs(shellLib));
+
+    if (shellLib &&
+        SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
+                                                 getter_AddRefs(savePath)))) {
+        PRUnichar* str = nullptr;
+        if (SUCCEEDED(savePath->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
+            nsAutoString path;
+            path.Assign(str);
+            path.AppendLiteral("\\");
+            nsresult rv =
+                NS_NewLocalFile(path, false, aFile);
+            CoTaskMemFree(str);
+            return rv;
+        }
+    }
+
+    return GetWindowsFolder(aFallbackFolderId, aFile);
+}
+
 /**
  * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
  * querying the registry when the call to SHGetSpecialFolderPathW is unable to
  * provide these paths (Bug 513958).
  */
 static nsresult GetRegWindowsAppDataFolder(bool aLocal, nsIFile** aFile)
 {
     HKEY key;
@@ -742,27 +804,39 @@ GetSpecialSystemDirectory(SystemDirector
         }
         case Win_LocalAppdata:
         {
             nsresult rv = GetWindowsFolder(CSIDL_LOCAL_APPDATA, aFile);
             if (NS_FAILED(rv))
                 rv = GetRegWindowsAppDataFolder(true, aFile);
             return rv;
         }
+        case Win_Documents:
+        {
+            return GetLibrarySaveToPath(CSIDL_MYDOCUMENTS,
+                                        FOLDERID_DocumentsLibrary,
+                                        aFile);
+        }
         case Win_Pictures:
         {
-            return GetWindowsFolder(CSIDL_MYPICTURES, aFile);
+            return GetLibrarySaveToPath(CSIDL_MYPICTURES,
+                                        FOLDERID_PicturesLibrary,
+                                        aFile);
         }
         case Win_Music:
         {
-            return GetWindowsFolder(CSIDL_MYMUSIC, aFile);
+            return GetLibrarySaveToPath(CSIDL_MYMUSIC,
+                                        FOLDERID_MusicLibrary,
+                                        aFile);
         }
         case Win_Videos:
         {
-            return GetWindowsFolder(CSIDL_MYVIDEO, aFile);
+            return GetLibrarySaveToPath(CSIDL_MYVIDEO,
+                                        FOLDERID_VideosLibrary,
+                                        aFile);
         }
 #endif  // XP_WIN
 
 #if defined(XP_UNIX)
         case Unix_LocalDirectory:
             return NS_NewNativeLocalFile(nsDependentCString("/usr/local/netscape/"),
                                          true,
                                          aFile);
--- a/xpcom/io/SpecialSystemDirectory.h
+++ b/xpcom/io/SpecialSystemDirectory.h
@@ -69,20 +69,21 @@ enum SystemDirectories {
   Win_Common_Desktopdirectory = 224,   
   Win_Appdata               =   225,   
   Win_Printhood             =   226,   
   Win_Cookies               =   227, 
   Win_LocalAppdata          =   228,
   Win_ProgramFiles          =   229,
   Win_Downloads             =   230,
   Win_Common_AppData        =   231,
-  Win_Pictures              =   232,
-  Win_Music                 =   233,
-  Win_Videos                =   234,
-  
+  Win_Documents             =   232,
+  Win_Pictures              =   233,
+  Win_Music                 =   234,
+  Win_Videos                =   235,
+
   Unix_LocalDirectory       =   301,   
   Unix_LibDirectory         =   302,   
   Unix_HomeDirectory        =   303,
   Unix_XDG_Desktop          =   304,
   Unix_XDG_Documents        =   305,
   Unix_XDG_Download         =   306,
   Unix_XDG_Music            =   307,
   Unix_XDG_Pictures         =   308,
--- a/xpcom/io/nsDirectoryService.cpp
+++ b/xpcom/io/nsDirectoryService.cpp
@@ -818,16 +818,20 @@ nsDirectoryService::GetFile(const char *
     else if (inAtom == nsDirectoryService::sWinCookiesDirectory)
     {
         rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile)); 
     }
     else if (inAtom == nsDirectoryService::sDefaultDownloadDirectory)
     {
         rv = GetSpecialSystemDirectory(Win_Downloads, getter_AddRefs(localFile));
     }
+    else if (inAtom == nsDirectoryService::sDocs)
+    {
+        rv = GetSpecialSystemDirectory(Win_Documents, getter_AddRefs(localFile));
+    }
     else if (inAtom == nsDirectoryService::sPictures)
     {
         rv = GetSpecialSystemDirectory(Win_Pictures, getter_AddRefs(localFile));
     }
     else if (inAtom == nsDirectoryService::sMusic)
     {
         rv = GetSpecialSystemDirectory(Win_Music, getter_AddRefs(localFile));
     }
--- a/xpcom/io/nsDirectoryServiceAtomList.h
+++ b/xpcom/io/nsDirectoryServiceAtomList.h
@@ -68,16 +68,17 @@ DIR_ATOM(sCommon_Programs, NS_WIN_COMMON
 DIR_ATOM(sCommon_Startup, NS_WIN_COMMON_STARTUP_DIR)
 DIR_ATOM(sCommon_Desktopdirectory, NS_WIN_COMMON_DESKTOP_DIRECTORY)
 DIR_ATOM(sCommon_AppData, NS_WIN_COMMON_APPDATA_DIR)
 DIR_ATOM(sAppdata, NS_WIN_APPDATA_DIR)
 DIR_ATOM(sLocalAppdata, NS_WIN_LOCAL_APPDATA_DIR)
 DIR_ATOM(sPrinthood, NS_WIN_PRINTHOOD)
 DIR_ATOM(sWinCookiesDirectory, NS_WIN_COOKIES_DIR)
 DIR_ATOM(sDefaultDownloadDirectory, NS_WIN_DEFAULT_DOWNLOAD_DIR)
+DIR_ATOM(sDocs, NS_WIN_DOCUMENTS_DIR)
 DIR_ATOM(sPictures, NS_WIN_PICTURES_DIR)
 DIR_ATOM(sMusic, NS_WIN_MUSIC_DIR)
 DIR_ATOM(sVideos, NS_WIN_VIDEOS_DIR)
 #elif defined (XP_UNIX)
 DIR_ATOM(sLocalDirectory, NS_UNIX_LOCAL_DIR)
 DIR_ATOM(sLibDirectory, NS_UNIX_LIB_DIR)
 DIR_ATOM(sDefaultDownloadDirectory, NS_UNIX_DEFAULT_DOWNLOAD_DIR)
 DIR_ATOM(sXDGDesktop, NS_UNIX_XDG_DESKTOP_DIR)
--- a/xpcom/io/nsDirectoryServiceDefs.h
+++ b/xpcom/io/nsDirectoryServiceDefs.h
@@ -117,16 +117,21 @@
     #define NS_WIN_COMMON_STARTUP_DIR           "CmStrt"
     #define NS_WIN_COMMON_DESKTOP_DIRECTORY     "CmDeskP"
     #define NS_WIN_COMMON_APPDATA_DIR           "CmAppData"
     #define NS_WIN_APPDATA_DIR                  "AppData"
     #define NS_WIN_LOCAL_APPDATA_DIR            "LocalAppData"
     #define NS_WIN_PRINTHOOD                    "PrntHd"
     #define NS_WIN_COOKIES_DIR                  "CookD"
     #define NS_WIN_DEFAULT_DOWNLOAD_DIR         "DfltDwnld"
+    // On Win7 and up these ids will return the default save-to location for
+    // Windows Libraries associated with the specific content type. For other
+    // os they return the local user folder. Note these can return network file
+    // paths which can jank the ui thread so be careful how you access them.
+    #define NS_WIN_DOCUMENTS_DIR                "Docs"
     #define NS_WIN_PICTURES_DIR                 "Pict"
     #define NS_WIN_MUSIC_DIR                    "Music"
     #define NS_WIN_VIDEOS_DIR                   "Vids"
 #elif defined (XP_UNIX)
     #define NS_UNIX_LOCAL_DIR                   "Locl"
     #define NS_UNIX_LIB_DIR                     "LibD"
     #define NS_UNIX_HOME_DIR                    NS_OS_HOME_DIR
     #define NS_UNIX_XDG_DESKTOP_DIR             "XDGDesk"