OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "device/core/device_monitor_win.h" | |
6 | |
7 #include <dbt.h> | |
8 #include <windows.h> | |
9 | |
10 #include <map> | |
11 #include <memory> | |
12 | |
13 #include "base/at_exit.h" | |
14 #include "base/bind.h" | |
15 #include "base/macros.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/sys_string_conversions.h" | |
18 #include "base/win/message_window.h" | |
19 | |
20 namespace device { | |
21 | |
22 class DeviceMonitorMessageWindow; | |
23 | |
24 namespace { | |
25 | |
26 const wchar_t kWindowClassName[] = L"DeviceMonitorMessageWindow"; | |
27 DeviceMonitorMessageWindow* g_message_window; | |
28 | |
29 // Provides basic comparability for GUIDs so that they can be used as keys to an | |
30 // STL map. | |
31 struct CompareGUID { | |
32 bool operator()(const GUID& a, const GUID& b) const { | |
33 return memcmp(&a, &b, sizeof a) < 0; | |
34 } | |
35 }; | |
36 } | |
37 | |
38 // This singleton class manages a shared message window for all registered | |
39 // device notification observers. It vends one instance of DeviceManagerWin for | |
40 // each unique GUID it sees. | |
41 class DeviceMonitorMessageWindow { | |
42 public: | |
43 static DeviceMonitorMessageWindow* GetInstance() { | |
44 if (!g_message_window) { | |
45 g_message_window = new DeviceMonitorMessageWindow(); | |
46 if (g_message_window->Init()) { | |
47 base::AtExitManager::RegisterTask( | |
48 base::Bind(&base::DeletePointer<DeviceMonitorMessageWindow>, | |
49 base::Unretained(g_message_window))); | |
50 } else { | |
51 delete g_message_window; | |
52 g_message_window = nullptr; | |
53 } | |
54 } | |
55 return g_message_window; | |
56 } | |
57 | |
58 DeviceMonitorWin* GetForDeviceInterface(const GUID& device_interface) { | |
59 std::unique_ptr<DeviceMonitorWin>& device_monitor = | |
60 device_monitors_[device_interface]; | |
61 if (!device_monitor) { | |
62 device_monitor.reset(new DeviceMonitorWin()); | |
63 } | |
64 return device_monitor.get(); | |
65 } | |
66 | |
67 DeviceMonitorWin* GetForAllInterfaces() { return &all_device_monitor_; } | |
68 | |
69 private: | |
70 friend void base::DeletePointer<DeviceMonitorMessageWindow>( | |
71 DeviceMonitorMessageWindow* message_window); | |
72 | |
73 DeviceMonitorMessageWindow() { | |
74 } | |
75 | |
76 ~DeviceMonitorMessageWindow() { | |
77 if (notify_handle_) { | |
78 UnregisterDeviceNotification(notify_handle_); | |
79 } | |
80 } | |
81 | |
82 bool Init() { | |
83 window_.reset(new base::win::MessageWindow()); | |
84 if (!window_->CreateNamed( | |
85 base::Bind(&DeviceMonitorMessageWindow::HandleMessage, | |
86 base::Unretained(this)), | |
87 base::string16(kWindowClassName))) { | |
88 LOG(ERROR) << "Failed to create message window: " << kWindowClassName; | |
89 return false; | |
90 } | |
91 | |
92 DEV_BROADCAST_DEVICEINTERFACE db = {sizeof(DEV_BROADCAST_DEVICEINTERFACE), | |
93 DBT_DEVTYP_DEVICEINTERFACE}; | |
94 notify_handle_ = RegisterDeviceNotification( | |
95 window_->hwnd(), &db, | |
96 DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); | |
97 if (!notify_handle_) { | |
98 PLOG(ERROR) << "Failed to register for device notifications"; | |
99 return false; | |
100 } | |
101 | |
102 return true; | |
103 } | |
104 | |
105 bool HandleMessage(UINT message, | |
106 WPARAM wparam, | |
107 LPARAM lparam, | |
108 LRESULT* result) { | |
109 if (message == WM_DEVICECHANGE && | |
110 (wparam == DBT_DEVICEARRIVAL || wparam == DBT_DEVICEREMOVECOMPLETE)) { | |
111 DEV_BROADCAST_HDR* hdr = reinterpret_cast<DEV_BROADCAST_HDR*>(lparam); | |
112 if (hdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) | |
113 return false; | |
114 | |
115 DEV_BROADCAST_DEVICEINTERFACE* db = | |
116 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(hdr); | |
117 | |
118 DeviceMonitorWin* device_monitor = nullptr; | |
119 const auto& map_entry = device_monitors_.find(db->dbcc_classguid); | |
120 if (map_entry != device_monitors_.end()) | |
121 device_monitor = map_entry->second.get(); | |
122 | |
123 std::string device_path(base::SysWideToUTF8(db->dbcc_name)); | |
124 DCHECK(base::IsStringASCII(device_path)); | |
125 device_path = base::ToLowerASCII(device_path); | |
126 | |
127 if (wparam == DBT_DEVICEARRIVAL) { | |
128 if (device_monitor) { | |
129 device_monitor->NotifyDeviceAdded(db->dbcc_classguid, device_path); | |
130 } | |
131 all_device_monitor_.NotifyDeviceAdded(db->dbcc_classguid, device_path); | |
132 } else if (wparam == DBT_DEVICEREMOVECOMPLETE) { | |
133 if (device_monitor) { | |
134 device_monitor->NotifyDeviceRemoved(db->dbcc_classguid, device_path); | |
135 } | |
136 all_device_monitor_.NotifyDeviceRemoved(db->dbcc_classguid, | |
137 device_path); | |
138 } | |
139 *result = NULL; | |
140 return true; | |
141 } | |
142 return false; | |
143 } | |
144 | |
145 std::map<GUID, std::unique_ptr<DeviceMonitorWin>, CompareGUID> | |
146 device_monitors_; | |
147 DeviceMonitorWin all_device_monitor_; | |
148 std::unique_ptr<base::win::MessageWindow> window_; | |
149 HDEVNOTIFY notify_handle_ = NULL; | |
150 | |
151 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow); | |
152 }; | |
153 | |
154 void DeviceMonitorWin::Observer::OnDeviceAdded(const GUID& class_guid, | |
155 const std::string& device_path) { | |
156 } | |
157 | |
158 void DeviceMonitorWin::Observer::OnDeviceRemoved( | |
159 const GUID& class_guid, | |
160 const std::string& device_path) { | |
161 } | |
162 | |
163 // static | |
164 DeviceMonitorWin* DeviceMonitorWin::GetForDeviceInterface( | |
165 const GUID& device_interface) { | |
166 DeviceMonitorMessageWindow* message_window = | |
167 DeviceMonitorMessageWindow::GetInstance(); | |
168 if (message_window) { | |
169 return message_window->GetForDeviceInterface(device_interface); | |
170 } | |
171 return nullptr; | |
172 } | |
173 | |
174 // static | |
175 DeviceMonitorWin* DeviceMonitorWin::GetForAllInterfaces() { | |
176 DeviceMonitorMessageWindow* message_window = | |
177 DeviceMonitorMessageWindow::GetInstance(); | |
178 if (message_window) { | |
179 return message_window->GetForAllInterfaces(); | |
180 } | |
181 return nullptr; | |
182 } | |
183 | |
184 DeviceMonitorWin::~DeviceMonitorWin() { | |
185 } | |
186 | |
187 void DeviceMonitorWin::AddObserver(Observer* observer) { | |
188 observer_list_.AddObserver(observer); | |
189 } | |
190 | |
191 void DeviceMonitorWin::RemoveObserver(Observer* observer) { | |
192 observer_list_.RemoveObserver(observer); | |
193 } | |
194 | |
195 DeviceMonitorWin::DeviceMonitorWin() { | |
196 } | |
197 | |
198 void DeviceMonitorWin::NotifyDeviceAdded(const GUID& class_guid, | |
199 const std::string& device_path) { | |
200 FOR_EACH_OBSERVER(Observer, observer_list_, | |
201 OnDeviceAdded(class_guid, device_path)); | |
202 } | |
203 | |
204 void DeviceMonitorWin::NotifyDeviceRemoved(const GUID& class_guid, | |
205 const std::string& device_path) { | |
206 FOR_EACH_OBSERVER(Observer, observer_list_, | |
207 OnDeviceRemoved(class_guid, device_path)); | |
208 } | |
209 | |
210 } // namespace device | |
OLD | NEW |