Roll src/third_party/WebKit 4526c29:30f3df0 (svn 190187:190189)
[chromium-blink-merge.git] / device / core / device_monitor_win.cc
blob0c8175159577947b7859a253c6bc76dc87eff720
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/core/device_monitor_win.h"
7 #include <dbt.h>
8 #include <map>
9 #include <windows.h>
11 #include "base/at_exit.h"
12 #include "base/bind.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/sys_string_conversions.h"
15 #include "base/win/message_window.h"
17 namespace device {
19 class DeviceMonitorMessageWindow;
21 namespace {
23 const wchar_t kWindowClassName[] = L"DeviceMonitorMessageWindow";
24 DeviceMonitorMessageWindow* g_message_window;
26 // Provides basic comparability for GUIDs so that they can be used as keys to an
27 // STL map.
28 struct CompareGUID {
29 bool operator()(const GUID& a, const GUID& b) {
30 return memcmp(&a, &b, sizeof a) < 0;
35 // This singleton class manages a shared message window for all registered
36 // device notification observers. It vends one instance of DeviceManagerWin for
37 // each unique GUID it sees.
38 class DeviceMonitorMessageWindow {
39 public:
40 static DeviceMonitorMessageWindow* GetInstance() {
41 if (!g_message_window) {
42 g_message_window = new DeviceMonitorMessageWindow();
43 base::AtExitManager::RegisterTask(
44 base::Bind(&base::DeletePointer<DeviceMonitorMessageWindow>,
45 base::Unretained(g_message_window)));
47 return g_message_window;
50 DeviceMonitorWin* GetForDeviceInterface(const GUID& device_interface) {
51 scoped_ptr<DeviceMonitorWin>& device_monitor =
52 device_monitors_[device_interface];
53 if (!device_monitor) {
54 DEV_BROADCAST_DEVICEINTERFACE db = {sizeof(DEV_BROADCAST_DEVICEINTERFACE),
55 DBT_DEVTYP_DEVICEINTERFACE,
57 device_interface};
58 HDEVNOTIFY notify_handle = RegisterDeviceNotification(
59 window_->hwnd(), &db, DEVICE_NOTIFY_WINDOW_HANDLE);
60 if (!notify_handle) {
61 LOG(ERROR) << "Failed to register for device notifications.";
62 return nullptr;
64 device_monitor.reset(new DeviceMonitorWin(notify_handle));
66 return device_monitor.get();
69 private:
70 friend void base::DeletePointer<DeviceMonitorMessageWindow>(
71 DeviceMonitorMessageWindow* message_window);
73 DeviceMonitorMessageWindow() {
74 window_.reset(new base::win::MessageWindow());
75 if (!window_->CreateNamed(
76 base::Bind(&DeviceMonitorMessageWindow::HandleMessage,
77 base::Unretained(this)),
78 base::string16(kWindowClassName))) {
79 LOG(ERROR) << "Failed to create message window: " << kWindowClassName;
80 window_.reset();
84 ~DeviceMonitorMessageWindow() {}
86 bool HandleMessage(UINT message,
87 WPARAM wparam,
88 LPARAM lparam,
89 LRESULT* result) {
90 if (message == WM_DEVICECHANGE) {
91 DEV_BROADCAST_DEVICEINTERFACE* db =
92 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(lparam);
93 const auto& map_entry = device_monitors_.find(db->dbcc_classguid);
94 if (map_entry == device_monitors_.end()) {
95 return false;
97 DeviceMonitorWin* device_monitor = map_entry->second.get();
99 std::string device_path(base::SysWideToUTF8(db->dbcc_name));
100 DCHECK(base::IsStringASCII(device_path));
101 if (wparam == DBT_DEVICEARRIVAL) {
102 device_monitor->NotifyDeviceAdded(
103 base::StringToLowerASCII(device_path));
104 } else if (wparam == DBT_DEVICEREMOVECOMPLETE) {
105 device_monitor->NotifyDeviceRemoved(
106 base::StringToLowerASCII(device_path));
107 } else {
108 return false;
110 *result = NULL;
111 return true;
113 return false;
116 std::map<GUID, scoped_ptr<DeviceMonitorWin>, CompareGUID> device_monitors_;
117 scoped_ptr<base::win::MessageWindow> window_;
119 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow);
122 void DeviceMonitorWin::Observer::OnDeviceAdded(const std::string& device_path) {
125 void DeviceMonitorWin::Observer::OnDeviceRemoved(
126 const std::string& device_path) {
129 // static
130 DeviceMonitorWin* DeviceMonitorWin::GetForDeviceInterface(
131 const GUID& device_interface) {
132 DeviceMonitorMessageWindow* message_window =
133 DeviceMonitorMessageWindow::GetInstance();
134 return message_window->GetForDeviceInterface(device_interface);
137 DeviceMonitorWin::~DeviceMonitorWin() {
138 UnregisterDeviceNotification(notify_handle_);
141 void DeviceMonitorWin::AddObserver(Observer* observer) {
142 observer_list_.AddObserver(observer);
145 void DeviceMonitorWin::RemoveObserver(Observer* observer) {
146 observer_list_.RemoveObserver(observer);
149 DeviceMonitorWin::DeviceMonitorWin(HDEVNOTIFY notify_handle)
150 : notify_handle_(notify_handle) {
153 void DeviceMonitorWin::NotifyDeviceAdded(const std::string& device_path) {
154 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device_path));
157 void DeviceMonitorWin::NotifyDeviceRemoved(const std::string& device_path) {
158 FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device_path));