1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/chrome_process_finder_win.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <shellapi.h> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <string> 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/command_line.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/file_util.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_path.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h" 14bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process_handle.h" 15bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process_info.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/win/message_window.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/metro.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/scoped_handle.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/win_util.h" 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/windows_version.h" 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/metro_utils/metro_chrome_win.h" 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/chrome_constants.h" 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace { 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kTimeoutInSeconds = 20; 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The following is copied from net/base/escape.cc. We don't want to depend on 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// net here because this gets compiled into chrome.exe to facilitate 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// fast-rendezvous (see https://codereview.chromium.org/14617003/). 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// TODO(koz): Move these functions out of net/base/escape.cc into base/escape.cc 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// so we can depend on it directly. 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// BEGIN COPY from net/base/escape.cc 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// A fast bit-vector map for ascii characters. 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Internally stores 256 bits in an array of 8 ints. 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Does quick bit-flicking to lookup needed characters. 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)struct Charmap { 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool Contains(unsigned char c) const { 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ((map[c >> 5] & (1 << (c & 31))) != 0); 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint32 map[8]; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kHexString[] = "0123456789ABCDEF"; 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline char IntToHex(int i) { 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_GE(i, 0) << i << " not a hex value"; 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_LE(i, 15) << i << " not a hex value"; 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return kHexString[i]; 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Given text to escape and a Charmap defining which values to escape, 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// return an escaped string. If use_plus is true, spaces are converted 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// to +, otherwise, if spaces are in the charmap, they are converted to 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// %20. 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::string Escape(const std::string& text, const Charmap& charmap, 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool use_plus) { 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string escaped; 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.reserve(text.length() * 3); 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (unsigned int i = 0; i < text.length(); ++i) { 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) unsigned char c = static_cast<unsigned char>(text[i]); 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (use_plus && ' ' == c) { 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.push_back('+'); 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else if (charmap.Contains(c)) { 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.push_back('%'); 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.push_back(IntToHex(c >> 4)); 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.push_back(IntToHex(c & 0xf)); 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) escaped.push_back(c); 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return escaped; 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Everything except alphanumerics and !'()*-._~ 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// See RFC 2396 for the list of reserved characters. 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const Charmap kQueryCharmap = {{ 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0xffffffffL, 0xfc00987dL, 0x78000001L, 0xb8000001L, 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 0xffffffffL, 0xffffffffL, 0xffffffffL, 0xffffffffL 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}}; 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::string EscapeQueryParamValue(const std::string& text, bool use_plus) { 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return Escape(text, kQueryCharmap, use_plus); 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// END COPY from net/base/escape.cc 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace chrome { 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) { 1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return base::win::MessageWindow::FindWindow(user_data_dir.value()); 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochNotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window, 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool fast_start) { 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(remote_window); 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static const char kSearchUrl[] = 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "http://www.google.com/search?q=%s&sourceid=chrome&ie=UTF-8"; 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DWORD process_id = 0; 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!thread_id || !process_id) 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NOTIFY_FAILED; 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if !defined(USE_AURA) 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (base::win::IsMetroProcess()) { 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Interesting corner case. We are launched as a metro process but we 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // found another chrome running. Since metro enforces single instance then 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // the other chrome must be desktop chrome and this must be a search charm 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // activation. This scenario is unique; other cases should be properly 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // handled by the delegate_execute which will not activate a second chrome. 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 terms; 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::win::MetroLaunchType launch = base::win::GetMetroLaunchParams(&terms); 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (launch != base::win::METRO_SEARCH) { 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LOG(WARNING) << "In metro mode, but and launch is " << launch; 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string query = EscapeQueryParamValue(base::UTF16ToUTF8(terms), true); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::string url = base::StringPrintf(kSearchUrl, query.c_str()); 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SHELLEXECUTEINFOA sei = { sizeof(sei) }; 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) sei.fMask = SEE_MASK_FLAG_LOG_USAGE; 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) sei.nShow = SW_SHOWNORMAL; 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) sei.lpFile = url.c_str(); 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) OutputDebugStringA(sei.lpFile); 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) sei.lpDirectory = ""; 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ::ShellExecuteExA(&sei); 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NOTIFY_SUCCESS; 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::win::ScopedHandle process_handle; 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (base::win::GetVersion() >= base::win::VERSION_WIN8 && 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::OpenProcessHandleWithAccess( 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) process_id, PROCESS_QUERY_INFORMATION, 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) process_handle.Receive())) { 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Receive() causes the process handle to be set in the destructor of the 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // temporary receiver object, which does not happen until after the if 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // statement is complete. So IsProcessImmersive() should only be checked 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // as part of a separate if statement. 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (base::win::IsProcessImmersive(process_handle.Get())) 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) chrome::ActivateMetroChrome(); 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CommandLine command_line(*CommandLine::ForCurrentProcess()); 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) command_line.AppendSwitchASCII( 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) switches::kOriginalProcessStartTime, 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Int64ToString( 158ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch base::CurrentProcessInfo::CreationTime().ToInternalValue())); 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (fast_start) 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch command_line.AppendSwitch(switches::kFastStart); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Send the command line to the remote chrome window. 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Format is "START\0<<<current directory>>>\0<<<commandline>>>". 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::wstring to_send(L"START\0", 6); // want the NULL in the string. 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FilePath cur_dir; 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!base::GetCurrentDirectory(&cur_dir)) 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NOTIFY_FAILED; 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) to_send.append(cur_dir.value()); 170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) to_send.append(L"\0", 1); // Null separator. 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) to_send.append(command_line.GetCommandLineString()); 172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) to_send.append(L"\0", 1); // Null separator. 173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Allow the current running browser window to make itself the foreground 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // window (otherwise it will just flash in the taskbar). 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ::AllowSetForegroundWindow(process_id); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) COPYDATASTRUCT cds; 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cds.dwData = 0; 180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t)); 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cds.lpData = const_cast<wchar_t*>(to_send.c_str()); 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DWORD_PTR result = 0; 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (::SendMessageTimeout(remote_window, 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) WM_COPYDATA, 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NULL, 186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) reinterpret_cast<LPARAM>(&cds), 187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SMTO_ABORTIFHUNG, 188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) kTimeoutInSeconds * 1000, 189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &result)) { 190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return result ? NOTIFY_SUCCESS : NOTIFY_FAILED; 191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // It is possible that the process owning this window may have died by now. 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!::IsWindow(remote_window)) 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NOTIFY_FAILED; 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If the window couldn't be notified but still exists, assume it is hung. 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return NOTIFY_WINDOW_HUNG; 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace chrome 202