Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: chrome_frame/test_utils.cc

Issue 9146054: Spawn a new process to register and unregister DLLs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updated error handling Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome_frame/test_utils.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « chrome_frame/test_utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698