• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 "base/base_paths.h"
6 
7 #include <windows.h>
8 
9 #include <KnownFolders.h>
10 #include <shlobj.h>
11 
12 #include "base/environment.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/path_service.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/win/current_module.h"
19 #include "base/win/scoped_co_mem.h"
20 #include "base/win/windows_version.h"
21 
22 using base::FilePath;
23 
24 namespace base {
25 
PathProviderWin(int key,FilePath * result)26 bool PathProviderWin(int key, FilePath* result) {
27   // We need to go compute the value. It would be nice to support paths with
28   // names longer than MAX_PATH, but the system functions don't seem to be
29   // designed for it either, with the exception of GetTempPath (but other
30   // things will surely break if the temp path is too long, so we don't bother
31   // handling it.
32   wchar_t system_buffer[MAX_PATH];
33   system_buffer[0] = 0;
34 
35   FilePath cur;
36   switch (key) {
37     case base::FILE_EXE:
38       if (GetModuleFileName(NULL, system_buffer, MAX_PATH) == 0)
39         return false;
40       cur = FilePath(system_buffer);
41       break;
42     case base::FILE_MODULE: {
43       // the resource containing module is assumed to be the one that
44       // this code lives in, whether that's a dll or exe
45       if (GetModuleFileName(CURRENT_MODULE(), system_buffer, MAX_PATH) == 0)
46         return false;
47       cur = FilePath(system_buffer);
48       break;
49     }
50     case base::DIR_WINDOWS:
51       GetWindowsDirectory(system_buffer, MAX_PATH);
52       cur = FilePath(system_buffer);
53       break;
54     case base::DIR_SYSTEM:
55       GetSystemDirectory(system_buffer, MAX_PATH);
56       cur = FilePath(system_buffer);
57       break;
58     case base::DIR_PROGRAM_FILESX86:
59       if (win::OSInfo::GetArchitecture() != win::OSInfo::X86_ARCHITECTURE) {
60         if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
61                                    SHGFP_TYPE_CURRENT, system_buffer)))
62           return false;
63         cur = FilePath(system_buffer);
64         break;
65       }
66       // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
67       [[fallthrough]];
68     case base::DIR_PROGRAM_FILES:
69       if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
70                                  SHGFP_TYPE_CURRENT, system_buffer)))
71         return false;
72       cur = FilePath(system_buffer);
73       break;
74     case base::DIR_PROGRAM_FILES6432:
75 #if !defined(_WIN64)
76       if (base::win::OSInfo::GetInstance()->IsWowX86OnAMD64() ||
77           base::win::OSInfo::GetInstance()->IsWowX86OnARM64()) {
78         std::unique_ptr<base::Environment> env(base::Environment::Create());
79         std::string programfiles_w6432;
80         // 32-bit process running in WOW64 sets ProgramW6432 environment
81         // variable. See
82         // https://msdn.microsoft.com/library/windows/desktop/aa384274.aspx.
83         if (!env->GetVar("ProgramW6432", &programfiles_w6432))
84           return false;
85         // GetVar returns UTF8 - convert back to Wide.
86         cur = FilePath(UTF8ToWide(programfiles_w6432));
87         break;
88       }
89 #endif
90       if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
91                                  SHGFP_TYPE_CURRENT, system_buffer)))
92         return false;
93       cur = FilePath(system_buffer);
94       break;
95     case base::DIR_IE_INTERNET_CACHE:
96       if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
97                                  SHGFP_TYPE_CURRENT, system_buffer)))
98         return false;
99       cur = FilePath(system_buffer);
100       break;
101     case base::DIR_COMMON_START_MENU:
102       if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
103                                  SHGFP_TYPE_CURRENT, system_buffer)))
104         return false;
105       cur = FilePath(system_buffer);
106       break;
107     case base::DIR_START_MENU:
108       if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, SHGFP_TYPE_CURRENT,
109                                  system_buffer)))
110         return false;
111       cur = FilePath(system_buffer);
112       break;
113     case base::DIR_COMMON_STARTUP:
114       if (FAILED(SHGetFolderPath(nullptr, CSIDL_COMMON_STARTUP, nullptr,
115                                  SHGFP_TYPE_CURRENT, system_buffer)))
116         return false;
117       cur = FilePath(system_buffer);
118       break;
119     case base::DIR_USER_STARTUP:
120       if (FAILED(SHGetFolderPath(nullptr, CSIDL_STARTUP, nullptr,
121                                  SHGFP_TYPE_CURRENT, system_buffer)))
122         return false;
123       cur = FilePath(system_buffer);
124       break;
125     case base::DIR_ROAMING_APP_DATA:
126       if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
127                                  system_buffer)))
128         return false;
129       cur = FilePath(system_buffer);
130       break;
131     case base::DIR_COMMON_APP_DATA:
132       if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
133                                  SHGFP_TYPE_CURRENT, system_buffer)))
134         return false;
135       cur = FilePath(system_buffer);
136       break;
137     case base::DIR_LOCAL_APP_DATA:
138       if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
139                                  SHGFP_TYPE_CURRENT, system_buffer)))
140         return false;
141       cur = FilePath(system_buffer);
142       break;
143     case base::DIR_SRC_TEST_DATA_ROOT: {
144       FilePath executableDir;
145       // On Windows, unit tests execute two levels deep from the source root.
146       // For example:  chrome/{Debug|Release}/ui_tests.exe
147       PathService::Get(base::DIR_EXE, &executableDir);
148       cur = executableDir.DirName().DirName();
149       break;
150     }
151     case base::DIR_APP_SHORTCUTS: {
152       base::win::ScopedCoMem<wchar_t> path_buf;
153       if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
154                                       &path_buf)))
155         return false;
156 
157       cur = FilePath(path_buf.get());
158       break;
159     }
160     case base::DIR_USER_DESKTOP:
161       if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
162                                  SHGFP_TYPE_CURRENT, system_buffer))) {
163         return false;
164       }
165       cur = FilePath(system_buffer);
166       break;
167     case base::DIR_COMMON_DESKTOP:
168       if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
169                                  SHGFP_TYPE_CURRENT, system_buffer))) {
170         return false;
171       }
172       cur = FilePath(system_buffer);
173       break;
174     case base::DIR_USER_QUICK_LAUNCH:
175       if (!PathService::Get(base::DIR_ROAMING_APP_DATA, &cur))
176         return false;
177       // According to various sources, appending
178       // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
179       // reliable way to get the quick launch folder across all versions of
180       // Windows.
181       // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
182       // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
183       cur = cur.Append(FILE_PATH_LITERAL("Microsoft"))
184                 .Append(FILE_PATH_LITERAL("Internet Explorer"))
185                 .Append(FILE_PATH_LITERAL("Quick Launch"));
186       break;
187     case base::DIR_TASKBAR_PINS: {
188       if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
189         return false;
190       cur = cur.Append(FILE_PATH_LITERAL("User Pinned"))
191                 .Append(FILE_PATH_LITERAL("TaskBar"));
192       break;
193     }
194     case base::DIR_IMPLICIT_APP_SHORTCUTS:
195       if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
196         return false;
197       cur = cur.Append(FILE_PATH_LITERAL("User Pinned"))
198                 .Append(FILE_PATH_LITERAL("ImplicitAppShortcuts"));
199       break;
200     case base::DIR_WINDOWS_FONTS:
201       if (FAILED(SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT,
202                                  system_buffer))) {
203         return false;
204       }
205       cur = FilePath(system_buffer);
206       break;
207     case base::DIR_SYSTEM_TEMP:
208       // Try C:\Windows\SystemTemp, which was introduced sometime before Windows
209       // 10 build 19042. Do not use GetTempPath2, as it only appeared later and
210       // will only return the path for processes running as SYSTEM.
211       if (PathService::Get(DIR_WINDOWS, &cur)) {
212         cur = cur.Append(FILE_PATH_LITERAL("SystemTemp"));
213         if (PathIsWritable(cur)) {
214           break;
215         }
216       }
217       // Failing that, use C:\Program Files or C:\Program Files (x86) for older
218       // versions of Windows 10.
219       if (!PathService::Get(DIR_PROGRAM_FILES, &cur) || !PathIsWritable(cur)) {
220         return false;
221       }
222       break;
223     default:
224       return false;
225   }
226 
227   *result = cur;
228   return true;
229 }
230 
231 }  // namespace base
232