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"
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"
19 class DeviceMonitorMessageWindow
;
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
29 bool operator()(const GUID
& a
, const GUID
& b
) const {
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
{
40 static DeviceMonitorMessageWindow
* GetInstance() {
41 if (!g_message_window
) {
42 g_message_window
= new DeviceMonitorMessageWindow();
43 if (g_message_window
->Init()) {
44 base::AtExitManager::RegisterTask(
45 base::Bind(&base::DeletePointer
<DeviceMonitorMessageWindow
>,
46 base::Unretained(g_message_window
)));
48 delete g_message_window
;
49 g_message_window
= nullptr;
52 return g_message_window
;
55 DeviceMonitorWin
* GetForDeviceInterface(const GUID
& device_interface
) {
56 scoped_ptr
<DeviceMonitorWin
>& device_monitor
=
57 device_monitors_
[device_interface
];
58 if (!device_monitor
) {
59 device_monitor
.reset(new DeviceMonitorWin());
61 return device_monitor
.get();
64 DeviceMonitorWin
* GetForAllInterfaces() { return &all_device_monitor_
; }
67 friend void base::DeletePointer
<DeviceMonitorMessageWindow
>(
68 DeviceMonitorMessageWindow
* message_window
);
70 DeviceMonitorMessageWindow() {
73 ~DeviceMonitorMessageWindow() {
75 UnregisterDeviceNotification(notify_handle_
);
80 window_
.reset(new base::win::MessageWindow());
81 if (!window_
->CreateNamed(
82 base::Bind(&DeviceMonitorMessageWindow::HandleMessage
,
83 base::Unretained(this)),
84 base::string16(kWindowClassName
))) {
85 LOG(ERROR
) << "Failed to create message window: " << kWindowClassName
;
89 DEV_BROADCAST_DEVICEINTERFACE db
= {sizeof(DEV_BROADCAST_DEVICEINTERFACE
),
90 DBT_DEVTYP_DEVICEINTERFACE
};
91 notify_handle_
= RegisterDeviceNotification(
93 DEVICE_NOTIFY_WINDOW_HANDLE
| DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
);
94 if (!notify_handle_
) {
95 PLOG(ERROR
) << "Failed to register for device notifications";
102 bool HandleMessage(UINT message
,
106 if (message
== WM_DEVICECHANGE
) {
107 DeviceMonitorWin
* device_monitor
= nullptr;
108 DEV_BROADCAST_DEVICEINTERFACE
* db
=
109 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE
*>(lparam
);
110 const auto& map_entry
= device_monitors_
.find(db
->dbcc_classguid
);
111 if (map_entry
!= device_monitors_
.end()) {
112 device_monitor
= map_entry
->second
.get();
115 std::string
device_path(base::SysWideToUTF8(db
->dbcc_name
));
116 DCHECK(base::IsStringASCII(device_path
));
117 device_path
= base::StringToLowerASCII(device_path
);
119 if (wparam
== DBT_DEVICEARRIVAL
) {
120 if (device_monitor
) {
121 device_monitor
->NotifyDeviceAdded(db
->dbcc_classguid
, device_path
);
123 all_device_monitor_
.NotifyDeviceAdded(db
->dbcc_classguid
, device_path
);
124 } else if (wparam
== DBT_DEVICEREMOVECOMPLETE
) {
125 if (device_monitor
) {
126 device_monitor
->NotifyDeviceRemoved(db
->dbcc_classguid
, device_path
);
128 all_device_monitor_
.NotifyDeviceRemoved(db
->dbcc_classguid
,
139 std::map
<GUID
, scoped_ptr
<DeviceMonitorWin
>, CompareGUID
> device_monitors_
;
140 DeviceMonitorWin all_device_monitor_
;
141 scoped_ptr
<base::win::MessageWindow
> window_
;
142 HDEVNOTIFY notify_handle_
= NULL
;
144 DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow
);
147 void DeviceMonitorWin::Observer::OnDeviceAdded(const GUID
& class_guid
,
148 const std::string
& device_path
) {
151 void DeviceMonitorWin::Observer::OnDeviceRemoved(
152 const GUID
& class_guid
,
153 const std::string
& device_path
) {
157 DeviceMonitorWin
* DeviceMonitorWin::GetForDeviceInterface(
158 const GUID
& device_interface
) {
159 DeviceMonitorMessageWindow
* message_window
=
160 DeviceMonitorMessageWindow::GetInstance();
161 if (message_window
) {
162 return message_window
->GetForDeviceInterface(device_interface
);
168 DeviceMonitorWin
* DeviceMonitorWin::GetForAllInterfaces() {
169 DeviceMonitorMessageWindow
* message_window
=
170 DeviceMonitorMessageWindow::GetInstance();
171 if (message_window
) {
172 return message_window
->GetForAllInterfaces();
177 DeviceMonitorWin::~DeviceMonitorWin() {
180 void DeviceMonitorWin::AddObserver(Observer
* observer
) {
181 observer_list_
.AddObserver(observer
);
184 void DeviceMonitorWin::RemoveObserver(Observer
* observer
) {
185 observer_list_
.RemoveObserver(observer
);
188 DeviceMonitorWin::DeviceMonitorWin() {
191 void DeviceMonitorWin::NotifyDeviceAdded(const GUID
& class_guid
,
192 const std::string
& device_path
) {
193 FOR_EACH_OBSERVER(Observer
, observer_list_
,
194 OnDeviceAdded(class_guid
, device_path
));
197 void DeviceMonitorWin::NotifyDeviceRemoved(const GUID
& class_guid
,
198 const std::string
& device_path
) {
199 FOR_EACH_OBSERVER(Observer
, observer_list_
,
200 OnDeviceRemoved(class_guid
, device_path
));
203 } // namespace device