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