1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/storage_monitor/storage_monitor_win.h"
16 #include "base/logging.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/win/wrapped_window_proc.h"
19 #include "components/storage_monitor/portable_device_watcher_win.h"
20 #include "components/storage_monitor/removable_device_constants.h"
21 #include "components/storage_monitor/storage_info.h"
22 #include "components/storage_monitor/volume_mount_watcher_win.h"
24 #define WM_USER_MEDIACHANGED (WM_USER + 5)
26 // StorageMonitorWin -------------------------------------------------------
28 namespace storage_monitor {
30 StorageMonitorWin::StorageMonitorWin(
31 std::unique_ptr<VolumeMountWatcherWin> volume_mount_watcher,
32 std::unique_ptr<PortableDeviceWatcherWin> portable_device_watcher)
33 : volume_mount_watcher_(std::move(volume_mount_watcher)),
34 portable_device_watcher_(std::move(portable_device_watcher)) {
35 DCHECK(volume_mount_watcher_);
36 DCHECK(portable_device_watcher_);
37 volume_mount_watcher_->SetNotifications(receiver());
38 portable_device_watcher_->SetNotifications(receiver());
41 StorageMonitorWin::~StorageMonitorWin() {
42 if (shell_change_notify_id_)
43 SHChangeNotifyDeregister(shell_change_notify_id_);
44 volume_mount_watcher_->SetNotifications(nullptr);
45 portable_device_watcher_->SetNotifications(nullptr);
48 DestroyWindow(window_);
51 UnregisterClass(MAKEINTATOM(window_class_), instance_);
54 void StorageMonitorWin::Init() {
55 WNDCLASSEX window_class;
56 base::win::InitializeWindowClass(
57 L"Chrome_StorageMonitorWindow",
58 &base::win::WrappedWindowProc<StorageMonitorWin::WndProcThunk>, 0, 0, 0,
59 nullptr, nullptr, nullptr, nullptr, nullptr, &window_class);
60 instance_ = window_class.hInstance;
61 window_class_ = RegisterClassEx(&window_class);
62 DCHECK(window_class_);
64 window_ = CreateWindow(MAKEINTATOM(window_class_), nullptr, 0, 0, 0, 0, 0,
65 nullptr, nullptr, instance_, nullptr);
66 SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
67 volume_mount_watcher_->Init();
68 portable_device_watcher_->Init(window_);
69 MediaChangeNotificationRegister();
72 bool StorageMonitorWin::GetStorageInfoForPath(const base::FilePath& path,
73 StorageInfo* device_info) const {
76 // TODO(gbillock): Move this logic up to StorageMonitor.
77 // If we already know the StorageInfo for the path, just return it.
78 // This will account for portable devices as well.
79 std::vector<StorageInfo> attached_devices = GetAllAvailableStorages();
80 size_t best_parent = attached_devices.size();
81 size_t best_length = 0;
82 for (size_t i = 0; i < attached_devices.size(); i++) {
83 if (!StorageInfo::IsRemovableDevice(attached_devices[i].device_id()))
85 base::FilePath relative;
86 if (base::FilePath(attached_devices[i].location()).AppendRelativePath(
88 // Note: the relative path is longer for shorter shared path between
89 // the path and the device mount point, so we want the shortest
91 if (relative.value().size() < best_length) {
93 best_length = relative.value().size();
97 if (best_parent != attached_devices.size()) {
98 *device_info = attached_devices[best_parent];
102 return GetDeviceInfo(path, device_info);
105 void StorageMonitorWin::EjectDevice(
106 const std::string& device_id,
107 base::OnceCallback<void(EjectStatus)> callback) {
108 StorageInfo::Type type;
109 if (!StorageInfo::CrackDeviceId(device_id, &type, nullptr)) {
110 std::move(callback).Run(EJECT_FAILURE);
114 if (type == StorageInfo::MTP_OR_PTP)
115 portable_device_watcher_->EjectDevice(device_id, std::move(callback));
116 else if (StorageInfo::IsRemovableDevice(device_id))
117 volume_mount_watcher_->EjectDevice(device_id, std::move(callback));
119 std::move(callback).Run(EJECT_FAILURE);
122 bool StorageMonitorWin::GetMTPStorageInfoFromDeviceId(
123 const std::string& storage_device_id,
124 std::wstring* device_location,
125 std::wstring* storage_object_id) const {
126 StorageInfo::Type type;
127 StorageInfo::CrackDeviceId(storage_device_id, &type, nullptr);
128 if (type != StorageInfo::MTP_OR_PTP)
130 return portable_device_watcher_->GetMTPStorageInfoFromDeviceId(
131 storage_device_id, device_location, storage_object_id);
135 LRESULT CALLBACK StorageMonitorWin::WndProcThunk(HWND hwnd, UINT message,
136 WPARAM wparam, LPARAM lparam) {
137 StorageMonitorWin* msg_wnd = reinterpret_cast<StorageMonitorWin*>(
138 GetWindowLongPtr(hwnd, GWLP_USERDATA));
140 return msg_wnd->WndProc(hwnd, message, wparam, lparam);
141 return ::DefWindowProc(hwnd, message, wparam, lparam);
144 LRESULT CALLBACK StorageMonitorWin::WndProc(HWND hwnd, UINT message,
145 WPARAM wparam, LPARAM lparam) {
147 case WM_DEVICECHANGE:
148 OnDeviceChange(static_cast<UINT>(wparam), lparam);
150 case WM_USER_MEDIACHANGED:
151 OnMediaChange(wparam, lparam);
157 return ::DefWindowProc(hwnd, message, wparam, lparam);
160 void StorageMonitorWin::MediaChangeNotificationRegister() {
161 LPITEMIDLIST id_list;
162 if (SHGetSpecialFolderLocation(nullptr, CSIDL_DRIVES, &id_list) == NOERROR) {
163 SHChangeNotifyEntry notify_entry;
164 notify_entry.pidl = id_list;
165 notify_entry.fRecursive = TRUE;
166 shell_change_notify_id_ = SHChangeNotifyRegister(
167 window_, SHCNRF_ShellLevel, SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED,
168 WM_USER_MEDIACHANGED, 1, ¬ify_entry);
169 if (!shell_change_notify_id_)
170 DVLOG(1) << "SHChangeNotifyRegister FAILED";
172 DVLOG(1) << "SHGetSpecialFolderLocation FAILED";
176 bool StorageMonitorWin::GetDeviceInfo(const base::FilePath& device_path,
177 StorageInfo* info) const {
180 // TODO(kmadhusu) Implement PortableDeviceWatcherWin::GetDeviceInfo()
181 // function when we have the functionality to add a sub directory of
182 // portable device as a media gallery.
183 return volume_mount_watcher_->GetDeviceInfo(device_path, info);
186 void StorageMonitorWin::OnDeviceChange(UINT event_type, LPARAM data) {
187 DVLOG(1) << "OnDeviceChange " << event_type << " " << data;
188 volume_mount_watcher_->OnWindowMessage(event_type, data);
189 portable_device_watcher_->OnWindowMessage(event_type, data);
192 void StorageMonitorWin::OnMediaChange(WPARAM wparam, LPARAM lparam) {
193 volume_mount_watcher_->OnMediaChange(wparam, lparam);
196 StorageMonitor* StorageMonitor::CreateInternal() {
197 return new StorageMonitorWin(std::make_unique<VolumeMountWatcherWin>(),
198 std::make_unique<PortableDeviceWatcherWin>());
201 } // namespace storage_monitor