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 "components/storage_monitor/storage_monitor_win.h"
12 #include "base/profiler/scoped_tracker.h"
13 #include "base/win/wrapped_window_proc.h"
14 #include "components/storage_monitor/portable_device_watcher_win.h"
15 #include "components/storage_monitor/removable_device_constants.h"
16 #include "components/storage_monitor/storage_info.h"
17 #include "components/storage_monitor/volume_mount_watcher_win.h"
19 #define WM_USER_MEDIACHANGED (WM_USER + 5)
21 // StorageMonitorWin -------------------------------------------------------
23 namespace storage_monitor
{
25 StorageMonitorWin::StorageMonitorWin(
26 VolumeMountWatcherWin
* volume_mount_watcher
,
27 PortableDeviceWatcherWin
* portable_device_watcher
)
31 shell_change_notify_id_(0),
32 volume_mount_watcher_(volume_mount_watcher
),
33 portable_device_watcher_(portable_device_watcher
) {
34 DCHECK(volume_mount_watcher_
);
35 DCHECK(portable_device_watcher_
);
36 volume_mount_watcher_
->SetNotifications(receiver());
37 portable_device_watcher_
->SetNotifications(receiver());
40 StorageMonitorWin::~StorageMonitorWin() {
41 if (shell_change_notify_id_
)
42 SHChangeNotifyDeregister(shell_change_notify_id_
);
43 volume_mount_watcher_
->SetNotifications(NULL
);
44 portable_device_watcher_
->SetNotifications(NULL
);
47 DestroyWindow(window_
);
50 UnregisterClass(MAKEINTATOM(window_class_
), instance_
);
53 void StorageMonitorWin::Init() {
54 WNDCLASSEX window_class
;
55 base::win::InitializeWindowClass(
56 L
"Chrome_StorageMonitorWindow",
57 &base::win::WrappedWindowProc
<StorageMonitorWin::WndProcThunk
>,
58 0, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
,
60 instance_
= window_class
.hInstance
;
61 window_class_
= RegisterClassEx(&window_class
);
62 DCHECK(window_class_
);
64 window_
= CreateWindow(MAKEINTATOM(window_class_
), 0, 0, 0, 0, 0, 0, 0, 0,
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::Callback
<void(EjectStatus
)> callback
) {
108 StorageInfo::Type type
;
109 if (!StorageInfo::CrackDeviceId(device_id
, &type
, NULL
)) {
110 callback
.Run(EJECT_FAILURE
);
114 if (type
== StorageInfo::MTP_OR_PTP
)
115 portable_device_watcher_
->EjectDevice(device_id
, callback
);
116 else if (StorageInfo::IsRemovableDevice(device_id
))
117 volume_mount_watcher_
->EjectDevice(device_id
, callback
);
119 callback
.Run(EJECT_FAILURE
);
122 bool StorageMonitorWin::GetMTPStorageInfoFromDeviceId(
123 const std::string
& storage_device_id
,
124 base::string16
* device_location
,
125 base::string16
* storage_object_id
) const {
126 StorageInfo::Type type
;
127 StorageInfo::CrackDeviceId(storage_device_id
, &type
, NULL
);
128 return ((type
== StorageInfo::MTP_OR_PTP
) &&
129 portable_device_watcher_
->GetMTPStorageInfoFromDeviceId(
130 storage_device_id
, device_location
, storage_object_id
));
134 LRESULT CALLBACK
StorageMonitorWin::WndProcThunk(HWND hwnd
, UINT message
,
135 WPARAM wparam
, LPARAM lparam
) {
136 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
137 tracked_objects::ScopedTracker
tracking_profile(
138 FROM_HERE_WITH_EXPLICIT_FUNCTION(
139 "440919 StorageMonitorWin::WndProcThunk"));
141 StorageMonitorWin
* msg_wnd
= reinterpret_cast<StorageMonitorWin
*>(
142 GetWindowLongPtr(hwnd
, GWLP_USERDATA
));
144 return msg_wnd
->WndProc(hwnd
, message
, wparam
, lparam
);
145 return ::DefWindowProc(hwnd
, message
, wparam
, lparam
);
148 LRESULT CALLBACK
StorageMonitorWin::WndProc(HWND hwnd
, UINT message
,
149 WPARAM wparam
, LPARAM lparam
) {
151 case WM_DEVICECHANGE
:
152 OnDeviceChange(static_cast<UINT
>(wparam
), lparam
);
154 case WM_USER_MEDIACHANGED
:
155 OnMediaChange(wparam
, lparam
);
161 return ::DefWindowProc(hwnd
, message
, wparam
, lparam
);
164 void StorageMonitorWin::MediaChangeNotificationRegister() {
165 LPITEMIDLIST id_list
;
166 if (SHGetSpecialFolderLocation(NULL
, CSIDL_DRIVES
, &id_list
) == NOERROR
) {
167 SHChangeNotifyEntry notify_entry
;
168 notify_entry
.pidl
= id_list
;
169 notify_entry
.fRecursive
= TRUE
;
170 shell_change_notify_id_
= SHChangeNotifyRegister(
171 window_
, SHCNRF_ShellLevel
, SHCNE_MEDIAINSERTED
| SHCNE_MEDIAREMOVED
,
172 WM_USER_MEDIACHANGED
, 1, ¬ify_entry
);
173 if (!shell_change_notify_id_
)
174 DVLOG(1) << "SHChangeNotifyRegister FAILED";
176 DVLOG(1) << "SHGetSpecialFolderLocation FAILED";
180 bool StorageMonitorWin::GetDeviceInfo(const base::FilePath
& device_path
,
181 StorageInfo
* info
) const {
184 // TODO(kmadhusu) Implement PortableDeviceWatcherWin::GetDeviceInfo()
185 // function when we have the functionality to add a sub directory of
186 // portable device as a media gallery.
187 return volume_mount_watcher_
->GetDeviceInfo(device_path
, info
);
190 void StorageMonitorWin::OnDeviceChange(UINT event_type
, LPARAM data
) {
191 DVLOG(1) << "OnDeviceChange " << event_type
<< " " << data
;
192 volume_mount_watcher_
->OnWindowMessage(event_type
, data
);
193 portable_device_watcher_
->OnWindowMessage(event_type
, data
);
196 void StorageMonitorWin::OnMediaChange(WPARAM wparam
, LPARAM lparam
) {
197 volume_mount_watcher_
->OnMediaChange(wparam
, lparam
);
200 StorageMonitor
* StorageMonitor::CreateInternal() {
201 return new StorageMonitorWin(new VolumeMountWatcherWin(),
202 new PortableDeviceWatcherWin());
205 } // namespace storage_monitor