blob: 03391b66d5ab248efbb260b2b38e88ddbec70641 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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
3// found in the LICENSE file.
[email protected]c9349d082008-08-22 21:16:474
[email protected]4512f3ac2009-11-04 03:39:225#include <windows.h>
6#include <shlwapi.h>
[email protected]c9349d082008-08-22 21:16:477
[email protected]4512f3ac2009-11-04 03:39:228#include "chrome/app/breakpad_win.h"
9#include "chrome/app/client_util.h"
10#include "chrome/common/result_codes.h"
[email protected]74d1eec2009-11-04 22:18:5711#include "chrome/installer/util/browser_distribution.h"
[email protected]4512f3ac2009-11-04 03:39:2212#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5713#include "chrome/installer/util/google_update_constants.h"
[email protected]28c19692008-11-07 23:40:3814#include "chrome/installer/util/util_constants.h"
15
16namespace {
[email protected]4512f3ac2009-11-04 03:39:2217// The entry point signature of chrome.dll.
18typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);
[email protected]28c19692008-11-07 23:40:3819
[email protected]4512f3ac2009-11-04 03:39:2220// Not generic, we only handle strings up to 128 chars.
21bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
22 BYTE out[128 * sizeof(wchar_t)];
23 DWORD size = sizeof(out);
24 DWORD type = 0;
25 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
[email protected]28c19692008-11-07 23:40:3826 return false;
[email protected]4512f3ac2009-11-04 03:39:2227 if (type != REG_SZ)
28 return false;
29 value->assign(reinterpret_cast<wchar_t*>(out));
[email protected]28c19692008-11-07 23:40:3830 return true;
31}
[email protected]c9349d082008-08-22 21:16:4732
[email protected]4512f3ac2009-11-04 03:39:2233// Gets chrome version according to the load path. |exe_path| must be the
34// backslash terminated directory of the current chrome.exe.
35bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
36 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3237 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3838 HKEY_LOCAL_MACHINE;
[email protected]4512f3ac2009-11-04 03:39:2239 HKEY key;
40 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
[email protected]c9349d082008-08-22 21:16:4741 return false;
[email protected]28c19692008-11-07 23:40:3842
[email protected]4512f3ac2009-11-04 03:39:2243 // If 'new_chrome.exe' is present it means chrome was auto-updated while
44 // running. We need to consult the opv value so we can load the old dll.
45 // TODO(cpu) : This is solving the same problem as the environment variable
46 // so one of them will eventually be deprecated.
[email protected]28c19692008-11-07 23:40:3847 std::wstring new_chrome_exe(exe_path);
48 new_chrome_exe.append(installer_util::kChromeNewExe);
[email protected]4512f3ac2009-11-04 03:39:2249 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
50 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
51 ::RegCloseKey(key);
[email protected]28c19692008-11-07 23:40:3852 return true;
[email protected]2414e842008-11-07 01:27:5753 }
54
[email protected]4512f3ac2009-11-04 03:39:2255 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
56 ::RegCloseKey(key);
[email protected]c9349d082008-08-22 21:16:4757 return ret;
58}
59
[email protected]4512f3ac2009-11-04 03:39:2260// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2661std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2262 wchar_t path[MAX_PATH];
63 ::GetModuleFileNameW(NULL, path, MAX_PATH);
64 if (!::PathRemoveFileSpecW(path))
65 return std::wstring();
66 std::wstring exe_path(path);
67 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4768}
69
[email protected]4512f3ac2009-11-04 03:39:2270// Not generic, we only handle strings up to 128 chars.
71bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
72 wchar_t out[128];
73 DWORD count = sizeof(out)/sizeof(out[0]);
74 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
75 if ((rv == 0) || (rv >= count))
76 return false;
77 *value = out;
78 return true;
79}
80
81// Expects that |dir| has a trailing backslash. |dir| is modified so it
82// contains the full path that was tried. Caller must check for the return
83// value not being null to dermine if this path contains a valid dll.
84HMODULE LoadChromeWithDirectory(std::wstring* dir) {
85 ::SetCurrentDirectoryW(dir->c_str());
86 dir->append(installer_util::kChromeDll);
87 return ::LoadLibraryExW(dir->c_str(), NULL,
88 LOAD_WITH_ALTERED_SEARCH_PATH);
89}
90
91// record did_run "dr" in client state.
92bool RecordDidRun(const wchar_t* guid) {
93 std::wstring key_path(google_update::kRegPathClientState);
94 key_path.append(L"\\").append(guid);
95 HKEY reg_key;
96 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
97 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
98 &reg_key, NULL) == ERROR_SUCCESS) {
99 const wchar_t kVal[] = L"1";
100 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
101 reinterpret_cast<const BYTE *>(kVal), sizeof(kVal));
102 ::RegCloseKey(reg_key);
103 return true;
104 }
105 return false;
106}
107}
108
109//=============================================================================
110
111MainDllLoader::MainDllLoader() : dll_(NULL) {
112}
113
114MainDllLoader::~MainDllLoader() {
115#ifdef PURIFY
116 // We should never unload the dll. There is only risk and no gain from
117 // doing so. The singleton dtors have been already run by AtExitManager.
118 ::FreeLibrary(dll_);
119#endif
120}
121
122// Loading chrome is an interesting afair. First we try loading from the current
123// directory to support run-what-you-compile and other development scenarios.
124// If that fails then we look at the 'CHROME_VERSION' env variable to determine
125// if we should stick with an older dll version even if a new one is available
126// to support upgrade-in-place scenarios, and if that fails we finally we look
127// at the registry which should point us to the latest version.
128HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
129 std::wstring dir(GetExecutablePath());
130 *file = dir;
131 HMODULE dll = LoadChromeWithDirectory(file);
132 if (dll)
133 return dll;
134
135 if (!EnvQueryStr(google_update::kEnvProductVersionKey, version)) {
136 std::wstring reg_path(GetRegistryPath());
137 // Look into the registry to find the latest version.
138 if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
139 return NULL;
140 }
141
142 *file = dir;
[email protected]f244388d2009-11-04 05:33:28143 file->append(*version).append(L"\\");
[email protected]4512f3ac2009-11-04 03:39:22144 return LoadChromeWithDirectory(file);
145}
146
147// Launching is a matter of loading the right dll, setting the CHROME_VERSION
148// environment variable and just calling the entry point. Derived classes can
149// add custom code in the OnBeforeLaunch callback.
150int MainDllLoader::Launch(HINSTANCE instance,
151 sandbox::SandboxInterfaceInfo* sbox_info) {
152 std::wstring version;
153 std::wstring file;
154 dll_ = Load(&version, &file);
155 if (!dll_)
156 return ResultCodes::MISSING_DATA;
157
158 ::SetEnvironmentVariableW(google_update::kEnvProductVersionKey,
159 version.c_str());
160
161 InitCrashReporterWithDllPath(file);
162
163 OnBeforeLaunch(version);
164
165 DLL_MAIN entry_point =
166 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
167 if (!entry_point)
168 return ResultCodes::BAD_PROCESS_TYPE;
169
170 return entry_point(instance, sbox_info, ::GetCommandLineW());
171}
172
173//=============================================================================
174
175class ChromeDllLoader : public MainDllLoader {
176 public:
177 virtual std::wstring GetRegistryPath() {
178 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48179 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
180 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22181 return key;
182 }
183
184 virtual void OnBeforeLaunch(const std::wstring& version) {
[email protected]5f2cee82009-11-05 04:59:48185 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
186 RecordDidRun(dist->GetAppGuid().c_str());
[email protected]4512f3ac2009-11-04 03:39:22187 }
188};
189
190//=============================================================================
191
192class ChromiumDllLoader : public MainDllLoader {
193 public:
194 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57195 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
196 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22197 }
198};
199
200MainDllLoader* MakeMainDllLoader() {
201#if defined(GOOGLE_CHROME_BUILD)
202 return new ChromeDllLoader();
203#else
204 return new ChromiumDllLoader();
205#endif
206}