| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Quits Chrome. |
| |
| This script sends a WM_CLOSE message to each window of Chrome and waits until |
| the process terminates. |
| """ |
| |
| import optparse |
| import os |
| import pywintypes |
| import sys |
| import time |
| import win32con |
| import win32gui |
| import winerror |
| |
| import chrome_helper |
| |
| |
| def CloseWindows(process_path): |
| """Closes all windows owned by processes whose exe path is |process_path|. |
| |
| Args: |
| process_path: The path to the executable whose processes will have their |
| windows closed. |
| |
| Returns: |
| A boolean indicating whether the processes successfully terminated within |
| 25 seconds. |
| """ |
| start_time = time.time() |
| while time.time() - start_time < 25: |
| process_ids = chrome_helper.GetProcessIDs(process_path) |
| if not process_ids: |
| return True |
| |
| for hwnd in chrome_helper.GetWindowHandles(process_ids): |
| try: |
| win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0) |
| except pywintypes.error as error: |
| # It's normal that some window handles have become invalid. |
| if error.args[0] != winerror.ERROR_INVALID_WINDOW_HANDLE: |
| raise |
| time.sleep(0.1) |
| return False |
| |
| |
| def KillNamedProcess(process_path): |
| """ Kills all running exes with the same name as the exe at |process_path|. |
| |
| Args: |
| process_path: The path to an executable. |
| |
| Returns: |
| True if running executables were successfully killed. False otherwise. |
| """ |
| return os.system('taskkill /f /im %s' % os.path.basename(process_path)) == 0 |
| |
| |
| def QuitChrome(chrome_path): |
| """ Tries to quit chrome in a safe way. If there is still an open instance |
| after a timeout delay, the process is killed the hard way. |
| |
| Args: |
| chrome_path: The path to chrome.exe. |
| """ |
| if not CloseWindows(chrome_path): |
| # TODO(robertshield): Investigate why Chrome occasionally doesn't shut down. |
| sys.stderr.write('Warning: Chrome not responding to window closure. ' |
| 'Killing all processes belonging to %s\n' % chrome_path) |
| KillNamedProcess(chrome_path) |
| |
| |
| def main(): |
| usage = 'usage: %prog chrome_path' |
| parser = optparse.OptionParser(usage, description='Quit Chrome.') |
| _, args = parser.parse_args() |
| if len(args) != 1: |
| parser.error('Incorrect number of arguments.') |
| chrome_path = args[0] |
| |
| QuitChrome(chrome_path) |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |