| // Copyright 2015 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. |
| |
| #include "chrome/test/base/always_on_top_window_killer_win.h" |
| |
| #include <Windows.h> |
| |
| #include <string> |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| |
| namespace { |
| |
| const char kDialogFoundBeforeTest[] = |
| "There is an always on top dialog on the desktop. This was most likely " |
| "caused by a previous test and may cause this test to fail. Trying to " |
| "close it."; |
| |
| const char kDialogFoundPostTest[] = |
| "There is an always on top dialog on the desktop after running this test. " |
| "This was most likely caused by this test and may cause future tests to " |
| "fail, trying to close it."; |
| |
| const char kWindowFoundBeforeTest[] = |
| "There is an always on top window on the desktop before running the test. " |
| "This may have been caused by a previous test and may cause this test to " |
| "fail, class-name="; |
| |
| const char kWindowFoundPostTest[] = |
| "There is an always on top window on the desktop after running the test. " |
| "This may have been caused by this test or a previous test and may cause " |
| "flake, class-name="; |
| |
| BOOL CALLBACK AlwaysOnTopWindowProc(HWND hwnd, LPARAM l_param) { |
| const BOOL kContinueIterating = TRUE; |
| |
| if (!IsWindowVisible(hwnd) || IsIconic(hwnd)) |
| return kContinueIterating; |
| |
| const LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE); |
| if (ex_styles & WS_EX_TOPMOST) { |
| wchar_t class_name_chars[512]; |
| if (GetClassName(hwnd, class_name_chars, arraysize(class_name_chars))) { |
| const std::wstring class_name(class_name_chars); |
| const RunType run_type = *reinterpret_cast<RunType*>(l_param); |
| // "#32770" is used for system dialogs, such as happens if a child |
| // process triggers an assert(). |
| if (class_name == L"#32770") { |
| LOG(ERROR) << (run_type == RunType::BEFORE_TEST ? kDialogFoundBeforeTest |
| : kDialogFoundPostTest); |
| // We don't own the dialog, so we can't destroy it. CloseWindow() |
| // results in iconifying the window. An alternative may be to focus it, |
| // then send return and wait for close. As we reboot machines running |
| // interactive ui tests at least every 12 hours we're going with the |
| // simple for now. |
| CloseWindow(hwnd); |
| } else if (class_name != L"Button" && class_name != L"Shell_TrayWnd") { |
| // 'Button' is the start button, and 'Shell_TrayWnd' the taskbar. |
| // |
| // These windows may be problematic as well, but in theory tests should |
| // not be creating an always on top window that outlives the test. Log |
| // the window in case there are problems. |
| DWORD process_id = 0; |
| DWORD thread_id = GetWindowThreadProcessId(hwnd, &process_id); |
| LOG(ERROR) << (run_type == RunType::BEFORE_TEST ? kWindowFoundBeforeTest |
| : kWindowFoundPostTest) |
| << class_name << " process_id=" << process_id |
| << " thread_id=" << thread_id; |
| return kContinueIterating; |
| } |
| } |
| } |
| return kContinueIterating; |
| } |
| |
| } // namespace |
| |
| void KillAlwaysOnTopWindows(RunType run_type) { |
| EnumWindows(AlwaysOnTopWindowProc, reinterpret_cast<LPARAM>(&run_type)); |
| } |