summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/net/dialog_watchdog.cc
blob: 8b2323a34607a52153e7553c32913a68bd751f97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) 2009 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 <oleacc.h>

#include "chrome_frame/test/net/dialog_watchdog.h"

#include "base/logging.h"
#include "base/scoped_comptr_win.h"
#include "base/string_util.h"

#include "chrome_frame/test/simulate_input.h"
#include "chrome_frame/function_stub.h"

namespace {
// Uses the IAccessible interface for the window to set the focus.
// This can be useful when you don't have control over the thread that
// owns the window.
// NOTE: this depends on oleacc.lib which the net tests already depend on
// but other unit tests don't depend on oleacc so we can't just add the method
// directly into chrome_frame_test_utils.cc (without adding a
// #pragma comment(lib, "oleacc.lib")).
bool SetFocusToAccessibleWindow(HWND hwnd) {
  bool ret = false;
  ScopedComPtr<IAccessible> acc;
  AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible,
      reinterpret_cast<void**>(acc.Receive()));
  if (acc) {
    VARIANT self = { VT_I4 };
    self.lVal = CHILDID_SELF;
    ret = SUCCEEDED(acc->accSelect(SELFLAG_TAKEFOCUS, self));
  }
  return ret;
}

}  // namespace

SupplyProxyCredentials::SupplyProxyCredentials(const char* username,
                                               const char* password)
    : username_(username), password_(password) {
}

bool SupplyProxyCredentials::OnDialogDetected(HWND hwnd,
                                              const std::string& caption) {
  // IE's dialog caption (en-US).
  if (caption.compare("Windows Security") != 0)
    return false;

  DialogProps props = {0};
  ::EnumChildWindows(hwnd, EnumChildren, reinterpret_cast<LPARAM>(&props));
  DCHECK(::IsWindow(props.username_));
  DCHECK(::IsWindow(props.password_));

  // We can't use SetWindowText to set the username/password, so simulate
  // keyboard input instead.
  simulate_input::ForceSetForegroundWindow(hwnd);
  CHECK(SetFocusToAccessibleWindow(props.username_));
  simulate_input::SendString(username_.c_str());
  Sleep(100);

  simulate_input::SendChar(static_cast<char>(VK_TAB), false, false);
  Sleep(100);
  simulate_input::SendString(password_.c_str());

  Sleep(100);
  simulate_input::SendChar(static_cast<char>(VK_RETURN), false, false);

  return true;
}

// static
BOOL SupplyProxyCredentials::EnumChildren(HWND hwnd, LPARAM param) {
  if (!::IsWindowVisible(hwnd))
    return TRUE;  // Ignore but continue to enumerate.

  DialogProps* props = reinterpret_cast<DialogProps*>(param);

  char class_name[MAX_PATH] = {0};
  ::GetClassNameA(hwnd, class_name, arraysize(class_name));
  if (lstrcmpiA(class_name, "Edit") == 0) {
    if (props->username_ == NULL || props->username_ == hwnd) {
      props->username_ = hwnd;
    } else if (props->password_ == NULL) {
      props->password_ = hwnd;
    }
  } else {
    EnumChildWindows(hwnd, EnumChildren, param);
  }

  return TRUE;
}

DialogWatchdog::DialogWatchdog() : hook_(NULL), hook_stub_(NULL) {
  Initialize();
}

DialogWatchdog::~DialogWatchdog() {
  Uninitialize();
}

bool DialogWatchdog::Initialize() {
  DCHECK(hook_ == NULL);
  DCHECK(hook_stub_ == NULL);
  hook_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
                                    WinEventHook);
  hook_ = SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_SHOW, NULL,
                          reinterpret_cast<WINEVENTPROC>(hook_stub_->code()), 0,
                          0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

  return hook_ != NULL;
}

void DialogWatchdog::Uninitialize() {
  if (hook_) {
    ::UnhookWinEvent(hook_);
    hook_ = NULL;
    FunctionStub::Destroy(hook_stub_);
    hook_stub_ = NULL;
  }
}

// static
void DialogWatchdog::WinEventHook(DialogWatchdog* me, HWINEVENTHOOK hook,
                                  DWORD event, HWND hwnd, LONG object_id,
                                  LONG child_id, DWORD event_thread_id,
                                  DWORD event_time) {
  // Check for a dialog class ("#32770") and notify observers if we find one.
  char class_name[MAX_PATH] = {0};
  ::GetClassNameA(hwnd, class_name, arraysize(class_name));
  if (lstrcmpA(class_name, "#32770") == 0) {
    int len = ::GetWindowTextLength(hwnd);
    std::string text;
    ::GetWindowTextA(hwnd, WriteInto(&text, len + 1), len + 1);
    me->OnDialogFound(hwnd, text);
  }
}

void DialogWatchdog::OnDialogFound(HWND hwnd, const std::string& caption) {
  std::vector<DialogWatchdogObserver*>::iterator it = observers_.begin();
  while (it != observers_.end()) {
    if ((*it)->OnDialogDetected(hwnd, caption))
      break;
    it++;
  }
}