Home | History | Annotate | Download | only in storage_monitor
      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