diff options
Diffstat (limited to 'chrome_frame/test/chrome_frame_test_utils.cc')
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc new file mode 100644 index 0000000..a75d791 --- /dev/null +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -0,0 +1,416 @@ +// Copyright (c) 2006-2008 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_frame/test/chrome_frame_test_utils.h" + +#include <atlbase.h> +#include <atlwin.h> +#include <iepmapi.h> + +#include "base/registry.h" // to find IE and firefox +#include "base/scoped_handle.h" +#include "base/scoped_comptr_win.h" +#include "base/string_util.h" +#include "base/win_util.h" +#include "chrome/common/chrome_switches.h" + +namespace chrome_frame_test { + +const wchar_t kIEImageName[] = L"iexplore.exe"; +const wchar_t kIEBrokerImageName[] = L"ieuser.exe"; +const wchar_t kFirefoxImageName[] = L"firefox.exe"; +const wchar_t kOperaImageName[] = L"opera.exe"; +const wchar_t kSafariImageName[] = L"safari.exe"; +const wchar_t kChromeImageName[] = L"chrome.exe"; + +bool IsTopLevelWindow(HWND window) { + long style = GetWindowLong(window, GWL_STYLE); // NOLINT + if (!(style & WS_CHILD)) + return true; + + HWND parent = GetParent(window); + if (!parent) + return true; + + if (parent == GetDesktopWindow()) + return true; + + return false; +} + +// Callback function for EnumThreadWindows. +BOOL CALLBACK CloseWindowsThreadCallback(HWND hwnd, LPARAM param) { + int& count = *reinterpret_cast<int*>(param); + if (IsWindowVisible(hwnd)) { + if (IsWindowEnabled(hwnd)) { + DWORD results = 0; + if (!::SendMessageTimeout(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0, SMTO_BLOCK, + 10000, &results)) { + DLOG(WARNING) << "Window hung: " << StringPrintf(L"%08X", hwnd); + } + count++; + } else { + DLOG(WARNING) << "Skipping disabled window: " + << StringPrintf(L"%08X", hwnd); + } + } + return TRUE; // continue enumeration +} + +// Attempts to close all non-child, visible windows on the given thread. +// The return value is the number of visible windows a close request was +// sent to. +int CloseVisibleTopLevelWindowsOnThread(DWORD thread_id) { + int window_close_attempts = 0; + EnumThreadWindows(thread_id, CloseWindowsThreadCallback, + reinterpret_cast<LPARAM>(&window_close_attempts)); + return window_close_attempts; +} + +// Enumerates the threads of a process and attempts to close visible non-child +// windows on all threads of the process. +// The return value is the number of visible windows a close request was +// sent to. +int CloseVisibleWindowsOnAllThreads(HANDLE process) { + DWORD process_id = ::GetProcessId(process); + if (process_id == 0) { + NOTREACHED(); + return 0; + } + + ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)); + if (!snapshot.IsValid()) { + NOTREACHED(); + return 0; + } + + int window_close_attempts = 0; + THREADENTRY32 te = { sizeof(THREADENTRY32) }; + if (Thread32First(snapshot, &te)) { + do { + if (RTL_CONTAINS_FIELD(&te, te.dwSize, th32OwnerProcessID) && + te.th32OwnerProcessID == process_id) { + window_close_attempts += + CloseVisibleTopLevelWindowsOnThread(te.th32ThreadID); + } + te.dwSize = sizeof(te); + } while (Thread32Next(snapshot, &te)); + } + + return window_close_attempts; +} + +class ForegroundHelperWindow : public CWindowImpl<ForegroundHelperWindow> { + public: +BEGIN_MSG_MAP(ForegroundHelperWindow) + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +END_MSG_MAP() + + HRESULT SetForeground(HWND window) { + DCHECK(::IsWindow(window)); + if (NULL == Create(NULL, NULL, NULL, WS_POPUP)) + return AtlHresultFromLastError(); + + static const int hotkey_id = 0x0000baba; + + SetWindowLongPtr(GWLP_USERDATA, reinterpret_cast<ULONG_PTR>(window)); + RegisterHotKey(m_hWnd, hotkey_id, 0, VK_F22); + + MSG msg = {0}; + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + INPUT hotkey = {0}; + hotkey.type = INPUT_KEYBOARD; + hotkey.ki.wVk = VK_F22; + SendInput(1, &hotkey, sizeof(hotkey)); + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (WM_HOTKEY == msg.message) + break; + } + + UnregisterHotKey(m_hWnd, hotkey_id); + DestroyWindow(); + + return S_OK; + } + + LRESULT OnHotKey(UINT msg, WPARAM wp, LPARAM lp, BOOL& handled) { // NOLINT + HWND window = reinterpret_cast<HWND>(GetWindowLongPtr(GWLP_USERDATA)); + SetForegroundWindow(window); + return 1; + } +}; + +bool ForceSetForegroundWindow(HWND window) { + if (GetForegroundWindow() == window) + return true; + ForegroundHelperWindow foreground_helper_window; + HRESULT hr = foreground_helper_window.SetForeground(window); + return SUCCEEDED(hr); +} + +struct PidAndWindow { + base::ProcessId pid; + HWND hwnd; +}; + +BOOL CALLBACK FindWindowInProcessCallback(HWND hwnd, LPARAM param) { + PidAndWindow* paw = reinterpret_cast<PidAndWindow*>(param); + base::ProcessId pid; + GetWindowThreadProcessId(hwnd, &pid); + if (pid == paw->pid && IsWindowVisible(hwnd)) { + paw->hwnd = hwnd; + return FALSE; + } + + return TRUE; +} + +bool EnsureProcessInForeground(base::ProcessId process_id) { + HWND hwnd = GetForegroundWindow(); + base::ProcessId current_foreground_pid = 0; + DWORD active_thread_id = GetWindowThreadProcessId(hwnd, + ¤t_foreground_pid); + if (current_foreground_pid == process_id) + return true; + + PidAndWindow paw = { process_id }; + EnumWindows(FindWindowInProcessCallback, reinterpret_cast<LPARAM>(&paw)); + if (!IsWindow(paw.hwnd)) { + DLOG(ERROR) << "failed to find process window"; + return false; + } + + bool ret = ForceSetForegroundWindow(paw.hwnd); + DLOG_IF(ERROR, !ret) << "ForceSetForegroundWindow: " << ret; + + return ret; +} + +// Iterates through all the characters in the string and simulates +// keyboard input. The input goes to the currently active application. +bool SendString(const wchar_t* string) { + DCHECK(string != NULL); + + INPUT input[2] = {0}; + input[0].type = INPUT_KEYBOARD; + input[0].ki.dwFlags = KEYEVENTF_UNICODE; // to avoid shift, etc. + input[1] = input[0]; + input[1].ki.dwFlags |= KEYEVENTF_KEYUP; + + for (const wchar_t* p = string; *p; p++) { + input[0].ki.wScan = input[1].ki.wScan = *p; + SendInput(2, input, sizeof(INPUT)); + } + + return true; +} + +void SendVirtualKey(int16 key) { + INPUT input = { INPUT_KEYBOARD }; + input.ki.wVk = key; + SendInput(1, &input, sizeof(input)); + input.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(1, &input, sizeof(input)); +} + +void SendChar(char c) { + SendVirtualKey(VkKeyScanA(c)); +} + +void SendString(const char* s) { + while (*s) { + SendChar(*s); + s++; + } +} + +// Sends a keystroke to the currently active application with optional +// modifiers set. +bool SendMnemonic(WORD mnemonic_char, bool shift_pressed, bool control_pressed, + bool alt_pressed) { + INPUT special_keys[3] = {0}; + for (int index = 0; index < arraysize(special_keys); ++index) { + special_keys[index].type = INPUT_KEYBOARD; + special_keys[index].ki.dwFlags = 0; + } + + int num_special_keys = 0; + if (shift_pressed) { + special_keys[num_special_keys].ki.wVk = VK_SHIFT; + num_special_keys++; + } + + if (control_pressed) { + special_keys[num_special_keys].ki.wVk = VK_CONTROL; + num_special_keys++; + } + + if (alt_pressed) { + special_keys[num_special_keys].ki.wVk = VK_MENU; + num_special_keys++; + } + + // Depress the modifiers. + SendInput(num_special_keys, special_keys, sizeof(INPUT)); + + Sleep(100); + + INPUT mnemonic = {0}; + mnemonic.type = INPUT_KEYBOARD; + mnemonic.ki.wVk = mnemonic_char; + + // Depress and release the mnemonic. + SendInput(1, &mnemonic, sizeof(INPUT)); + Sleep(100); + + mnemonic.ki.dwFlags |= KEYEVENTF_KEYUP; + SendInput(1, &mnemonic, sizeof(INPUT)); + Sleep(100); + + // Now release the modifiers. + for (int index = 0; index < num_special_keys; index++) { + special_keys[index].ki.dwFlags |= KEYEVENTF_KEYUP; + } + + SendInput(num_special_keys, special_keys, sizeof(INPUT)); + Sleep(100); + + return true; +} + +std::wstring GetExecutableAppPath(const std::wstring& file) { + std::wstring kAppPathsKey = + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"; + + std::wstring app_path; + RegKey key(HKEY_LOCAL_MACHINE, (kAppPathsKey + file).c_str()); + if (key.Handle()) { + key.ReadValue(NULL, &app_path); + } + + return app_path; +} + +std::wstring FormatCommandForApp(const std::wstring& exe_name, + const std::wstring& argument) { + std::wstring reg_path(StringPrintf(L"Applications\\%ls\\shell\\open\\command", + exe_name.c_str())); + RegKey key(HKEY_CLASSES_ROOT, reg_path.c_str()); + + std::wstring command; + if (key.Handle()) { + key.ReadValue(NULL, &command); + int found = command.find(L"%1"); + if (found >= 0) { + command.replace(found, 2, argument); + } + } + return command; +} + +base::ProcessHandle LaunchExecutable(const std::wstring& executable, + const std::wstring& argument) { + base::ProcessHandle process = NULL; + std::wstring path = GetExecutableAppPath(executable); + if (path.empty()) { + path = FormatCommandForApp(executable, argument); + if (path.empty()) { + DLOG(ERROR) << "Failed to find executable: " << executable; + } else { + CommandLine cmdline(L""); + cmdline.ParseFromString(path); + base::LaunchApp(cmdline, false, false, &process); + } + } else { + CommandLine cmdline(path); + cmdline.AppendLooseValue(argument); + base::LaunchApp(cmdline, false, false, &process); + } + return process; +} + +base::ProcessHandle LaunchFirefox(const std::wstring& url) { + return LaunchExecutable(kFirefoxImageName, url); +} + +base::ProcessHandle LaunchSafari(const std::wstring& url) { + return LaunchExecutable(kSafariImageName, url); +} + +base::ProcessHandle LaunchChrome(const std::wstring& url) { + return LaunchExecutable(kChromeImageName, + StringPrintf(L"--%ls ", switches::kNoFirstRun) + url); +} + +base::ProcessHandle LaunchOpera(const std::wstring& url) { + // NOTE: For Opera tests to work it must be configured to start up with + // a blank page. There is an command line switch, -nosession, that's supposed + // to avoid opening up the previous session, but that switch is not working. + // TODO(tommi): Include a special ini file (opera6.ini) for opera and launch + // with our required settings. This file is by default stored here: + // "%USERPROFILE%\Application Data\Opera\Opera\profile\opera6.ini" + return LaunchExecutable(kOperaImageName, url); +} + +base::ProcessHandle LaunchIEOnVista(const std::wstring& url) { + typedef HRESULT (WINAPI* IELaunchURLPtr)( + const wchar_t* url, + PROCESS_INFORMATION *pi, + VOID *info); + + IELaunchURLPtr launch; + PROCESS_INFORMATION pi = {0}; + IELAUNCHURLINFO info = {sizeof info, 0}; + HMODULE h = LoadLibrary(L"ieframe.dll"); + if (!h) + return NULL; + launch = reinterpret_cast<IELaunchURLPtr>(GetProcAddress(h, "IELaunchURL")); + HRESULT hr = launch(url.c_str(), &pi, &info); + FreeLibrary(h); + if (SUCCEEDED(hr)) + CloseHandle(pi.hThread); + return pi.hProcess; +} + +base::ProcessHandle LaunchIE(const std::wstring& url) { + if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) { + return LaunchIEOnVista(url); + } else { + return LaunchExecutable(kIEImageName, url); + } +} + +int CloseAllIEWindows() { + int ret = 0; + + ScopedComPtr<IShellWindows> windows; + HRESULT hr = ::CoCreateInstance(__uuidof(ShellWindows), NULL, CLSCTX_ALL, + IID_IShellWindows, reinterpret_cast<void**>(windows.Receive())); + DCHECK(SUCCEEDED(hr)); + + if (SUCCEEDED(hr)) { + long count = 0; // NOLINT + windows->get_Count(&count); + VARIANT i = { VT_I4 }; + for (i.lVal = 0; i.lVal < count; ++i.lVal) { + ScopedComPtr<IDispatch> folder; + windows->Item(i, folder.Receive()); + if (folder != NULL) { + ScopedComPtr<IWebBrowser2> browser; + if (SUCCEEDED(browser.QueryFrom(folder))) { + browser->Quit(); + ++ret; + } + } + } + } + + return ret; +} + +} // namespace chrome_frame_test |