OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <algorithm> | |
6 | |
7 #include "chrome_frame/test_utils.h" | 5 #include "chrome_frame/test_utils.h" |
8 | 6 |
9 #include <atlbase.h> | 7 #include <atlbase.h> |
10 #include <atlwin.h> | 8 #include <atlwin.h> |
9 #include <shellapi.h> | |
11 #include <winternl.h> | 10 #include <winternl.h> |
12 | 11 |
12 #include <algorithm> | |
13 | |
14 #include "base/command_line.h" | |
13 #include "base/file_path.h" | 15 #include "base/file_path.h" |
14 #include "base/file_util.h" | 16 #include "base/file_util.h" |
15 #include "base/logging.h" | 17 #include "base/logging.h" |
16 #include "base/path_service.h" | 18 #include "base/path_service.h" |
17 #include "base/process_util.h" | 19 #include "base/process_util.h" |
18 #include "base/string_util.h" | 20 #include "base/string_util.h" |
21 #include "base/stringprintf.h" | |
22 #include "base/utf_string_conversions.h" | |
19 #include "base/win/scoped_handle.h" | 23 #include "base/win/scoped_handle.h" |
20 #include "chrome/common/chrome_paths.h" | 24 #include "chrome/common/chrome_paths.h" |
21 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
22 #include "chrome_frame/test/chrome_frame_test_utils.h" | 26 #include "chrome_frame/test/chrome_frame_test_utils.h" |
23 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
24 | 28 |
25 const wchar_t kChromeFrameDllName[] = L"npchrome_frame.dll"; | 29 const wchar_t kChromeFrameDllName[] = L"npchrome_frame.dll"; |
26 const wchar_t kChromeLauncherExeName[] = L"chrome_launcher.exe"; | 30 const wchar_t kChromeLauncherExeName[] = L"chrome_launcher.exe"; |
31 // How long to wait for DLLs to register or unregister themselves before killing | |
32 // the registrar. | |
33 const int64 kDllRegistrationTimeoutMs = 30 * 1000; | |
27 | 34 |
28 FilePath GetChromeFrameBuildPath() { | 35 FilePath GetChromeFrameBuildPath() { |
29 FilePath build_path; | 36 FilePath build_path; |
30 PathService::Get(chrome::DIR_APP, &build_path); | 37 PathService::Get(chrome::DIR_APP, &build_path); |
31 | 38 |
32 FilePath dll_path = build_path.Append(kChromeFrameDllName); | 39 FilePath dll_path = build_path.Append(kChromeFrameDllName); |
33 | 40 |
34 if (!file_util::PathExists(dll_path)) { | 41 if (!file_util::PathExists(dll_path)) { |
35 // Well, dang.. try looking in the current directory. | 42 // Well, dang.. try looking in the current directory. |
36 dll_path = build_path.Append(kChromeFrameDllName); | 43 dll_path = build_path.Append(kChromeFrameDllName); |
37 } | 44 } |
38 | 45 |
39 if (!file_util::PathExists(dll_path)) { | 46 if (!file_util::PathExists(dll_path)) { |
40 // No luck, return something empty. | 47 // No luck, return something empty. |
41 dll_path = FilePath(); | 48 dll_path = FilePath(); |
42 } | 49 } |
43 | 50 |
44 return dll_path; | 51 return dll_path; |
45 } | 52 } |
46 | 53 |
54 const wchar_t ScopedChromeFrameRegistrar::kCallRegistrationEntrypointSwitch[] = | |
55 L"--call-registration-entrypoint"; | |
56 | |
47 bool ScopedChromeFrameRegistrar::register_chrome_path_provider_ = false; | 57 bool ScopedChromeFrameRegistrar::register_chrome_path_provider_ = false; |
48 | 58 |
49 // static | 59 // static |
50 void ScopedChromeFrameRegistrar::RegisterDefaults() { | 60 void ScopedChromeFrameRegistrar::RegisterDefaults() { |
51 if (!register_chrome_path_provider_) { | 61 if (!register_chrome_path_provider_) { |
52 chrome::RegisterPathProvider(); | 62 chrome::RegisterPathProvider(); |
53 register_chrome_path_provider_ = true; | 63 register_chrome_path_provider_ = true; |
54 } | 64 } |
55 } | 65 } |
56 | 66 |
67 // Registers or unregisters the DLL at |path| by calling out to the current | |
68 // executable with --call-registration-entrypoint. Loading the DLL into the | |
69 // test process is problematic for component=shared_library builds since | |
70 // singletons in base.dll aren't designed to handle multiple initialization. | |
71 // Use of rundll32.exe is problematic since it does not return useful error | |
72 // information. | |
73 // static | |
74 void ScopedChromeFrameRegistrar::DoRegistration( | |
75 const string16& path, | |
76 RegistrationType registration_type, | |
77 RegistrationOperation registration_operation) { | |
78 static const char* const kEntrypoints[] = { | |
79 "DllRegisterServer", | |
80 "DllUnregisterServer", | |
81 "DllRegisterUserServer", | |
82 "DllUnregisterUserServer", | |
83 }; | |
84 | |
85 DCHECK(!path.empty()); | |
86 DCHECK(registration_type == PER_USER || registration_type == SYSTEM_LEVEL); | |
87 DCHECK(registration_operation == REGISTER || | |
88 registration_operation == UNREGISTER); | |
89 | |
90 int entrypoint_index = 0; | |
91 base::LaunchOptions launch_options; | |
92 base::ProcessHandle process_handle = INVALID_HANDLE_VALUE; | |
93 int exit_code = -1; | |
94 | |
95 if (registration_type == PER_USER) | |
96 entrypoint_index += 2; | |
97 if (registration_operation == UNREGISTER) | |
98 entrypoint_index += 1; | |
99 string16 registration_command(ASCIIToUTF16("\"")); | |
100 registration_command += | |
101 CommandLine::ForCurrentProcess()->GetProgram().value(); | |
102 registration_command += ASCIIToUTF16("\" "); | |
103 registration_command += kCallRegistrationEntrypointSwitch; | |
104 registration_command += ASCIIToUTF16(" \""); | |
105 registration_command += path; | |
106 registration_command += ASCIIToUTF16("\" "); | |
107 registration_command += ASCIIToUTF16(kEntrypoints[entrypoint_index]); | |
108 launch_options.wait = true; | |
109 if (!base::LaunchProcess(registration_command, launch_options, | |
110 &process_handle)) { | |
111 PLOG(FATAL) | |
112 << "Failed to register or unregister DLL with command: " | |
113 << registration_command; | |
114 } else { | |
115 base::win::ScopedHandle rundll32(process_handle); | |
116 if (!base::WaitForExitCodeWithTimeout(process_handle, &exit_code, | |
117 kDllRegistrationTimeoutMs)) { | |
118 LOG(ERROR) << "Timeout waiting to register or unregister DLL with " | |
119 "command: " << registration_command; | |
120 base::KillProcess(process_handle, 0, false); | |
121 NOTREACHED() << "Aborting test due to registration failure."; | |
122 } | |
123 } | |
124 if (exit_code != 0) { | |
125 if (registration_operation == REGISTER) { | |
126 LOG(FATAL) | |
127 << "DLL registration failed (exit code: 0x" << std::hex << exit_code | |
128 << ", command: " << registration_command | |
129 << "). Are you running as Admin?"; | |
robertshield
2012/01/24 22:40:01
"Are you" -> "Make sure"
grt (UTC plus 2)
2012/01/25 02:46:37
Done.
| |
130 } else { | |
131 LOG(WARNING) | |
132 << "DLL unregistration failed (exit code: 0x" << std::hex << exit_code | |
133 << ", command: " << registration_command << ")."; | |
134 } | |
135 } | |
136 } | |
137 | |
57 // static | 138 // static |
58 void ScopedChromeFrameRegistrar::RegisterAtPath( | 139 void ScopedChromeFrameRegistrar::RegisterAtPath( |
59 const std::wstring& path, RegistrationType registration_type) { | 140 const std::wstring& path, RegistrationType registration_type) { |
60 | 141 DoRegistration(path, registration_type, REGISTER); |
61 ASSERT_FALSE(path.empty()); | |
62 HMODULE dll_handle = LoadLibrary(path.c_str()); | |
63 ASSERT_TRUE(dll_handle != NULL) << "Failed to load " << path | |
64 << " , gle = " << GetLastError(); | |
65 | |
66 typedef HRESULT (STDAPICALLTYPE* DllRegisterServerFn)(); | |
67 DllRegisterServerFn register_server = NULL; | |
68 | |
69 if (registration_type == PER_USER) { | |
70 register_server = reinterpret_cast<DllRegisterServerFn>(GetProcAddress( | |
71 dll_handle, "DllRegisterUserServer")); | |
72 } else { | |
73 register_server = reinterpret_cast<DllRegisterServerFn>(GetProcAddress( | |
74 dll_handle, "DllRegisterServer")); | |
75 } | |
76 ASSERT_TRUE(register_server != NULL); | |
77 HRESULT reg_result = (*register_server)(); | |
78 ASSERT_TRUE(FreeLibrary(dll_handle)); | |
79 | |
80 // Assert here after the FreeLibrary since otherwise we hit a | |
81 // multiple AtExitMananger crash for modules that use base. | |
82 ASSERT_HRESULT_SUCCEEDED(reg_result) << "Failed to register DLL at " | |
83 << path | |
84 << " , are you running as Admin?"; | |
85 } | 142 } |
86 | 143 |
87 // static | 144 // static |
88 void ScopedChromeFrameRegistrar::UnregisterAtPath( | 145 void ScopedChromeFrameRegistrar::UnregisterAtPath( |
89 const std::wstring& path, RegistrationType registration_type) { | 146 const std::wstring& path, RegistrationType registration_type) { |
90 | 147 DoRegistration(path, registration_type, UNREGISTER); |
91 ASSERT_FALSE(path.empty()); | |
92 HMODULE dll_handle = LoadLibrary(path.c_str()); | |
93 ASSERT_TRUE(dll_handle != NULL); | |
94 | |
95 typedef HRESULT (STDAPICALLTYPE* DllUnregisterServerFn)(); | |
96 DllUnregisterServerFn unregister_server = NULL; | |
97 if (registration_type == PER_USER) { | |
98 unregister_server = reinterpret_cast<DllUnregisterServerFn> | |
99 (GetProcAddress(dll_handle, "DllUnregisterUserServer")); | |
100 } else { | |
101 unregister_server = reinterpret_cast<DllUnregisterServerFn> | |
102 (GetProcAddress(dll_handle, "DllUnregisterServer")); | |
103 } | |
104 ASSERT_TRUE(unregister_server != NULL); | |
105 EXPECT_HRESULT_SUCCEEDED((*unregister_server)()); | |
106 | |
107 ASSERT_TRUE(FreeLibrary(dll_handle)); | |
108 } | 148 } |
109 | 149 |
110 FilePath ScopedChromeFrameRegistrar::GetReferenceChromeFrameDllPath() { | 150 FilePath ScopedChromeFrameRegistrar::GetReferenceChromeFrameDllPath() { |
111 FilePath reference_build_dir; | 151 FilePath reference_build_dir; |
112 PathService::Get(chrome::DIR_APP, &reference_build_dir); | 152 PathService::Get(chrome::DIR_APP, &reference_build_dir); |
113 | 153 |
114 reference_build_dir = reference_build_dir.DirName(); | 154 reference_build_dir = reference_build_dir.DirName(); |
115 reference_build_dir = reference_build_dir.DirName(); | 155 reference_build_dir = reference_build_dir.DirName(); |
116 | 156 |
117 reference_build_dir = reference_build_dir.AppendASCII("chrome_frame"); | 157 reference_build_dir = reference_build_dir.AppendASCII("chrome_frame"); |
118 reference_build_dir = reference_build_dir.AppendASCII("tools"); | 158 reference_build_dir = reference_build_dir.AppendASCII("tools"); |
119 reference_build_dir = reference_build_dir.AppendASCII("test"); | 159 reference_build_dir = reference_build_dir.AppendASCII("test"); |
120 reference_build_dir = reference_build_dir.AppendASCII("reference_build"); | 160 reference_build_dir = reference_build_dir.AppendASCII("reference_build"); |
121 reference_build_dir = reference_build_dir.AppendASCII("chrome"); | 161 reference_build_dir = reference_build_dir.AppendASCII("chrome"); |
122 reference_build_dir = reference_build_dir.AppendASCII("servers"); | 162 reference_build_dir = reference_build_dir.AppendASCII("servers"); |
123 reference_build_dir = reference_build_dir.Append(kChromeFrameDllName); | 163 reference_build_dir = reference_build_dir.Append(kChromeFrameDllName); |
124 return reference_build_dir; | 164 return reference_build_dir; |
125 } | 165 } |
126 | 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; | |
robertshield
2012/01/24 22:40:01
= 0
grt (UTC plus 2)
2012/01/25 02:46:37
Done.
| |
172 const wchar_t* const* argv = ::CommandLineToArgvW(::GetCommandLine(), &argc); | |
173 if (argc != 4 || ::lstrcmp(argv[1], kCallRegistrationEntrypointSwitch) != 0) | |
robertshield
2012/01/24 22:40:01
I wonder if this should printf() a usage string an
grt (UTC plus 2)
2012/01/25 02:46:37
Done.
| |
174 return; | |
175 | |
176 // The only way to leave from here on down is ExitProcess. | |
177 const wchar_t* dll_path = argv[2]; | |
178 const wchar_t* wide_entrypoint = argv[3]; | |
179 char entrypoint[256]; | |
180 HRESULT exit_code = 0; | |
181 int entrypoint_len = lstrlen(wide_entrypoint); | |
182 if (entrypoint_len <= 0 || entrypoint_len >= arraysize(entrypoint)) { | |
183 exit_code = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); | |
184 } else { | |
185 std::copy(wide_entrypoint, wide_entrypoint + entrypoint_len + 1, | |
186 &entrypoint[0]); | |
robertshield
2012/01/24 22:40:01
Maybe a brief comment explaining that this does th
grt (UTC plus 2)
2012/01/25 02:46:37
Done.
| |
187 HMODULE dll_module = ::LoadLibrary(dll_path); | |
188 if (dll_module == NULL) { | |
189 exit_code = HRESULT_FROM_WIN32(::GetLastError()); | |
190 } else { | |
191 typedef HRESULT (STDAPICALLTYPE *RegisterFp)(); | |
192 RegisterFp register_func = | |
193 reinterpret_cast<RegisterFp>(::GetProcAddress(dll_module, | |
194 entrypoint)); | |
195 if (register_func == NULL) { | |
196 exit_code = HRESULT_FROM_WIN32(::GetLastError()); | |
197 } else { | |
198 exit_code = register_func(); | |
199 } | |
200 ::FreeLibrary(dll_module); | |
201 } | |
202 } | |
203 | |
204 ::ExitProcess(exit_code); | |
205 } | |
206 | |
127 // Non-statics | 207 // Non-statics |
128 | 208 |
129 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( | 209 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( |
130 const std::wstring& path, RegistrationType registration_type) | 210 const std::wstring& path, RegistrationType registration_type) |
131 : registration_type_(registration_type) { | 211 : registration_type_(registration_type) { |
132 if (!register_chrome_path_provider_) { | 212 if (!register_chrome_path_provider_) { |
133 // Register paths needed by the ScopedChromeFrameRegistrar. | 213 // Register paths needed by the ScopedChromeFrameRegistrar. |
134 chrome::RegisterPathProvider(); | 214 chrome::RegisterPathProvider(); |
135 register_chrome_path_provider_ = true; | 215 register_chrome_path_provider_ = true; |
136 } | 216 } |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
345 UOI_NAME, | 425 UOI_NAME, |
346 name, | 426 name, |
347 sizeof(name), | 427 sizeof(name), |
348 &needed)) { | 428 &needed)) { |
349 is_locked = lstrcmpi(name, L"default") != 0; | 429 is_locked = lstrcmpi(name, L"default") != 0; |
350 } | 430 } |
351 ::CloseDesktop(input_desk); | 431 ::CloseDesktop(input_desk); |
352 } | 432 } |
353 return is_locked; | 433 return is_locked; |
354 } | 434 } |
OLD | NEW |