15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_co_mem.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" IMAGE_DOS_HEADER __ImageBase;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::FilePath;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathProviderWin(int key, FilePath* result) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to go compute the value. It would be nice to support paths with
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // names longer than MAX_PATH, but the system functions don't seem to be
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // designed for it either, with the exception of GetTempPath (but other
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // things will surely break if the temp path is too long, so we don't bother
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handling it.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t system_buffer[MAX_PATH];
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system_buffer[0] = 0;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath cur;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (key) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::FILE_EXE:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetModuleFileName(NULL, system_buffer, MAX_PATH);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::FILE_MODULE: {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the resource containing module is assumed to be the one that
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // this code lives in, whether that's a dll or exe
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetModuleFileName(this_module, system_buffer, MAX_PATH);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_WINDOWS:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetWindowsDirectory(system_buffer, MAX_PATH);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_SYSTEM:
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSystemDirectory(system_buffer, MAX_PATH);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_PROGRAM_FILESX86:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base::win::OSInfo::GetInstance()->architecture() !=
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::win::OSInfo::X86_ARCHITECTURE) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   SHGFP_TYPE_CURRENT, system_buffer)))
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cur = FilePath(system_buffer);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_PROGRAM_FILES:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_IE_INTERNET_CACHE:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_COMMON_START_MENU:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_START_MENU:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_APP_DATA:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 system_buffer)))
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_COMMON_APP_DATA:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_LOCAL_APP_DATA_LOW:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (win::GetVersion() < win::VERSION_VISTA)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 system_buffer)))
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow");
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_LOCAL_APP_DATA:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer)))
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_SOURCE_ROOT: {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath executableDir;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // On Windows, unit tests execute two levels deep from the source root.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // For example:  chrome/{Debug|Release}/ui_tests.exe
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PathService::Get(base::DIR_EXE, &executableDir);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = executableDir.DirName().DirName();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_APP_SHORTCUTS: {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (win::GetVersion() < win::VERSION_WIN8)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::ScopedCoMem<wchar_t> path_buf;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &path_buf)))
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(string16(path_buf));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_USER_DESKTOP:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer))) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_COMMON_DESKTOP:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SHGFP_TYPE_CURRENT, system_buffer))) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = FilePath(system_buffer);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_USER_QUICK_LAUNCH:
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (!PathService::Get(base::DIR_APP_DATA, &cur))
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return false;
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // According to various sources, appending
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // reliable way to get the quick launch folder across all versions of
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // Windows.
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      cur = cur.AppendASCII("Microsoft")
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                .AppendASCII("Internet Explorer")
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                .AppendASCII("Quick Launch");
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::DIR_TASKBAR_PINS:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = cur.AppendASCII("User Pinned");
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cur = cur.AppendASCII("TaskBar");
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case base::DIR_WINDOWS_FONTS:
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (FAILED(SHGetFolderPath(
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, system_buffer))) {
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return false;
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      cur = FilePath(system_buffer);
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *result = cur;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
183