1 // Copyright (c) 2012 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 "content/browser/system_message_window_win.h"
9 #include "base/logging.h"
10 #include "base/system_monitor/system_monitor.h"
11 #include "base/win/wrapped_window_proc.h"
12 #include "media/audio/win/core_audio_util_win.h"
17 const wchar_t kWindowClassName
[] = L
"Chrome_SystemMessageWindow";
19 // A static map from a device category guid to base::SystemMonitor::DeviceType.
21 const GUID device_category
;
22 const base::SystemMonitor::DeviceType device_type
;
23 } const kDeviceCategoryMap
[] = {
24 { KSCATEGORY_AUDIO
, base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE
},
25 { KSCATEGORY_VIDEO
, base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE
},
29 // Manages the device notification handles for SystemMessageWindowWin.
30 class SystemMessageWindowWin::DeviceNotifications
{
32 explicit DeviceNotifications(HWND hwnd
) : notifications_() {
36 ~DeviceNotifications() {
40 void Register(HWND hwnd
) {
41 // Request to receive device notifications. All applications receive basic
42 // notifications via WM_DEVICECHANGE but in order to receive detailed device
43 // arrival and removal messages, we need to register.
44 DEV_BROADCAST_DEVICEINTERFACE filter
= {0};
45 filter
.dbcc_size
= sizeof(filter
);
46 filter
.dbcc_devicetype
= DBT_DEVTYP_DEVICEINTERFACE
;
47 bool core_audio_support
= media::CoreAudioUtil::IsSupported();
48 for (int i
= 0; i
< arraysize(kDeviceCategoryMap
); ++i
) {
49 // If CoreAudio is supported, AudioDeviceListenerWin will
50 // take care of monitoring audio devices.
51 if (core_audio_support
&&
52 KSCATEGORY_AUDIO
== kDeviceCategoryMap
[i
].device_category
) {
56 filter
.dbcc_classguid
= kDeviceCategoryMap
[i
].device_category
;
57 DCHECK_EQ(notifications_
[i
], static_cast<HDEVNOTIFY
>(NULL
));
58 notifications_
[i
] = RegisterDeviceNotification(
59 hwnd
, &filter
, DEVICE_NOTIFY_WINDOW_HANDLE
);
60 DPLOG_IF(ERROR
, !notifications_
[i
])
61 << "RegisterDeviceNotification failed";
66 for (int i
= 0; i
< arraysize(notifications_
); ++i
) {
67 if (notifications_
[i
]) {
68 UnregisterDeviceNotification(notifications_
[i
]);
69 notifications_
[i
] = NULL
;
75 HDEVNOTIFY notifications_
[arraysize(kDeviceCategoryMap
)];
77 DISALLOW_IMPLICIT_CONSTRUCTORS(DeviceNotifications
);
81 SystemMessageWindowWin::SystemMessageWindowWin() {
82 WNDCLASSEX window_class
;
83 base::win::InitializeWindowClass(
85 &base::win::WrappedWindowProc
<SystemMessageWindowWin::WndProcThunk
>,
86 0, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
,
88 instance_
= window_class
.hInstance
;
89 ATOM clazz
= RegisterClassEx(&window_class
);
92 window_
= CreateWindow(kWindowClassName
,
93 0, 0, 0, 0, 0, 0, 0, 0, instance_
, 0);
94 SetWindowLongPtr(window_
, GWLP_USERDATA
, reinterpret_cast<LONG_PTR
>(this));
95 device_notifications_
.reset(new DeviceNotifications(window_
));
98 SystemMessageWindowWin::~SystemMessageWindowWin() {
100 DestroyWindow(window_
);
101 UnregisterClass(kWindowClassName
, instance_
);
105 LRESULT
SystemMessageWindowWin::OnDeviceChange(UINT event_type
, LPARAM data
) {
106 base::SystemMonitor
* monitor
= base::SystemMonitor::Get();
107 base::SystemMonitor::DeviceType device_type
=
108 base::SystemMonitor::DEVTYPE_UNKNOWN
;
109 switch (event_type
) {
110 case DBT_DEVNODES_CHANGED
:
111 // For this notification, we're happy with the default DEVTYPE_UNKNOWN.
114 case DBT_DEVICEREMOVECOMPLETE
:
115 case DBT_DEVICEARRIVAL
: {
116 // This notification has more details about the specific device that
117 // was added or removed. See if this is a category we're interested
118 // in monitoring and if so report the specific device type. If we don't
119 // find the category in our map, ignore the notification and do not
120 // notify the system monitor.
121 DEV_BROADCAST_DEVICEINTERFACE
* device_interface
=
122 reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE
*>(data
);
123 if (device_interface
->dbcc_devicetype
!= DBT_DEVTYP_DEVICEINTERFACE
)
125 for (int i
= 0; i
< arraysize(kDeviceCategoryMap
); ++i
) {
126 if (kDeviceCategoryMap
[i
].device_category
==
127 device_interface
->dbcc_classguid
) {
128 device_type
= kDeviceCategoryMap
[i
].device_type
;
133 // Devices that we do not have a DEVTYPE_ for, get detected via
134 // DBT_DEVNODES_CHANGED, so we avoid sending additional notifications
136 if (device_type
== base::SystemMonitor::DEVTYPE_UNKNOWN
)
145 monitor
->ProcessDevicesChanged(device_type
);
150 LRESULT CALLBACK
SystemMessageWindowWin::WndProc(HWND hwnd
, UINT message
,
151 WPARAM wparam
, LPARAM lparam
) {
153 case WM_DEVICECHANGE
:
154 return OnDeviceChange(static_cast<UINT
>(wparam
), lparam
);
159 return ::DefWindowProc(hwnd
, message
, wparam
, lparam
);
162 } // namespace content