summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/win_event_receiver.h
blob: 66ad9eba8a692e48f4e9f7ab27b7f98b421d2c4c (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) 2011 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.

#ifndef CHROME_FRAME_TEST_WIN_EVENT_RECEIVER_H_
#define CHROME_FRAME_TEST_WIN_EVENT_RECEIVER_H_

#include <windows.h>

#include <string>
#include <vector>
#include <utility>

#include "base/memory/linked_ptr.h"
#include "base/win/object_watcher.h"

struct FunctionStub;

// Listens to WinEvents from the WinEventReceiver.
class WinEventListener {
 public:
  virtual ~WinEventListener() {}
  // Called when an event has been received. |hwnd| is the window that generated
  // the event, or null if no window is associated with the event.
  virtual void OnEventReceived(DWORD event, HWND hwnd, LONG object_id,
                               LONG child_id) = 0;
};

// Receives WinEvents and forwards them to its listener. The event types the
// listener wants to receive can be specified.
class WinEventReceiver {
 public:
  WinEventReceiver();
  ~WinEventReceiver();

  // Sets the sole listener of this receiver. The listener will receive all
  // WinEvents of the given event type. Any previous listener will be
  // replaced. |listener| should not be NULL.
  void SetListenerForEvent(WinEventListener* listener, DWORD event);

  // Same as above, but sets a range of events to listen for.
  void SetListenerForEvents(WinEventListener* listener, DWORD event_min,
                            DWORD event_max);

  // Stops receiving events and forwarding them to the listener. It is
  // permitted to call this even if the receiver has already been stopped.
  void StopReceivingEvents();

 private:
  bool InitializeHook(DWORD event_min, DWORD event_max);

  static void CALLBACK WinEventHook(WinEventReceiver* me, HWINEVENTHOOK hook,
      DWORD event, HWND hwnd, LONG object_id, LONG child_id,
      DWORD event_thread_id, DWORD event_time);

  WinEventListener* listener_;
  HWINEVENTHOOK hook_;
  FunctionStub* hook_stub_;
};

// Receives notifications when a window is opened or closed.
class WindowObserver {
 public:
  virtual ~WindowObserver() {}
  virtual void OnWindowOpen(HWND hwnd) = 0;
  virtual void OnWindowClose(HWND hwnd) = 0;
};

// Notifies observers when windows whose captions match specified patterns
// open or close. When a window opens, its caption is compared to the patterns
// associated with each observer. Observers registered with matching patterns
// are notified of the window's opening and will be notified when the same
// window is closed (including if the owning process terminates without closing
// the window).
//
// Changes to a window's caption while it is open do not affect the set of
// observers to be notified when it closes.
//
// Observers are not notified of the closing of windows that were already open
// when they were registered.
//
// Observers may call AddObserver and/or RemoveObserver during notifications.
//
// Each instance of this class must only be accessed from a single thread, and
// that thread must be running a message loop.
class WindowWatchdog : public WinEventListener {
 public:
  WindowWatchdog();
  // Register |observer| to be notified when windows matching |caption_pattern|
  // and/or |class_name_pattern| are opened or closed. A single observer may be
  // registered multiple times.
  // If a single window caption and/or class name matches multiple
  // registrations of a single observer, the observer will be notified once per
  // matching registration.
  void AddObserver(WindowObserver* observer,
                   const std::string& caption_pattern,
                   const std::string& class_name_pattern);

  // Remove all registrations of |observer|. The |observer| will not be notified
  // during or after this call.
  void RemoveObserver(WindowObserver* observer);

 private:
  class ProcessExitObserver;

  // The Delegate object is actually a ProcessExitObserver, but declaring
  // it as such would require fully declaring the ProcessExitObserver class
  // here in order for linked_ptr to access its destructor.
  typedef std::pair<HWND, linked_ptr<base::win::ObjectWatcher::Delegate> >
      OpenWindowEntry;
  typedef std::vector<OpenWindowEntry> OpenWindowList;

  struct ObserverEntry {
    WindowObserver* observer;
    std::string caption_pattern;
    std::string class_name_pattern;
    OpenWindowList open_windows;
  };

  typedef std::vector<ObserverEntry> ObserverEntryList;

  // WinEventListener implementation.
  virtual void OnEventReceived(
      DWORD event, HWND hwnd, LONG object_id, LONG child_id);

  static std::string GetWindowCaption(HWND hwnd);

  void HandleOnOpen(HWND hwnd);
  void HandleOnClose(HWND hwnd);
  void OnHwndProcessExited(HWND hwnd);

  // Returns true if the caption pattern and/or the class name pattern in the
  // observer entry structure matches the caption and/or class name passed in.
  bool MatchingWindow(const ObserverEntry& entry,
                      const std::string& caption,
                      const std::string& class_name);

  ObserverEntryList observers_;
  WinEventReceiver win_event_receiver_;

  DISALLOW_COPY_AND_ASSIGN(WindowWatchdog);
};



#endif  // CHROME_FRAME_TEST_WIN_EVENT_RECEIVER_H_