// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "device/core/device_monitor_win.h" #include #include #include #include "base/at_exit.h" #include "base/bind.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "base/win/message_window.h" namespace device { class DeviceMonitorMessageWindow; namespace { const wchar_t kWindowClassName[] = L"DeviceMonitorMessageWindow"; DeviceMonitorMessageWindow* g_message_window; // Provides basic comparability for GUIDs so that they can be used as keys to an // STL map. struct CompareGUID { bool operator()(const GUID& a, const GUID& b) { return memcmp(&a, &b, sizeof a) < 0; } }; } // This singleton class manages a shared message window for all registered // device notification observers. It vends one instance of DeviceManagerWin for // each unique GUID it sees. class DeviceMonitorMessageWindow { public: static DeviceMonitorMessageWindow* GetInstance() { if (!g_message_window) { g_message_window = new DeviceMonitorMessageWindow(); base::AtExitManager::RegisterTask( base::Bind(&base::DeletePointer, base::Unretained(g_message_window))); } return g_message_window; } DeviceMonitorWin* GetForDeviceInterface(const GUID& device_interface) { scoped_ptr& device_monitor = device_monitors_[device_interface]; if (!device_monitor) { DEV_BROADCAST_DEVICEINTERFACE db = {sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE, 0, device_interface}; HDEVNOTIFY notify_handle = RegisterDeviceNotification( window_->hwnd(), &db, DEVICE_NOTIFY_WINDOW_HANDLE); if (!notify_handle) { LOG(ERROR) << "Failed to register for device notifications."; return nullptr; } device_monitor.reset(new DeviceMonitorWin(notify_handle)); } return device_monitor.get(); } private: friend void base::DeletePointer( DeviceMonitorMessageWindow* message_window); DeviceMonitorMessageWindow() { window_.reset(new base::win::MessageWindow()); if (!window_->CreateNamed( base::Bind(&DeviceMonitorMessageWindow::HandleMessage, base::Unretained(this)), base::string16(kWindowClassName))) { LOG(ERROR) << "Failed to create message window: " << kWindowClassName; window_.reset(); } } ~DeviceMonitorMessageWindow() {} bool HandleMessage(UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) { if (message == WM_DEVICECHANGE) { DEV_BROADCAST_DEVICEINTERFACE* db = reinterpret_cast(lparam); const auto& map_entry = device_monitors_.find(db->dbcc_classguid); if (map_entry == device_monitors_.end()) { return false; } DeviceMonitorWin* device_monitor = map_entry->second.get(); std::string device_path(base::SysWideToUTF8(db->dbcc_name)); DCHECK(base::IsStringASCII(device_path)); if (wparam == DBT_DEVICEARRIVAL) { device_monitor->NotifyDeviceAdded( base::StringToLowerASCII(device_path)); } else if (wparam == DBT_DEVICEREMOVECOMPLETE) { device_monitor->NotifyDeviceRemoved( base::StringToLowerASCII(device_path)); } else { return false; } *result = NULL; return true; } return false; } std::map, CompareGUID> device_monitors_; scoped_ptr window_; DISALLOW_COPY_AND_ASSIGN(DeviceMonitorMessageWindow); }; void DeviceMonitorWin::Observer::OnDeviceAdded(const std::string& device_path) { } void DeviceMonitorWin::Observer::OnDeviceRemoved( const std::string& device_path) { } // static DeviceMonitorWin* DeviceMonitorWin::GetForDeviceInterface( const GUID& device_interface) { DeviceMonitorMessageWindow* message_window = DeviceMonitorMessageWindow::GetInstance(); return message_window->GetForDeviceInterface(device_interface); } DeviceMonitorWin::~DeviceMonitorWin() { UnregisterDeviceNotification(notify_handle_); } void DeviceMonitorWin::AddObserver(Observer* observer) { observer_list_.AddObserver(observer); } void DeviceMonitorWin::RemoveObserver(Observer* observer) { observer_list_.RemoveObserver(observer); } DeviceMonitorWin::DeviceMonitorWin(HDEVNOTIFY notify_handle) : notify_handle_(notify_handle) { } void DeviceMonitorWin::NotifyDeviceAdded(const std::string& device_path) { FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceAdded(device_path)); } void DeviceMonitorWin::NotifyDeviceRemoved(const std::string& device_path) { FOR_EACH_OBSERVER(Observer, observer_list_, OnDeviceRemoved(device_path)); } }