| 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 |