Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 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 "chrome/browser/process_singleton.h" | 5 #include "chrome/browser/process_singleton.h" |
| 6 | 6 |
| 7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
| 11 #include "base/process_util.h" | 11 #include "base/process_util.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "base/win/scoped_handle.h" | 13 #include "base/win/scoped_handle.h" |
| 14 #include "base/win/wrapped_window_proc.h" | 14 #include "base/win/wrapped_window_proc.h" |
| 15 #include "chrome/browser/ui/simple_message_box.h" | 15 #include "chrome/browser/ui/simple_message_box.h" |
| 16 #include "chrome/common/chrome_constants.h" | 16 #include "chrome/common/chrome_constants.h" |
| 17 #include "chrome/installer/util/wmi.h" | 17 #include "chrome/installer/util/wmi.h" |
| 18 #include "content/public/common/result_codes.h" | 18 #include "content/public/common/result_codes.h" |
| 19 #include "grit/chromium_strings.h" | 19 #include "grit/chromium_strings.h" |
| 20 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
| 21 #include "ui/base/l10n/l10n_util.h" | 21 #include "ui/base/l10n/l10n_util.h" |
| 22 #include "ui/base/win/hwnd_util.h" | 22 #include "ui/base/win/hwnd_util.h" |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 const char kLockfile[] = "lockfile"; | |
| 27 | |
| 26 // Checks the visibility of the enumerated window and signals once a visible | 28 // Checks the visibility of the enumerated window and signals once a visible |
| 27 // window has been found. | 29 // window has been found. |
| 28 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { | 30 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { |
| 29 bool* result = reinterpret_cast<bool*>(param); | 31 bool* result = reinterpret_cast<bool*>(param); |
| 30 *result = IsWindowVisible(window) != 0; | 32 *result = IsWindowVisible(window) != 0; |
| 31 // Stops enumeration if a visible window has been found. | 33 // Stops enumeration if a visible window has been found. |
| 32 return !*result; | 34 return !*result; |
| 33 } | 35 } |
| 34 | 36 |
| 35 // This function thunks to the object's version of the windowproc, taking in | 37 // This function thunks to the object's version of the windowproc, taking in |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 return true; | 143 return true; |
| 142 } | 144 } |
| 143 return false; | 145 return false; |
| 144 } | 146 } |
| 145 | 147 |
| 146 // Look for a Chrome instance that uses the same profile directory. | 148 // Look for a Chrome instance that uses the same profile directory. |
| 147 // If there isn't one, create a message window with its title set to | 149 // If there isn't one, create a message window with its title set to |
| 148 // the profile directory path. | 150 // the profile directory path. |
| 149 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) | 151 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) |
| 150 : window_(NULL), locked_(false), foreground_window_(NULL), | 152 : window_(NULL), locked_(false), foreground_window_(NULL), |
| 151 is_virtualized_(false) { | 153 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE) { |
| 152 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 154 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
| 153 chrome::kMessageWindowClass, | 155 chrome::kMessageWindowClass, |
| 154 user_data_dir.value().c_str()); | 156 user_data_dir.value().c_str()); |
| 155 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { | 157 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { |
| 156 // Make sure we will be the one and only process creating the window. | 158 // Make sure we will be the one and only process creating the window. |
| 157 // We use a named Mutex since we are protecting against multi-process | 159 // We use a named Mutex since we are protecting against multi-process |
| 158 // access. As documented, it's clearer to NOT request ownership on creation | 160 // access. As documented, it's clearer to NOT request ownership on creation |
| 159 // since it isn't guaranteed we will get it. It is better to create it | 161 // since it isn't guaranteed we will get it. It is better to create it |
| 160 // without ownership and explicitly get the ownership afterward. | 162 // without ownership and explicitly get the ownership afterward. |
| 161 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); | 163 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); |
| 162 base::win::ScopedHandle only_me( | 164 base::win::ScopedHandle only_me( |
| 163 CreateMutex(NULL, FALSE, mutex_name.c_str())); | 165 CreateMutex(NULL, FALSE, mutex_name.c_str())); |
| 164 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); | 166 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); |
| 165 | 167 |
| 166 // This is how we acquire the mutex (as opposed to the initial ownership). | 168 // This is how we acquire the mutex (as opposed to the initial ownership). |
| 167 DWORD result = WaitForSingleObject(only_me, INFINITE); | 169 DWORD result = WaitForSingleObject(only_me, INFINITE); |
| 168 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << | 170 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << |
| 169 "GetLastError = " << GetLastError(); | 171 "GetLastError = " << GetLastError(); |
| 170 | 172 |
| 171 // We now own the mutex so we are the only process that can create the | 173 // We now own the mutex so we are the only process that can create the |
| 172 // window at this time, but we must still check if someone created it | 174 // window at this time, but we must still check if someone created it |
| 173 // between the time where we looked for it above and the time the mutex | 175 // between the time where we looked for it above and the time the mutex |
| 174 // was given to us. | 176 // was given to us. |
| 175 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | 177 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, |
| 176 chrome::kMessageWindowClass, | 178 chrome::kMessageWindowClass, |
| 177 user_data_dir.value().c_str()); | 179 user_data_dir.value().c_str()); |
| 178 if (!remote_window_) { | 180 |
| 181 // We have to make sure there is no Chrome instance running on another | |
| 182 // machine that uses the same profile. | |
| 183 FilePath lock_file_path = user_data_dir.AppendASCII(kLockfile); | |
| 184 lock_file_ = CreateFile(lock_file_path.value().c_str(), | |
| 185 GENERIC_WRITE, | |
| 186 FILE_SHARE_READ, | |
| 187 NULL, | |
| 188 CREATE_ALWAYS, | |
| 189 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, | |
| 190 NULL); | |
| 191 DWORD error = GetLastError(); | |
|
cpu_(ooo_6.6-7.5)
2012/07/16 20:36:31
this version I like better. Now for two local chro
pastarmovj
2012/07/16 21:17:53
For two local instances the first one will acquire
| |
| 192 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && | |
| 193 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; | |
| 194 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) | |
| 195 << "Lock file can not be created! Error code: " << error; | |
| 196 | |
| 197 if (!remote_window_ && lock_file_ != INVALID_HANDLE_VALUE) { | |
| 179 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | 198 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); |
| 180 | 199 |
| 181 WNDCLASSEX wc = {0}; | 200 WNDCLASSEX wc = {0}; |
| 182 wc.cbSize = sizeof(wc); | 201 wc.cbSize = sizeof(wc); |
| 183 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | 202 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; |
| 184 wc.hInstance = hinst; | 203 wc.hInstance = hinst; |
| 185 wc.lpszClassName = chrome::kMessageWindowClass; | 204 wc.lpszClassName = chrome::kMessageWindowClass; |
| 186 ATOM clazz = ::RegisterClassEx(&wc); | 205 ATOM clazz = ::RegisterClassEx(&wc); |
| 187 DCHECK(clazz); | 206 DCHECK(clazz); |
| 188 | 207 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 200 | 219 |
| 201 ProcessSingleton::~ProcessSingleton() { | 220 ProcessSingleton::~ProcessSingleton() { |
| 202 // We need to unregister the window as late as possible so that we can detect | 221 // We need to unregister the window as late as possible so that we can detect |
| 203 // another instance of chrome running. Otherwise we may end up writing out | 222 // another instance of chrome running. Otherwise we may end up writing out |
| 204 // data while a new chrome is starting up. | 223 // data while a new chrome is starting up. |
| 205 if (window_) { | 224 if (window_) { |
| 206 ::DestroyWindow(window_); | 225 ::DestroyWindow(window_); |
| 207 ::UnregisterClass(chrome::kMessageWindowClass, | 226 ::UnregisterClass(chrome::kMessageWindowClass, |
| 208 base::GetModuleFromAddress(&ThunkWndProc)); | 227 base::GetModuleFromAddress(&ThunkWndProc)); |
| 209 } | 228 } |
| 229 if (lock_file_ != INVALID_HANDLE_VALUE) | |
| 230 CloseHandle(lock_file_); | |
| 210 } | 231 } |
| 211 | 232 |
| 212 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { | 233 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
| 213 if (is_virtualized_) | 234 if (is_virtualized_) |
| 214 return PROCESS_NOTIFIED; // We already spawned the process in this case. | 235 return PROCESS_NOTIFIED; // We already spawned the process in this case. |
| 236 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) | |
| 237 return LOCK_ERROR; | |
| 215 else if (!remote_window_) | 238 else if (!remote_window_) |
| 216 return PROCESS_NONE; | 239 return PROCESS_NONE; |
| 217 | 240 |
| 218 // Found another window, send our command line to it | 241 // Found another window, send our command line to it |
| 219 // format is "START\0<<<current directory>>>\0<<<commandline>>>". | 242 // format is "START\0<<<current directory>>>\0<<<commandline>>>". |
| 220 std::wstring to_send(L"START\0", 6); // want the NULL in the string. | 243 std::wstring to_send(L"START\0", 6); // want the NULL in the string. |
| 221 FilePath cur_dir; | 244 FilePath cur_dir; |
| 222 if (!PathService::Get(base::DIR_CURRENT, &cur_dir)) | 245 if (!PathService::Get(base::DIR_CURRENT, &cur_dir)) |
| 223 return PROCESS_NONE; | 246 return PROCESS_NONE; |
| 224 to_send.append(cur_dir.value()); | 247 to_send.append(cur_dir.value()); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 347 switch (message) { | 370 switch (message) { |
| 348 case WM_COPYDATA: | 371 case WM_COPYDATA: |
| 349 return OnCopyData(reinterpret_cast<HWND>(wparam), | 372 return OnCopyData(reinterpret_cast<HWND>(wparam), |
| 350 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | 373 reinterpret_cast<COPYDATASTRUCT*>(lparam)); |
| 351 default: | 374 default: |
| 352 break; | 375 break; |
| 353 } | 376 } |
| 354 | 377 |
| 355 return ::DefWindowProc(hwnd, message, wparam, lparam); | 378 return ::DefWindowProc(hwnd, message, wparam, lparam); |
| 356 } | 379 } |
| OLD | NEW |