1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <windows.h> 6 #include <shlobj.h> 7 8 #include "base/base_paths.h" 9 #include "base/files/file_path.h" 10 #include "base/path_service.h" 11 #include "base/win/scoped_co_mem.h" 12 #include "base/win/windows_version.h" 13 14 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx 15 extern "C" IMAGE_DOS_HEADER __ImageBase; 16 17 using base::FilePath; 18 19 namespace base { 20 21 bool PathProviderWin(int key, FilePath* result) { 22 // We need to go compute the value. It would be nice to support paths with 23 // names longer than MAX_PATH, but the system functions don't seem to be 24 // designed for it either, with the exception of GetTempPath (but other 25 // things will surely break if the temp path is too long, so we don't bother 26 // handling it. 27 wchar_t system_buffer[MAX_PATH]; 28 system_buffer[0] = 0; 29 30 FilePath cur; 31 switch (key) { 32 case base::FILE_EXE: 33 GetModuleFileName(NULL, system_buffer, MAX_PATH); 34 cur = FilePath(system_buffer); 35 break; 36 case base::FILE_MODULE: { 37 // the resource containing module is assumed to be the one that 38 // this code lives in, whether that's a dll or exe 39 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); 40 GetModuleFileName(this_module, system_buffer, MAX_PATH); 41 cur = FilePath(system_buffer); 42 break; 43 } 44 case base::DIR_WINDOWS: 45 GetWindowsDirectory(system_buffer, MAX_PATH); 46 cur = FilePath(system_buffer); 47 break; 48 case base::DIR_SYSTEM: 49 GetSystemDirectory(system_buffer, MAX_PATH); 50 cur = FilePath(system_buffer); 51 break; 52 case base::DIR_PROGRAM_FILESX86: 53 if (base::win::OSInfo::GetInstance()->architecture() != 54 base::win::OSInfo::X86_ARCHITECTURE) { 55 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, 56 SHGFP_TYPE_CURRENT, system_buffer))) 57 return false; 58 cur = FilePath(system_buffer); 59 break; 60 } 61 // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine. 62 case base::DIR_PROGRAM_FILES: 63 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 64 SHGFP_TYPE_CURRENT, system_buffer))) 65 return false; 66 cur = FilePath(system_buffer); 67 break; 68 case base::DIR_IE_INTERNET_CACHE: 69 if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, 70 SHGFP_TYPE_CURRENT, system_buffer))) 71 return false; 72 cur = FilePath(system_buffer); 73 break; 74 case base::DIR_COMMON_START_MENU: 75 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL, 76 SHGFP_TYPE_CURRENT, system_buffer))) 77 return false; 78 cur = FilePath(system_buffer); 79 break; 80 case base::DIR_START_MENU: 81 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 82 SHGFP_TYPE_CURRENT, system_buffer))) 83 return false; 84 cur = FilePath(system_buffer); 85 break; 86 case base::DIR_APP_DATA: 87 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, 88 system_buffer))) 89 return false; 90 cur = FilePath(system_buffer); 91 break; 92 case base::DIR_COMMON_APP_DATA: 93 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 94 SHGFP_TYPE_CURRENT, system_buffer))) 95 return false; 96 cur = FilePath(system_buffer); 97 break; 98 case base::DIR_LOCAL_APP_DATA_LOW: 99 if (win::GetVersion() < win::VERSION_VISTA) 100 return false; 101 102 // TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128 103 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, 104 system_buffer))) 105 return false; 106 cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow"); 107 break; 108 case base::DIR_LOCAL_APP_DATA: 109 if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 110 SHGFP_TYPE_CURRENT, system_buffer))) 111 return false; 112 cur = FilePath(system_buffer); 113 break; 114 case base::DIR_SOURCE_ROOT: { 115 FilePath executableDir; 116 // On Windows, unit tests execute two levels deep from the source root. 117 // For example: chrome/{Debug|Release}/ui_tests.exe 118 PathService::Get(base::DIR_EXE, &executableDir); 119 cur = executableDir.DirName().DirName(); 120 break; 121 } 122 case base::DIR_APP_SHORTCUTS: { 123 if (win::GetVersion() < win::VERSION_WIN8) 124 return false; 125 126 base::win::ScopedCoMem<wchar_t> path_buf; 127 if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL, 128 &path_buf))) 129 return false; 130 131 cur = FilePath(string16(path_buf)); 132 break; 133 } 134 case base::DIR_USER_DESKTOP: 135 if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 136 SHGFP_TYPE_CURRENT, system_buffer))) { 137 return false; 138 } 139 cur = FilePath(system_buffer); 140 break; 141 case base::DIR_COMMON_DESKTOP: 142 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 143 SHGFP_TYPE_CURRENT, system_buffer))) { 144 return false; 145 } 146 cur = FilePath(system_buffer); 147 break; 148 case base::DIR_USER_QUICK_LAUNCH: 149 if (!PathService::Get(base::DIR_APP_DATA, &cur)) 150 return false; 151 // According to various sources, appending 152 // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only 153 // reliable way to get the quick launch folder across all versions of 154 // Windows. 155 // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick- 156 // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx 157 cur = cur.AppendASCII("Microsoft") 158 .AppendASCII("Internet Explorer") 159 .AppendASCII("Quick Launch"); 160 break; 161 case base::DIR_TASKBAR_PINS: 162 if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur)) 163 return false; 164 cur = cur.AppendASCII("User Pinned"); 165 cur = cur.AppendASCII("TaskBar"); 166 break; 167 case base::DIR_WINDOWS_FONTS: 168 if (FAILED(SHGetFolderPath( 169 NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, system_buffer))) { 170 return false; 171 } 172 cur = FilePath(system_buffer); 173 break; 174 default: 175 return false; 176 } 177 178 *result = cur; 179 return true; 180 } 181 182 } // namespace base 183