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. 4 5 #include "chrome/browser/storage_monitor/storage_monitor_win.h" 6 7 #include <windows.h> 8 #include <dbt.h> 9 #include <fileapi.h> 10 11 #include "base/win/wrapped_window_proc.h" 12 #include "chrome/browser/storage_monitor/portable_device_watcher_win.h" 13 #include "chrome/browser/storage_monitor/removable_device_constants.h" 14 #include "chrome/browser/storage_monitor/storage_info.h" 15 #include "chrome/browser/storage_monitor/volume_mount_watcher_win.h" 16 17 // StorageMonitorWin ------------------------------------------------------- 18 19 StorageMonitorWin::StorageMonitorWin( 20 VolumeMountWatcherWin* volume_mount_watcher, 21 PortableDeviceWatcherWin* portable_device_watcher) 22 : window_class_(0), 23 instance_(NULL), 24 window_(NULL), 25 volume_mount_watcher_(volume_mount_watcher), 26 portable_device_watcher_(portable_device_watcher) { 27 DCHECK(volume_mount_watcher_); 28 DCHECK(portable_device_watcher_); 29 volume_mount_watcher_->SetNotifications(receiver()); 30 portable_device_watcher_->SetNotifications(receiver()); 31 } 32 33 StorageMonitorWin::~StorageMonitorWin() { 34 volume_mount_watcher_->SetNotifications(NULL); 35 portable_device_watcher_->SetNotifications(NULL); 36 37 if (window_) 38 DestroyWindow(window_); 39 40 if (window_class_) 41 UnregisterClass(MAKEINTATOM(window_class_), instance_); 42 } 43 44 void StorageMonitorWin::Init() { 45 WNDCLASSEX window_class; 46 base::win::InitializeWindowClass( 47 L"Chrome_StorageMonitorWindow", 48 &base::win::WrappedWindowProc<StorageMonitorWin::WndProcThunk>, 49 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 50 &window_class); 51 instance_ = window_class.hInstance; 52 window_class_ = RegisterClassEx(&window_class); 53 DCHECK(window_class_); 54 55 window_ = CreateWindow(MAKEINTATOM(window_class_), 0, 0, 0, 0, 0, 0, 0, 0, 56 instance_, 0); 57 SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); 58 volume_mount_watcher_->Init(); 59 portable_device_watcher_->Init(window_); 60 } 61 62 bool StorageMonitorWin::GetStorageInfoForPath(const base::FilePath& path, 63 StorageInfo* device_info) const { 64 DCHECK(device_info); 65 66 // TODO(gbillock): Move this logic up to StorageMonitor. 67 // If we already know the StorageInfo for the path, just return it. 68 // This will account for portable devices as well. 69 std::vector<StorageInfo> attached_devices = GetAllAvailableStorages(); 70 size_t best_parent = attached_devices.size(); 71 size_t best_length = 0; 72 for (size_t i = 0; i < attached_devices.size(); i++) { 73 if (!StorageInfo::IsRemovableDevice(attached_devices[i].device_id())) 74 continue; 75 base::FilePath relative; 76 if (base::FilePath(attached_devices[i].location()).AppendRelativePath( 77 path, &relative)) { 78 // Note: the relative path is longer for shorter shared path between 79 // the path and the device mount point, so we want the shortest 80 // relative path. 81 if (relative.value().size() < best_length) { 82 best_parent = i; 83 best_length = relative.value().size(); 84 } 85 } 86 } 87 if (best_parent != attached_devices.size()) { 88 *device_info = attached_devices[best_parent]; 89 return true; 90 } 91 92 return GetDeviceInfo(path, device_info); 93 } 94 95 void StorageMonitorWin::EjectDevice( 96 const std::string& device_id, 97 base::Callback<void(EjectStatus)> callback) { 98 StorageInfo::Type type; 99 if (!StorageInfo::CrackDeviceId(device_id, &type, NULL)) { 100 callback.Run(EJECT_FAILURE); 101 return; 102 } 103 104 if (type == StorageInfo::MTP_OR_PTP) 105 portable_device_watcher_->EjectDevice(device_id, callback); 106 else if (StorageInfo::IsRemovableDevice(device_id)) 107 volume_mount_watcher_->EjectDevice(device_id, callback); 108 else 109 callback.Run(EJECT_FAILURE); 110 } 111 112 bool StorageMonitorWin::GetMTPStorageInfoFromDeviceId( 113 const std::string& storage_device_id, 114 base::string16* device_location, 115 base::string16* storage_object_id) const { 116 StorageInfo::Type type; 117 StorageInfo::CrackDeviceId(storage_device_id, &type, NULL); 118 return ((type == StorageInfo::MTP_OR_PTP) && 119 portable_device_watcher_->GetMTPStorageInfoFromDeviceId( 120 storage_device_id, device_location, storage_object_id)); 121 } 122 123 // static 124 LRESULT CALLBACK StorageMonitorWin::WndProcThunk(HWND hwnd, UINT message, 125 WPARAM wparam, LPARAM lparam) { 126 StorageMonitorWin* msg_wnd = reinterpret_cast<StorageMonitorWin*>( 127 GetWindowLongPtr(hwnd, GWLP_USERDATA)); 128 if (msg_wnd) 129 return msg_wnd->WndProc(hwnd, message, wparam, lparam); 130 return ::DefWindowProc(hwnd, message, wparam, lparam); 131 } 132 133 LRESULT CALLBACK StorageMonitorWin::WndProc(HWND hwnd, UINT message, 134 WPARAM wparam, LPARAM lparam) { 135 switch (message) { 136 case WM_DEVICECHANGE: 137 OnDeviceChange(static_cast<UINT>(wparam), lparam); 138 return TRUE; 139 default: 140 break; 141 } 142 143 return ::DefWindowProc(hwnd, message, wparam, lparam); 144 } 145 146 bool StorageMonitorWin::GetDeviceInfo(const base::FilePath& device_path, 147 StorageInfo* info) const { 148 DCHECK(info); 149 150 // TODO(kmadhusu) Implement PortableDeviceWatcherWin::GetDeviceInfo() 151 // function when we have the functionality to add a sub directory of 152 // portable device as a media gallery. 153 return volume_mount_watcher_->GetDeviceInfo(device_path, info); 154 } 155 156 void StorageMonitorWin::OnDeviceChange(UINT event_type, LPARAM data) { 157 volume_mount_watcher_->OnWindowMessage(event_type, data); 158 portable_device_watcher_->OnWindowMessage(event_type, data); 159 } 160 161 StorageMonitor* StorageMonitor::Create() { 162 return new StorageMonitorWin(new VolumeMountWatcherWin(), 163 new PortableDeviceWatcherWin()); 164 } 165