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
) {
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 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
,
58 HDEVNOTIFY notify_handle
= RegisterDeviceNotification(
59 window_
->hwnd(), &db
, DEVICE_NOTIFY_WINDOW_HANDLE
);
61 LOG(ERROR
) << "Failed to register for device notifications.";
64 device_monitor
.reset(new DeviceMonitorWin(notify_handle
));
66 return device_monitor
.get();
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
;
84 ~DeviceMonitorMessageWindow() {}
86 bool HandleMessage(UINT message
,
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()) {
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
));
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
) {
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
));