OLD | NEW |
| (Empty) |
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 "chrome_frame/test_utils.h" | |
6 | |
7 #include <atlbase.h> | |
8 #include <atlwin.h> | |
9 #include <shellapi.h> | |
10 | |
11 #include <algorithm> | |
12 | |
13 #include "base/command_line.h" | |
14 #include "base/file_util.h" | |
15 #include "base/files/file_path.h" | |
16 #include "base/logging.h" | |
17 #include "base/path_service.h" | |
18 #include "base/process/kill.h" | |
19 #include "base/process/launch.h" | |
20 #include "base/strings/stringprintf.h" | |
21 #include "base/strings/utf_string_conversions.h" | |
22 #include "base/win/scoped_handle.h" | |
23 #include "chrome/common/chrome_paths.h" | |
24 #include "chrome/common/chrome_switches.h" | |
25 #include "chrome_frame/test/chrome_frame_test_utils.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 | |
28 const wchar_t kChromeFrameDllName[] = L"npchrome_frame.dll"; | |
29 const wchar_t kChromeLauncherExeName[] = L"chrome_launcher.exe"; | |
30 // How long to wait for DLLs to register or unregister themselves before killing | |
31 // the registrar. | |
32 const int64 kDllRegistrationTimeoutMs = 30 * 1000; | |
33 | |
34 base::FilePath GetChromeFrameBuildPath() { | |
35 base::FilePath build_path; | |
36 PathService::Get(chrome::DIR_APP, &build_path); | |
37 | |
38 base::FilePath dll_path = build_path.Append(kChromeFrameDllName); | |
39 | |
40 if (!base::PathExists(dll_path)) { | |
41 // Well, dang.. try looking in the current directory. | |
42 dll_path = build_path.Append(kChromeFrameDllName); | |
43 } | |
44 | |
45 if (!base::PathExists(dll_path)) { | |
46 // No luck, return something empty. | |
47 dll_path = base::FilePath(); | |
48 } | |
49 | |
50 return dll_path; | |
51 } | |
52 | |
53 const wchar_t ScopedChromeFrameRegistrar::kCallRegistrationEntrypointSwitch[] = | |
54 L"--call-registration-entrypoint"; | |
55 | |
56 bool ScopedChromeFrameRegistrar::register_chrome_path_provider_ = false; | |
57 | |
58 // static | |
59 void ScopedChromeFrameRegistrar::RegisterDefaults() { | |
60 if (!register_chrome_path_provider_) { | |
61 chrome::RegisterPathProvider(); | |
62 register_chrome_path_provider_ = true; | |
63 } | |
64 } | |
65 | |
66 // Registers or unregisters the DLL at |path| by calling out to the current | |
67 // executable with --call-registration-entrypoint. Loading the DLL into the | |
68 // test process is problematic for component=shared_library builds since | |
69 // singletons in base.dll aren't designed to handle multiple initialization. | |
70 // Use of rundll32.exe is problematic since it does not return useful error | |
71 // information. | |
72 // static | |
73 void ScopedChromeFrameRegistrar::DoRegistration( | |
74 const base::string16& path, | |
75 RegistrationType registration_type, | |
76 RegistrationOperation registration_operation) { | |
77 static const char* const kEntrypoints[] = { | |
78 "DllRegisterServer", | |
79 "DllUnregisterServer", | |
80 "DllRegisterUserServer", | |
81 "DllUnregisterUserServer", | |
82 }; | |
83 | |
84 DCHECK(!path.empty()); | |
85 DCHECK(registration_type == PER_USER || registration_type == SYSTEM_LEVEL); | |
86 DCHECK(registration_operation == REGISTER || | |
87 registration_operation == UNREGISTER); | |
88 | |
89 int entrypoint_index = 0; | |
90 base::LaunchOptions launch_options; | |
91 base::win::ScopedHandle process_handle; | |
92 int exit_code = -1; | |
93 | |
94 if (registration_type == PER_USER) | |
95 entrypoint_index += 2; | |
96 if (registration_operation == UNREGISTER) | |
97 entrypoint_index += 1; | |
98 base::string16 registration_command(base::ASCIIToUTF16("\"")); | |
99 registration_command += | |
100 CommandLine::ForCurrentProcess()->GetProgram().value(); | |
101 registration_command += base::ASCIIToUTF16("\" "); | |
102 registration_command += kCallRegistrationEntrypointSwitch; | |
103 registration_command += base::ASCIIToUTF16(" \""); | |
104 registration_command += path; | |
105 registration_command += base::ASCIIToUTF16("\" "); | |
106 registration_command += base::ASCIIToUTF16(kEntrypoints[entrypoint_index]); | |
107 launch_options.wait = true; | |
108 if (!base::LaunchProcess(registration_command, launch_options, | |
109 &process_handle)) { | |
110 PLOG(FATAL) | |
111 << "Failed to register or unregister DLL with command: " | |
112 << registration_command; | |
113 } else { | |
114 if (!base::WaitForExitCodeWithTimeout( | |
115 process_handle.Get(), &exit_code, | |
116 base::TimeDelta::FromMilliseconds(kDllRegistrationTimeoutMs))) { | |
117 LOG(ERROR) << "Timeout waiting to register or unregister DLL with " | |
118 "command: " << registration_command; | |
119 base::KillProcess(process_handle.Get(), 0, false); | |
120 NOTREACHED() << "Aborting test due to registration failure."; | |
121 } | |
122 } | |
123 if (exit_code != 0) { | |
124 if (registration_operation == REGISTER) { | |
125 LOG(ERROR) | |
126 << "DLL registration failed (exit code: 0x" << std::hex << exit_code | |
127 << ", command: " << registration_command | |
128 << "). Make sure you are running as Admin."; | |
129 ::ExitProcess(1); | |
130 } else { | |
131 LOG(WARNING) | |
132 << "DLL unregistration failed (exit code: 0x" << std::hex << exit_code | |
133 << ", command: " << registration_command << ")."; | |
134 } | |
135 } | |
136 } | |
137 | |
138 // static | |
139 void ScopedChromeFrameRegistrar::RegisterAtPath( | |
140 const std::wstring& path, RegistrationType registration_type) { | |
141 DoRegistration(path, registration_type, REGISTER); | |
142 } | |
143 | |
144 // static | |
145 void ScopedChromeFrameRegistrar::UnregisterAtPath( | |
146 const std::wstring& path, RegistrationType registration_type) { | |
147 DoRegistration(path, registration_type, UNREGISTER); | |
148 } | |
149 | |
150 base::FilePath ScopedChromeFrameRegistrar::GetReferenceChromeFrameDllPath() { | |
151 base::FilePath reference_build_dir; | |
152 PathService::Get(chrome::DIR_APP, &reference_build_dir); | |
153 | |
154 reference_build_dir = reference_build_dir.DirName(); | |
155 reference_build_dir = reference_build_dir.DirName(); | |
156 | |
157 reference_build_dir = reference_build_dir.AppendASCII("chrome_frame"); | |
158 reference_build_dir = reference_build_dir.AppendASCII("tools"); | |
159 reference_build_dir = reference_build_dir.AppendASCII("test"); | |
160 reference_build_dir = reference_build_dir.AppendASCII("reference_build"); | |
161 reference_build_dir = reference_build_dir.AppendASCII("chrome"); | |
162 reference_build_dir = reference_build_dir.AppendASCII("servers"); | |
163 reference_build_dir = reference_build_dir.Append(kChromeFrameDllName); | |
164 return reference_build_dir; | |
165 } | |
166 | |
167 // static | |
168 void ScopedChromeFrameRegistrar::RegisterAndExitProcessIfDirected() { | |
169 // This method is invoked before any Chromium helpers have been initialized. | |
170 // Take pains to use only Win32 and CRT functions. | |
171 int argc = 0; | |
172 const wchar_t* const* argv = ::CommandLineToArgvW(::GetCommandLine(), &argc); | |
173 if (argc < 2 || ::lstrcmp(argv[1], kCallRegistrationEntrypointSwitch) != 0) | |
174 return; | |
175 if (argc != 4) { | |
176 printf("Usage: %S %S <path to dll> <entrypoint>\n", argv[0], | |
177 kCallRegistrationEntrypointSwitch); | |
178 return; | |
179 } | |
180 | |
181 // The only way to leave from here on down is ExitProcess. | |
182 const wchar_t* dll_path = argv[2]; | |
183 const wchar_t* wide_entrypoint = argv[3]; | |
184 char entrypoint[256]; | |
185 HRESULT exit_code = 0; | |
186 int entrypoint_len = lstrlen(wide_entrypoint); | |
187 if (entrypoint_len <= 0 || entrypoint_len >= arraysize(entrypoint)) { | |
188 exit_code = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); | |
189 } else { | |
190 // Convert wide to narrow. Since the entrypoint must be a narrow string | |
191 // anyway, it is safe to truncate each character like this. | |
192 std::copy(wide_entrypoint, wide_entrypoint + entrypoint_len + 1, | |
193 &entrypoint[0]); | |
194 HMODULE dll_module = ::LoadLibrary(dll_path); | |
195 if (dll_module == NULL) { | |
196 exit_code = HRESULT_FROM_WIN32(::GetLastError()); | |
197 } else { | |
198 typedef HRESULT (STDAPICALLTYPE *RegisterFp)(); | |
199 RegisterFp register_func = | |
200 reinterpret_cast<RegisterFp>(::GetProcAddress(dll_module, | |
201 entrypoint)); | |
202 if (register_func == NULL) { | |
203 exit_code = HRESULT_FROM_WIN32(::GetLastError()); | |
204 } else { | |
205 exit_code = register_func(); | |
206 } | |
207 ::FreeLibrary(dll_module); | |
208 } | |
209 } | |
210 | |
211 ::ExitProcess(exit_code); | |
212 } | |
213 | |
214 // Non-statics | |
215 | |
216 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( | |
217 const std::wstring& path, RegistrationType registration_type) | |
218 : registration_type_(registration_type) { | |
219 if (!register_chrome_path_provider_) { | |
220 // Register paths needed by the ScopedChromeFrameRegistrar. | |
221 chrome::RegisterPathProvider(); | |
222 register_chrome_path_provider_ = true; | |
223 } | |
224 original_dll_path_ = path; | |
225 RegisterChromeFrameAtPath(original_dll_path_); | |
226 } | |
227 | |
228 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( | |
229 RegistrationType registration_type) | |
230 : registration_type_(registration_type) { | |
231 if (!register_chrome_path_provider_) { | |
232 // Register paths needed by the ScopedChromeFrameRegistrar. | |
233 chrome::RegisterPathProvider(); | |
234 register_chrome_path_provider_ = true; | |
235 } | |
236 original_dll_path_ = GetChromeFrameBuildPath().value(); | |
237 RegisterChromeFrameAtPath(original_dll_path_); | |
238 } | |
239 | |
240 ScopedChromeFrameRegistrar::~ScopedChromeFrameRegistrar() { | |
241 if (base::FilePath(original_dll_path_) != | |
242 base::FilePath(new_chrome_frame_dll_path_)) { | |
243 RegisterChromeFrameAtPath(original_dll_path_); | |
244 } else if (registration_type_ == PER_USER) { | |
245 UnregisterAtPath(new_chrome_frame_dll_path_, registration_type_); | |
246 HWND chrome_frame_helper_window = | |
247 FindWindow(L"ChromeFrameHelperWindowClass", NULL); | |
248 if (IsWindow(chrome_frame_helper_window)) { | |
249 PostMessage(chrome_frame_helper_window, WM_CLOSE, 0, 0); | |
250 } else { | |
251 base::KillProcesses(L"chrome_frame_helper.exe", 0, NULL); | |
252 } | |
253 } | |
254 } | |
255 | |
256 void ScopedChromeFrameRegistrar::RegisterChromeFrameAtPath( | |
257 const std::wstring& path) { | |
258 RegisterAtPath(path, registration_type_); | |
259 new_chrome_frame_dll_path_ = path; | |
260 } | |
261 | |
262 void ScopedChromeFrameRegistrar::RegisterReferenceChromeFrameBuild() { | |
263 RegisterChromeFrameAtPath(GetReferenceChromeFrameDllPath().value()); | |
264 } | |
265 | |
266 std::wstring ScopedChromeFrameRegistrar::GetChromeFrameDllPath() const { | |
267 return new_chrome_frame_dll_path_; | |
268 } | |
269 | |
270 bool IsWorkstationLocked() { | |
271 bool is_locked = true; | |
272 HDESK input_desk = ::OpenInputDesktop(0, 0, GENERIC_READ); | |
273 if (input_desk) { | |
274 wchar_t name[256] = {0}; | |
275 DWORD needed = 0; | |
276 if (::GetUserObjectInformation(input_desk, | |
277 UOI_NAME, | |
278 name, | |
279 sizeof(name), | |
280 &needed)) { | |
281 is_locked = lstrcmpi(name, L"default") != 0; | |
282 } | |
283 ::CloseDesktop(input_desk); | |
284 } | |
285 return is_locked; | |
286 } | |
OLD | NEW |