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 << "). Make sure you are running as Admin."; |
| 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 = 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 |
127 // Non-statics | 214 // Non-statics |
128 | 215 |
129 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( | 216 ScopedChromeFrameRegistrar::ScopedChromeFrameRegistrar( |
130 const std::wstring& path, RegistrationType registration_type) | 217 const std::wstring& path, RegistrationType registration_type) |
131 : registration_type_(registration_type) { | 218 : registration_type_(registration_type) { |
132 if (!register_chrome_path_provider_) { | 219 if (!register_chrome_path_provider_) { |
133 // Register paths needed by the ScopedChromeFrameRegistrar. | 220 // Register paths needed by the ScopedChromeFrameRegistrar. |
134 chrome::RegisterPathProvider(); | 221 chrome::RegisterPathProvider(); |
135 register_chrome_path_provider_ = true; | 222 register_chrome_path_provider_ = true; |
136 } | 223 } |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 UOI_NAME, | 432 UOI_NAME, |
346 name, | 433 name, |
347 sizeof(name), | 434 sizeof(name), |
348 &needed)) { | 435 &needed)) { |
349 is_locked = lstrcmpi(name, L"default") != 0; | 436 is_locked = lstrcmpi(name, L"default") != 0; |
350 } | 437 } |
351 ::CloseDesktop(input_desk); | 438 ::CloseDesktop(input_desk); |
352 } | 439 } |
353 return is_locked; | 440 return is_locked; |
354 } | 441 } |
OLD | NEW |