• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetChromeFrameBuildPath()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
RegisterDefaults()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
DoRegistration(const string16 & path,RegistrationType registration_type,RegistrationOperation registration_operation)73 void ScopedChromeFrameRegistrar::DoRegistration(
74     const 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   string16 registration_command(ASCIIToUTF16("\""));
99   registration_command +=
100       CommandLine::ForCurrentProcess()->GetProgram().value();
101   registration_command += ASCIIToUTF16("\" ");
102   registration_command += kCallRegistrationEntrypointSwitch;
103   registration_command += ASCIIToUTF16(" \"");
104   registration_command += path;
105   registration_command += ASCIIToUTF16("\" ");
106   registration_command += 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
RegisterAtPath(const std::wstring & path,RegistrationType registration_type)139 void ScopedChromeFrameRegistrar::RegisterAtPath(
140     const std::wstring& path, RegistrationType registration_type) {
141   DoRegistration(path, registration_type, REGISTER);
142 }
143 
144 // static
UnregisterAtPath(const std::wstring & path,RegistrationType registration_type)145 void ScopedChromeFrameRegistrar::UnregisterAtPath(
146     const std::wstring& path, RegistrationType registration_type) {
147   DoRegistration(path, registration_type, UNREGISTER);
148 }
149 
GetReferenceChromeFrameDllPath()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
RegisterAndExitProcessIfDirected()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 
ScopedChromeFrameRegistrar(const std::wstring & path,RegistrationType registration_type)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 
ScopedChromeFrameRegistrar(RegistrationType registration_type)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 
~ScopedChromeFrameRegistrar()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 
RegisterChromeFrameAtPath(const std::wstring & path)256 void ScopedChromeFrameRegistrar::RegisterChromeFrameAtPath(
257     const std::wstring& path) {
258   RegisterAtPath(path, registration_type_);
259   new_chrome_frame_dll_path_ = path;
260 }
261 
RegisterReferenceChromeFrameBuild()262 void ScopedChromeFrameRegistrar::RegisterReferenceChromeFrameBuild() {
263   RegisterChromeFrameAtPath(GetReferenceChromeFrameDllPath().value());
264 }
265 
GetChromeFrameDllPath() const266 std::wstring ScopedChromeFrameRegistrar::GetChromeFrameDllPath() const {
267   return new_chrome_frame_dll_path_;
268 }
269 
IsWorkstationLocked()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 }
287