OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 <windows.h> |
| 6 #include <shlwapi.h> |
| 7 |
| 8 #include "chrome/app/breakpad_win.h" |
5 #include "chrome/app/client_util.h" | 9 #include "chrome/app/client_util.h" |
| 10 #include "chrome/common/result_codes.h" |
6 #include "chrome/installer/util/install_util.h" | 11 #include "chrome/installer/util/install_util.h" |
7 | |
8 #include "chrome/installer/util/google_update_constants.h" | 12 #include "chrome/installer/util/google_update_constants.h" |
9 #include "chrome/installer/util/util_constants.h" | 13 #include "chrome/installer/util/util_constants.h" |
10 | 14 |
11 namespace { | 15 namespace { |
12 bool ReadStrValueFromRegistry(const HKEY reg_key, | 16 // The entry point signature of chrome.dll. |
13 const wchar_t* const value_name, | 17 typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*); |
14 wchar_t** value) { | 18 |
15 DWORD size = 0; | 19 // Not generic, we only handle strings up to 128 chars. |
16 if (::RegQueryValueEx(reg_key, value_name, NULL, NULL, NULL, | 20 bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) { |
17 &size) != ERROR_SUCCESS) { | 21 BYTE out[128 * sizeof(wchar_t)]; |
18 return false; | 22 DWORD size = sizeof(out); |
19 } | 23 DWORD type = 0; |
20 | 24 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size)) |
21 *value = new wchar_t[1 + (size / sizeof(wchar_t))]; | 25 return false; |
22 if (::RegQueryValueEx(reg_key, value_name, NULL, NULL, | 26 if (type != REG_SZ) |
23 reinterpret_cast<BYTE*>(*value), | 27 return false; |
24 &size) != ERROR_SUCCESS) { | 28 value->assign(reinterpret_cast<wchar_t*>(out)); |
25 delete[] *value; | |
26 return false; | |
27 } | |
28 | |
29 return true; | 29 return true; |
30 } | 30 } |
31 } | 31 |
32 | 32 // Gets chrome version according to the load path. |exe_path| must be the |
33 namespace client_util { | 33 // backslash terminated directory of the current chrome.exe. |
34 bool FileExists(const std::wstring& file_path) { | 34 bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path, |
35 WIN32_FILE_ATTRIBUTE_DATA attrs; | 35 std::wstring* version) { |
36 return ::GetFileAttributesEx( | |
37 file_path.c_str(), GetFileExInfoStandard, &attrs) != 0; | |
38 } | |
39 | |
40 bool GetChromiumVersion(const wchar_t* const exe_path, | |
41 const wchar_t* const reg_key_path, | |
42 wchar_t** version) { | |
43 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER : | 36 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER : |
44 HKEY_LOCAL_MACHINE; | 37 HKEY_LOCAL_MACHINE; |
45 HKEY reg_key; | 38 HKEY key; |
46 if (::RegOpenKeyEx(reg_root, reg_key_path, 0, | 39 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS) |
47 KEY_READ, ®_key) != ERROR_SUCCESS) { | 40 return false; |
48 return false; | 41 |
49 } | 42 // If 'new_chrome.exe' is present it means chrome was auto-updated while |
50 | 43 // running. We need to consult the opv value so we can load the old dll. |
| 44 // TODO(cpu) : This is solving the same problem as the environment variable |
| 45 // so one of them will eventually be deprecated. |
51 std::wstring new_chrome_exe(exe_path); | 46 std::wstring new_chrome_exe(exe_path); |
52 new_chrome_exe.append(installer_util::kChromeNewExe); | 47 new_chrome_exe.append(installer_util::kChromeNewExe); |
53 if (FileExists(new_chrome_exe) && | 48 if (::PathFileExistsW(new_chrome_exe.c_str()) && |
54 ReadStrValueFromRegistry(reg_key, google_update::kRegOldVersionField, | 49 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) { |
55 version)) { | 50 ::RegCloseKey(key); |
| 51 return true; |
| 52 } |
| 53 |
| 54 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version); |
| 55 ::RegCloseKey(key); |
| 56 return ret; |
| 57 } |
| 58 |
| 59 // Gets the path of the current exe with a trailing backslash. |
| 60 std::wstring GetExecutablePath() { |
| 61 wchar_t path[MAX_PATH]; |
| 62 ::GetModuleFileNameW(NULL, path, MAX_PATH); |
| 63 if (!::PathRemoveFileSpecW(path)) |
| 64 return std::wstring(); |
| 65 std::wstring exe_path(path); |
| 66 return exe_path.append(L"\\"); |
| 67 } |
| 68 |
| 69 // Not generic, we only handle strings up to 128 chars. |
| 70 bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { |
| 71 wchar_t out[128]; |
| 72 DWORD count = sizeof(out)/sizeof(out[0]); |
| 73 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count); |
| 74 if ((rv == 0) || (rv >= count)) |
| 75 return false; |
| 76 *value = out; |
| 77 return true; |
| 78 } |
| 79 |
| 80 // Expects that |dir| has a trailing backslash. |dir| is modified so it |
| 81 // contains the full path that was tried. Caller must check for the return |
| 82 // value not being null to dermine if this path contains a valid dll. |
| 83 HMODULE LoadChromeWithDirectory(std::wstring* dir) { |
| 84 ::SetCurrentDirectoryW(dir->c_str()); |
| 85 dir->append(installer_util::kChromeDll); |
| 86 return ::LoadLibraryExW(dir->c_str(), NULL, |
| 87 LOAD_WITH_ALTERED_SEARCH_PATH); |
| 88 } |
| 89 |
| 90 // record did_run "dr" in client state. |
| 91 bool RecordDidRun(const wchar_t* guid) { |
| 92 std::wstring key_path(google_update::kRegPathClientState); |
| 93 key_path.append(L"\\").append(guid); |
| 94 HKEY reg_key; |
| 95 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL, |
| 96 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, |
| 97 ®_key, NULL) == ERROR_SUCCESS) { |
| 98 const wchar_t kVal[] = L"1"; |
| 99 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ, |
| 100 reinterpret_cast<const BYTE *>(kVal), sizeof(kVal)); |
56 ::RegCloseKey(reg_key); | 101 ::RegCloseKey(reg_key); |
57 return true; | 102 return true; |
58 } | 103 } |
59 | 104 return false; |
60 bool ret = ReadStrValueFromRegistry(reg_key, | 105 } |
61 google_update::kRegVersionField, | 106 } |
62 version); | 107 |
63 ::RegCloseKey(reg_key); | 108 //============================================================================= |
64 return ret; | 109 |
65 } | 110 MainDllLoader::MainDllLoader() : dll_(NULL) { |
66 | 111 } |
67 std::wstring GetDLLPath(const std::wstring& dll_name, | 112 |
68 const std::wstring& dll_path) { | 113 MainDllLoader::~MainDllLoader() { |
69 if (!dll_path.empty() && FileExists(dll_path)) | 114 #ifdef PURIFY |
70 return dll_path + L"\\" + dll_name; | 115 // We should never unload the dll. There is only risk and no gain from |
71 | 116 // doing so. The singleton dtors have been already run by AtExitManager. |
72 // This is not an official build. Find the dll using the default | 117 ::FreeLibrary(dll_); |
73 // path order in LoadLibrary. | 118 #endif |
74 wchar_t path[MAX_PATH] = {0}; | 119 } |
75 wchar_t* file_part = NULL; | 120 |
76 DWORD result = ::SearchPath(NULL, dll_name.c_str(), NULL, MAX_PATH, | 121 // Loading chrome is an interesting afair. First we try loading from the current |
77 path, &file_part); | 122 // directory to support run-what-you-compile and other development scenarios. |
78 if (result == 0 || result > MAX_PATH) | 123 // If that fails then we look at the 'CHROME_VERSION' env variable to determine |
79 return std::wstring(); | 124 // if we should stick with an older dll version even if a new one is available |
80 | 125 // to support upgrade-in-place scenarios, and if that fails we finally we look |
81 return path; | 126 // at the registry which should point us to the latest version. |
82 } | 127 HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) { |
83 | 128 std::wstring dir(GetExecutablePath()); |
84 std::wstring GetExecutablePath() { | 129 *file = dir; |
85 wchar_t exe_path[MAX_PATH]; | 130 HMODULE dll = LoadChromeWithDirectory(file); |
86 DWORD len = ::GetModuleFileName(NULL, exe_path, MAX_PATH); | 131 if (dll) |
87 wchar_t* tmp = exe_path + len - 1; | 132 return dll; |
88 while (tmp >= exe_path && *tmp != L'\\') | 133 |
89 tmp--; | 134 if (!EnvQueryStr(google_update::kEnvProductVersionKey, version)) { |
90 if (tmp > exe_path) { | 135 std::wstring reg_path(GetRegistryPath()); |
91 tmp++; | 136 // Look into the registry to find the latest version. |
92 *tmp = 0; | 137 if (!GetVersion(dir.c_str(), reg_path.c_str(), version)) |
93 } | 138 return NULL; |
94 return exe_path; | 139 } |
95 } | 140 |
96 | 141 *file = dir; |
97 } // namespace client_util | 142 file->append(*version); |
| 143 return LoadChromeWithDirectory(file); |
| 144 } |
| 145 |
| 146 // Launching is a matter of loading the right dll, setting the CHROME_VERSION |
| 147 // environment variable and just calling the entry point. Derived classes can |
| 148 // add custom code in the OnBeforeLaunch callback. |
| 149 int MainDllLoader::Launch(HINSTANCE instance, |
| 150 sandbox::SandboxInterfaceInfo* sbox_info) { |
| 151 std::wstring version; |
| 152 std::wstring file; |
| 153 dll_ = Load(&version, &file); |
| 154 if (!dll_) |
| 155 return ResultCodes::MISSING_DATA; |
| 156 |
| 157 ::SetEnvironmentVariableW(google_update::kEnvProductVersionKey, |
| 158 version.c_str()); |
| 159 |
| 160 InitCrashReporterWithDllPath(file); |
| 161 |
| 162 OnBeforeLaunch(version); |
| 163 |
| 164 DLL_MAIN entry_point = |
| 165 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain")); |
| 166 if (!entry_point) |
| 167 return ResultCodes::BAD_PROCESS_TYPE; |
| 168 |
| 169 return entry_point(instance, sbox_info, ::GetCommandLineW()); |
| 170 } |
| 171 |
| 172 //============================================================================= |
| 173 |
| 174 class ChromeDllLoader : public MainDllLoader { |
| 175 public: |
| 176 virtual std::wstring GetRegistryPath() { |
| 177 std::wstring key(google_update::kRegPathClients); |
| 178 key.append(L"\\").append(google_update::kChromeGuid); |
| 179 return key; |
| 180 } |
| 181 |
| 182 virtual void OnBeforeLaunch(const std::wstring& version) { |
| 183 RecordDidRun(google_update::kChromeGuid); |
| 184 } |
| 185 }; |
| 186 |
| 187 //============================================================================= |
| 188 |
| 189 class ChromiumDllLoader : public MainDllLoader { |
| 190 public: |
| 191 virtual std::wstring GetRegistryPath() { |
| 192 return L"Software\\Chromium"; |
| 193 } |
| 194 }; |
| 195 |
| 196 MainDllLoader* MakeMainDllLoader() { |
| 197 #if defined(GOOGLE_CHROME_BUILD) |
| 198 return new ChromeDllLoader(); |
| 199 #else |
| 200 return new ChromiumDllLoader(); |
| 201 #endif |
| 202 } |
OLD | NEW |