|
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 { |
|
20 |
|
21 bool GetQuickLaunchPath(bool default_user, FilePath* result) { |
|
22 if (default_user) { |
|
23 wchar_t system_buffer[MAX_PATH]; |
|
24 system_buffer[0] = 0; |
|
25 // As per MSDN, passing -1 for |hToken| indicates the Default user: |
|
26 // http://msdn.microsoft.com/library/windows/desktop/bb762181.aspx |
|
27 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, |
|
28 reinterpret_cast<HANDLE>(-1), SHGFP_TYPE_CURRENT, |
|
29 system_buffer))) { |
|
30 return false; |
|
31 } |
|
32 *result = FilePath(system_buffer); |
|
33 } else if (!PathService::Get(base::DIR_APP_DATA, result)) { |
|
34 // For the current user, grab the APPDATA directory directly from the |
|
35 // PathService cache. |
|
36 return false; |
|
37 } |
|
38 // According to various sources, appending |
|
39 // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only |
|
40 // reliable way to get the quick launch folder across all versions of Windows. |
|
41 // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick- |
|
42 // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx |
|
43 *result = result->AppendASCII("Microsoft"); |
|
44 *result = result->AppendASCII("Internet Explorer"); |
|
45 *result = result->AppendASCII("Quick Launch"); |
|
46 return true; |
|
47 } |
|
48 |
|
49 } // namespace |
|
50 |
|
51 namespace base { |
|
52 |
|
53 bool PathProviderWin(int key, FilePath* result) { |
|
54 // We need to go compute the value. It would be nice to support paths with |
|
55 // names longer than MAX_PATH, but the system functions don't seem to be |
|
56 // designed for it either, with the exception of GetTempPath (but other |
|
57 // things will surely break if the temp path is too long, so we don't bother |
|
58 // handling it. |
|
59 wchar_t system_buffer[MAX_PATH]; |
|
60 system_buffer[0] = 0; |
|
61 |
|
62 FilePath cur; |
|
63 switch (key) { |
|
64 case base::FILE_EXE: |
|
65 GetModuleFileName(NULL, system_buffer, MAX_PATH); |
|
66 cur = FilePath(system_buffer); |
|
67 break; |
|
68 case base::FILE_MODULE: { |
|
69 // the resource containing module is assumed to be the one that |
|
70 // this code lives in, whether that's a dll or exe |
|
71 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); |
|
72 GetModuleFileName(this_module, system_buffer, MAX_PATH); |
|
73 cur = FilePath(system_buffer); |
|
74 break; |
|
75 } |
|
76 case base::DIR_WINDOWS: |
|
77 GetWindowsDirectory(system_buffer, MAX_PATH); |
|
78 cur = FilePath(system_buffer); |
|
79 break; |
|
80 case base::DIR_SYSTEM: |
|
81 GetSystemDirectory(system_buffer, MAX_PATH); |
|
82 cur = FilePath(system_buffer); |
|
83 break; |
|
84 case base::DIR_PROGRAM_FILESX86: |
|
85 if (base::win::OSInfo::GetInstance()->architecture() != |
|
86 base::win::OSInfo::X86_ARCHITECTURE) { |
|
87 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, |
|
88 SHGFP_TYPE_CURRENT, system_buffer))) |
|
89 return false; |
|
90 cur = FilePath(system_buffer); |
|
91 break; |
|
92 } |
|
93 // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine. |
|
94 case base::DIR_PROGRAM_FILES: |
|
95 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, |
|
96 SHGFP_TYPE_CURRENT, system_buffer))) |
|
97 return false; |
|
98 cur = FilePath(system_buffer); |
|
99 break; |
|
100 case base::DIR_IE_INTERNET_CACHE: |
|
101 if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, |
|
102 SHGFP_TYPE_CURRENT, system_buffer))) |
|
103 return false; |
|
104 cur = FilePath(system_buffer); |
|
105 break; |
|
106 case base::DIR_COMMON_START_MENU: |
|
107 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL, |
|
108 SHGFP_TYPE_CURRENT, system_buffer))) |
|
109 return false; |
|
110 cur = FilePath(system_buffer); |
|
111 break; |
|
112 case base::DIR_START_MENU: |
|
113 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, |
|
114 SHGFP_TYPE_CURRENT, system_buffer))) |
|
115 return false; |
|
116 cur = FilePath(system_buffer); |
|
117 break; |
|
118 case base::DIR_APP_DATA: |
|
119 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, |
|
120 system_buffer))) |
|
121 return false; |
|
122 cur = FilePath(system_buffer); |
|
123 break; |
|
124 case base::DIR_COMMON_APP_DATA: |
|
125 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, |
|
126 SHGFP_TYPE_CURRENT, system_buffer))) |
|
127 return false; |
|
128 cur = FilePath(system_buffer); |
|
129 break; |
|
130 case base::DIR_PROFILE: |
|
131 if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, |
|
132 system_buffer))) |
|
133 return false; |
|
134 cur = FilePath(system_buffer); |
|
135 break; |
|
136 case base::DIR_LOCAL_APP_DATA_LOW: |
|
137 if (win::GetVersion() < win::VERSION_VISTA) |
|
138 return false; |
|
139 |
|
140 // TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128 |
|
141 if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, |
|
142 system_buffer))) |
|
143 return false; |
|
144 cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow"); |
|
145 break; |
|
146 case base::DIR_LOCAL_APP_DATA: |
|
147 if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, |
|
148 SHGFP_TYPE_CURRENT, system_buffer))) |
|
149 return false; |
|
150 cur = FilePath(system_buffer); |
|
151 break; |
|
152 case base::DIR_SOURCE_ROOT: { |
|
153 FilePath executableDir; |
|
154 // On Windows, unit tests execute two levels deep from the source root. |
|
155 // For example: chrome/{Debug|Release}/ui_tests.exe |
|
156 PathService::Get(base::DIR_EXE, &executableDir); |
|
157 cur = executableDir.DirName().DirName(); |
|
158 break; |
|
159 } |
|
160 case base::DIR_APP_SHORTCUTS: { |
|
161 if (win::GetVersion() < win::VERSION_WIN8) |
|
162 return false; |
|
163 |
|
164 base::win::ScopedCoMem<wchar_t> path_buf; |
|
165 if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL, |
|
166 &path_buf))) |
|
167 return false; |
|
168 |
|
169 cur = FilePath(string16(path_buf)); |
|
170 break; |
|
171 } |
|
172 case base::DIR_USER_DESKTOP: |
|
173 if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, |
|
174 SHGFP_TYPE_CURRENT, system_buffer))) { |
|
175 return false; |
|
176 } |
|
177 cur = FilePath(system_buffer); |
|
178 break; |
|
179 case base::DIR_COMMON_DESKTOP: |
|
180 if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, |
|
181 SHGFP_TYPE_CURRENT, system_buffer))) { |
|
182 return false; |
|
183 } |
|
184 cur = FilePath(system_buffer); |
|
185 break; |
|
186 case base::DIR_USER_QUICK_LAUNCH: |
|
187 if (!GetQuickLaunchPath(false, &cur)) |
|
188 return false; |
|
189 break; |
|
190 case base::DIR_DEFAULT_USER_QUICK_LAUNCH: |
|
191 if (!GetQuickLaunchPath(true, &cur)) |
|
192 return false; |
|
193 break; |
|
194 case base::DIR_TASKBAR_PINS: |
|
195 if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur)) |
|
196 return false; |
|
197 cur = cur.AppendASCII("User Pinned"); |
|
198 cur = cur.AppendASCII("TaskBar"); |
|
199 break; |
|
200 default: |
|
201 return false; |
|
202 } |
|
203 |
|
204 *result = cur; |
|
205 return true; |
|
206 } |
|
207 |
|
208 } // namespace base |