2010-08-15 20:08:09 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-08-15 20:08:09 +02:00
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-08-30 21:58:01 +02:00
|
|
|
#define _WIN32_WINNT 0x0501
|
|
|
|
|
2010-08-15 20:08:09 +02:00
|
|
|
#include "wmdmlister.h"
|
2010-08-22 21:18:22 +02:00
|
|
|
#include "wmdmthread.h"
|
2010-08-23 21:13:27 +02:00
|
|
|
#include "core/utilities.h"
|
2010-08-15 20:08:09 +02:00
|
|
|
|
|
|
|
#include <objbase.h>
|
|
|
|
#include <mswmdm_i.c>
|
2010-08-30 21:58:01 +02:00
|
|
|
#include <winbase.h>
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-17 23:09:28 +02:00
|
|
|
#include <boost/bind.hpp>
|
2010-08-22 18:25:22 +02:00
|
|
|
#include <boost/scoped_array.hpp>
|
2010-08-17 23:09:28 +02:00
|
|
|
|
2010-09-04 13:09:59 +02:00
|
|
|
#include <QDir>
|
2010-08-16 01:26:04 +02:00
|
|
|
#include <QPixmap>
|
2010-08-15 20:08:09 +02:00
|
|
|
#include <QStringList>
|
|
|
|
#include <QtDebug>
|
|
|
|
|
2010-08-30 21:58:01 +02:00
|
|
|
const QUuid WmdmLister::kDeviceProtocolMsc(
|
|
|
|
0xa4d2c26c, 0xa881, 0x44bb, 0xbd, 0x5d, 0x1f, 0x70, 0x3c, 0x71, 0xf7, 0xa9);
|
|
|
|
|
2010-08-22 18:25:22 +02:00
|
|
|
QString WmdmLister::CanonicalNameToId(const QString& canonical_name) {
|
|
|
|
return "wmdm/" + canonical_name;
|
|
|
|
}
|
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
QString WmdmLister::DeviceInfo::unique_id() const {
|
2010-08-22 18:25:22 +02:00
|
|
|
return WmdmLister::CanonicalNameToId(canonical_name_);
|
2010-08-16 01:26:04 +02:00
|
|
|
}
|
|
|
|
|
2010-08-15 20:08:09 +02:00
|
|
|
WmdmLister::WmdmLister()
|
2010-08-22 21:18:22 +02:00
|
|
|
: notification_cookie_(0)
|
2010-08-15 20:08:09 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-08-22 21:18:22 +02:00
|
|
|
WmdmLister::~WmdmLister() {
|
|
|
|
Q_ASSERT(!thread_);
|
|
|
|
}
|
2010-08-16 01:26:04 +02:00
|
|
|
|
2010-08-22 21:18:22 +02:00
|
|
|
void WmdmLister::Init() {
|
|
|
|
thread_.reset(new WmdmThread);
|
2011-01-22 12:29:47 +01:00
|
|
|
if (!thread_->manager())
|
|
|
|
return;
|
2010-08-16 01:26:04 +02:00
|
|
|
|
2010-08-22 17:26:59 +02:00
|
|
|
// Register for notifications
|
|
|
|
IConnectionPointContainer* cp_container = NULL;
|
2010-08-22 21:18:22 +02:00
|
|
|
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
|
2010-08-22 17:26:59 +02:00
|
|
|
|
|
|
|
IConnectionPoint* cp = NULL;
|
|
|
|
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
|
|
|
|
|
|
|
|
cp->Advise(this, ¬ification_cookie_);
|
|
|
|
|
|
|
|
cp->Release();
|
|
|
|
cp_container->Release();
|
|
|
|
|
|
|
|
// Fetch the initial list of devices
|
2010-08-16 01:26:04 +02:00
|
|
|
IWMDMEnumDevice* device_it = NULL;
|
2010-08-22 21:18:22 +02:00
|
|
|
if (thread_->manager()->EnumDevices2(&device_it)) {
|
2010-08-16 01:26:04 +02:00
|
|
|
qWarning() << "Error querying WMDM devices";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate through the devices
|
|
|
|
QMap<QString, DeviceInfo> devices;
|
|
|
|
forever {
|
|
|
|
IWMDMDevice* device = NULL;
|
2010-08-22 18:11:14 +02:00
|
|
|
IWMDMDevice2* device2 = NULL;
|
2010-08-16 01:26:04 +02:00
|
|
|
ULONG fetched = 0;
|
|
|
|
if (device_it->Next(1, &device, &fetched) || fetched != 1)
|
|
|
|
break;
|
|
|
|
|
2010-08-22 18:11:14 +02:00
|
|
|
if (device->QueryInterface(IID_IWMDMDevice2, (void**)&device2)) {
|
|
|
|
qWarning() << "Error getting IWMDMDevice2 from device";
|
|
|
|
device->Release();
|
|
|
|
continue;
|
|
|
|
}
|
2010-08-22 18:25:22 +02:00
|
|
|
device->Release();
|
2010-08-22 18:11:14 +02:00
|
|
|
|
|
|
|
DeviceInfo info = ReadDeviceInfo(device2);
|
2010-08-16 01:26:04 +02:00
|
|
|
if (info.is_suitable_)
|
|
|
|
devices[info.unique_id()] = info;
|
2010-08-22 18:11:14 +02:00
|
|
|
else
|
2010-08-22 18:25:22 +02:00
|
|
|
device2->Release();
|
2010-08-16 01:26:04 +02:00
|
|
|
}
|
|
|
|
device_it->Release();
|
|
|
|
|
|
|
|
// Update the internal cache
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
devices_ = devices;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify about the changes
|
|
|
|
foreach (const QString& id, devices.keys()) {
|
|
|
|
emit DeviceAdded(id);
|
|
|
|
}
|
|
|
|
}
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-23 12:26:00 +02:00
|
|
|
void WmdmLister::ReallyShutdown() {
|
2010-08-22 17:42:21 +02:00
|
|
|
// Unregister for notifications
|
|
|
|
IConnectionPointContainer* cp_container;
|
2010-08-22 21:18:22 +02:00
|
|
|
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
|
2010-08-22 17:42:21 +02:00
|
|
|
|
|
|
|
IConnectionPoint* cp;
|
|
|
|
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
|
|
|
|
|
|
|
|
cp->Release();
|
|
|
|
cp_container->Release();
|
|
|
|
|
2010-08-22 21:18:22 +02:00
|
|
|
thread_.reset();
|
2010-08-22 17:42:21 +02:00
|
|
|
}
|
|
|
|
|
2010-08-23 12:26:00 +02:00
|
|
|
void WmdmLister::ShutDown() {
|
|
|
|
// COM shutdown must be done in the original thread.
|
|
|
|
metaObject()->invokeMethod(this, "ReallyShutdown", Qt::BlockingQueuedConnection);
|
|
|
|
}
|
|
|
|
|
2010-08-17 23:09:28 +02:00
|
|
|
template <typename F>
|
|
|
|
qint64 GetSpaceValue(F f) {
|
|
|
|
DWORD low, high;
|
|
|
|
f(&low, &high);
|
|
|
|
|
|
|
|
return (qint64)high << 32 | (qint64)low;
|
|
|
|
}
|
|
|
|
|
2010-08-22 18:11:14 +02:00
|
|
|
WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
|
2010-08-16 01:26:04 +02:00
|
|
|
DeviceInfo ret;
|
2010-08-17 23:09:28 +02:00
|
|
|
ret.device_ = device;
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
// Get text strings
|
2010-08-22 18:11:14 +02:00
|
|
|
const int max_size = 512;
|
|
|
|
wchar_t buf[max_size];
|
|
|
|
device->GetName(buf, max_size);
|
2010-08-30 21:58:01 +02:00
|
|
|
ret.name_ = QString::fromWCharArray(buf).trimmed();
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-22 18:11:14 +02:00
|
|
|
device->GetManufacturer(buf, max_size);
|
2010-08-30 21:58:01 +02:00
|
|
|
ret.manufacturer_ = QString::fromWCharArray(buf).trimmed();
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-22 18:25:22 +02:00
|
|
|
device->GetCanonicalName(buf, max_size);
|
|
|
|
ret.canonical_name_ = QString::fromWCharArray(buf).toLower();
|
2010-08-22 18:11:14 +02:00
|
|
|
|
2010-08-30 21:58:01 +02:00
|
|
|
// Upgrade to a device3
|
|
|
|
IWMDMDevice3* device3 = NULL;
|
|
|
|
device->QueryInterface(IID_IWMDMDevice3, (void**)&device3);
|
|
|
|
|
|
|
|
// Get the device protocol so we can figure out whether the device is MSC
|
|
|
|
PROPVARIANT protocol;
|
2010-08-30 22:37:53 +02:00
|
|
|
if (device3) {
|
|
|
|
device3->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
|
|
|
|
device3->Release();
|
|
|
|
}
|
2010-08-30 21:58:01 +02:00
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
// Get the type and check whether it has storage
|
|
|
|
DWORD type = 0;
|
|
|
|
device->GetType(&type);
|
|
|
|
if (type & WMDM_DEVICE_TYPE_STORAGE)
|
|
|
|
ret.is_suitable_ = true;
|
2010-08-15 20:08:09 +02:00
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
// Get the icon
|
|
|
|
HICON icon;
|
2011-03-13 23:14:23 +01:00
|
|
|
if (device->GetDeviceIcon((ULONG*)&icon) == S_OK) {
|
|
|
|
// Extra check for whether the icon is valid (see issue 1417)
|
2010-08-16 01:26:04 +02:00
|
|
|
|
2011-03-13 23:14:23 +01:00
|
|
|
ICONINFO iconinfo;
|
|
|
|
if (GetIconInfo(icon, &iconinfo)) {
|
|
|
|
ret.icon_ = QPixmap::fromWinHICON(icon);
|
|
|
|
DestroyIcon(icon);
|
|
|
|
}
|
|
|
|
}
|
2010-08-16 01:26:04 +02:00
|
|
|
|
2010-08-17 23:09:28 +02:00
|
|
|
// Get the main (first) storage for the device
|
|
|
|
IWMDMEnumStorage* storage_it = NULL;
|
|
|
|
if (device->EnumStorage(&storage_it) == S_OK && storage_it) {
|
|
|
|
ULONG storage_fetched = 0;
|
2010-08-22 18:11:14 +02:00
|
|
|
IWMDMStorage* storage;
|
|
|
|
|
|
|
|
if (storage_it->Next(1, &storage, &storage_fetched) == S_OK) {
|
|
|
|
if (storage->QueryInterface(IID_IWMDMStorage2, (void**)&ret.storage_)) {
|
|
|
|
qWarning() << "Error getting IWMDMStorage2 from storage";
|
|
|
|
} else {
|
|
|
|
// Get free space information
|
2010-08-30 19:23:24 +02:00
|
|
|
UpdateFreeSpace(&ret);
|
2010-08-22 18:11:14 +02:00
|
|
|
}
|
2010-08-22 21:18:22 +02:00
|
|
|
storage->Release();
|
2010-08-17 23:09:28 +02:00
|
|
|
}
|
|
|
|
storage_it->Release();
|
|
|
|
}
|
|
|
|
|
2010-08-28 20:21:37 +02:00
|
|
|
// There doesn't seem to be a way to get the drive letter of MSC devices, so
|
|
|
|
// try parsing the device's name to extract it.
|
2010-08-30 22:37:53 +02:00
|
|
|
if (!device3 || QUuid(*protocol.puuid) == kDeviceProtocolMsc)
|
2010-08-30 21:58:01 +02:00
|
|
|
GuessDriveLetter(&ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::GuessDriveLetter(DeviceInfo* info) {
|
2010-08-30 22:37:53 +02:00
|
|
|
qDebug() << "Guessing drive letter for" << info->name_;
|
|
|
|
|
2010-08-30 21:58:01 +02:00
|
|
|
// Windows XP puts the drive letter in brackets at the end of the name
|
2010-08-28 20:21:37 +02:00
|
|
|
QRegExp drive_letter("\\(([A-Z]:)\\)$");
|
2010-08-30 21:58:01 +02:00
|
|
|
if (drive_letter.indexIn(info->name_) != -1) {
|
2010-08-30 22:37:53 +02:00
|
|
|
qDebug() << "Looks like an XP drive" << drive_letter.cap(1);
|
2010-08-30 21:58:01 +02:00
|
|
|
CheckDriveLetter(info, drive_letter.cap(1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Windows 7 sometimes has the drive letter as the whole name
|
|
|
|
drive_letter = QRegExp("^([A-Z]:)\\\\$");
|
|
|
|
if (drive_letter.indexIn(info->name_) != -1) {
|
2010-08-30 22:37:53 +02:00
|
|
|
qDebug() << "Looks like a win7 drive" << drive_letter.cap(1);
|
2010-08-30 21:58:01 +02:00
|
|
|
CheckDriveLetter(info, drive_letter.cap(1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise Windows 7 uses the drive's DOS label as its whole name.
|
|
|
|
// Let's enumerate all the volumes on the system and find one with that
|
|
|
|
// label, then get its drive letter. Yay!
|
|
|
|
wchar_t volume_name[MAX_PATH + 1];
|
|
|
|
HANDLE handle = FindFirstVolumeW(volume_name, MAX_PATH);
|
|
|
|
|
|
|
|
forever {
|
|
|
|
// QueryDosDeviceW doesn't allow a trailing backslash, so remove it.
|
|
|
|
int length = wcslen(volume_name);
|
|
|
|
volume_name[length - 1] = L'\0';
|
|
|
|
|
|
|
|
wchar_t device_name[MAX_PATH + 1];
|
|
|
|
QueryDosDeviceW(&volume_name[4], device_name, MAX_PATH);
|
|
|
|
|
|
|
|
volume_name[length - 1] = L'\\';
|
|
|
|
|
|
|
|
// Don't do cd-roms or floppies
|
|
|
|
if (QString::fromWCharArray(device_name).contains("HarddiskVolume")) {
|
|
|
|
wchar_t volume_path[MAX_PATH + 1];
|
|
|
|
DWORD volume_path_length = MAX_PATH;
|
|
|
|
GetVolumePathNamesForVolumeNameW(
|
|
|
|
volume_name, volume_path, volume_path_length, &volume_path_length);
|
|
|
|
|
|
|
|
if (wcslen(volume_path) == 3) {
|
|
|
|
ScopedWCharArray name(QString(MAX_PATH + 1, '\0'));
|
|
|
|
ScopedWCharArray type(QString(MAX_PATH + 1, '\0'));
|
|
|
|
DWORD serial = 0;
|
|
|
|
|
|
|
|
if (!GetVolumeInformationW(volume_path, name, MAX_PATH,
|
|
|
|
&serial, NULL, NULL, type, MAX_PATH)) {
|
|
|
|
qWarning() << "Error getting volume information for" <<
|
|
|
|
QString::fromWCharArray(volume_path);
|
|
|
|
} else {
|
|
|
|
if (name.ToString() == info->name_ && name.characters() != 0) {
|
|
|
|
// We found it!
|
2010-08-30 22:37:53 +02:00
|
|
|
qDebug() << "Looks like a win7 drive name" << QString::fromWCharArray(volume_path);
|
2010-09-04 13:09:59 +02:00
|
|
|
if (CheckDriveLetter(info, QString::fromWCharArray(volume_path))) {
|
|
|
|
info->device_name_ = QString::fromWCharArray(device_name);
|
|
|
|
info->volume_name_ = QString::fromWCharArray(volume_name);
|
|
|
|
}
|
2010-08-30 21:58:01 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-08-28 20:21:37 +02:00
|
|
|
}
|
2010-08-30 21:58:01 +02:00
|
|
|
|
|
|
|
if (!FindNextVolumeW(handle, volume_name, MAX_PATH))
|
|
|
|
break;
|
2010-08-28 20:21:37 +02:00
|
|
|
}
|
2010-08-30 21:58:01 +02:00
|
|
|
FindVolumeClose(handle);
|
|
|
|
}
|
2010-08-28 20:21:37 +02:00
|
|
|
|
2010-09-04 13:09:59 +02:00
|
|
|
bool WmdmLister::CheckDriveLetter(DeviceInfo* info, const QString& drive) {
|
2010-08-30 21:58:01 +02:00
|
|
|
// Sanity check to make sure there really is a drive there
|
|
|
|
ScopedWCharArray path(drive.endsWith('\\') ? drive : (drive + "\\"));
|
|
|
|
ScopedWCharArray name(QString(MAX_PATH + 1, '\0'));
|
|
|
|
ScopedWCharArray type(QString(MAX_PATH + 1, '\0'));
|
|
|
|
DWORD serial = 0;
|
|
|
|
|
|
|
|
if (!GetVolumeInformationW(
|
|
|
|
path,
|
|
|
|
name, MAX_PATH,
|
|
|
|
&serial,
|
|
|
|
NULL, // max component length
|
|
|
|
NULL, // flags
|
|
|
|
type, MAX_PATH // fat or ntfs
|
|
|
|
)) {
|
|
|
|
qWarning() << "Error getting volume information for" << drive;
|
2010-09-04 13:09:59 +02:00
|
|
|
return false;
|
2010-08-30 21:58:01 +02:00
|
|
|
} else {
|
2010-08-30 22:37:53 +02:00
|
|
|
qDebug() << "Validated drive letter" << drive;
|
2010-09-04 13:09:59 +02:00
|
|
|
info->mount_point_ = path.ToString();
|
2010-08-30 21:58:01 +02:00
|
|
|
info->fs_name_ = name.ToString();
|
|
|
|
info->fs_type_ = type.ToString();
|
|
|
|
info->fs_serial_ = serial;
|
2010-09-04 13:09:59 +02:00
|
|
|
return true;
|
2010-08-30 21:58:01 +02:00
|
|
|
}
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList WmdmLister::DeviceUniqueIDs() {
|
2010-08-16 01:26:04 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
return devices_.keys();
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
2010-08-16 01:26:04 +02:00
|
|
|
QVariantList WmdmLister::DeviceIcons(const QString& id) {
|
|
|
|
QPixmap pixmap = LockAndGetDeviceInfo(id, &DeviceInfo::icon_);
|
|
|
|
|
|
|
|
if (pixmap.isNull())
|
|
|
|
return QVariantList();
|
|
|
|
return QVariantList() << pixmap;
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString WmdmLister::DeviceManufacturer(const QString& id) {
|
2010-08-16 01:26:04 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::manufacturer_);
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString WmdmLister::DeviceModel(const QString& id) {
|
2010-08-16 01:26:04 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::name_);
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
quint64 WmdmLister::DeviceCapacity(const QString& id) {
|
2010-08-17 23:09:28 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::total_bytes_);
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
quint64 WmdmLister::DeviceFreeSpace(const QString& id) {
|
2010-08-17 23:09:28 +02:00
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::free_bytes_);
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariantMap WmdmLister::DeviceHardwareInfo(const QString& id) {
|
2010-09-04 13:09:59 +02:00
|
|
|
QVariantMap ret;
|
|
|
|
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
if (!devices_.contains(id))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
|
|
|
|
ret[tr("Drive letter")] = QDir::toNativeSeparators(info.mount_point_);
|
|
|
|
ret[tr("Filesystem type")] = info.fs_type_;
|
|
|
|
ret[tr("Filesystem name")] = info.fs_name_;
|
|
|
|
ret[tr("Device name")] = info.device_name_;
|
|
|
|
ret[tr("Volume name")] = info.volume_name_;
|
|
|
|
|
|
|
|
if (info.fs_serial_ != 0)
|
|
|
|
ret[tr("Filesystem serial number")] = info.fs_serial_;
|
|
|
|
|
|
|
|
return ret;
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString WmdmLister::MakeFriendlyName(const QString& id) {
|
2010-08-16 01:26:04 +02:00
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
if (!devices_.contains(id))
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
const DeviceInfo& info = devices_[id];
|
|
|
|
if (info.manufacturer_.isEmpty() || info.manufacturer_ == "Unknown")
|
|
|
|
return info.name_;
|
|
|
|
|
|
|
|
return info.manufacturer_ + " " + info.name_;
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QList<QUrl> WmdmLister::MakeDeviceUrls(const QString& id) {
|
2010-08-28 20:21:37 +02:00
|
|
|
QList<QUrl> ret;
|
2010-08-22 21:18:22 +02:00
|
|
|
|
2010-08-28 20:21:37 +02:00
|
|
|
QString mount_point = LockAndGetDeviceInfo(id, &DeviceInfo::mount_point_);
|
|
|
|
if (!mount_point.isEmpty()) {
|
|
|
|
ret << MakeUrlFromLocalPath(mount_point);
|
|
|
|
}
|
|
|
|
|
|
|
|
QUrl wmdm_url;
|
|
|
|
wmdm_url.setScheme("wmdm");
|
|
|
|
wmdm_url.setPath(id);
|
|
|
|
ret << wmdm_url;
|
|
|
|
|
|
|
|
return ret;
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::UnmountDevice(const QString& id) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::UpdateDeviceFreeSpace(const QString& id) {
|
2010-08-30 19:23:24 +02:00
|
|
|
// This needs to be done in the lister's thread where we already have COM
|
|
|
|
// initialised
|
|
|
|
metaObject()->invokeMethod(this, "DoUpdateDriveFreeSpace",
|
|
|
|
Qt::BlockingQueuedConnection, Q_ARG(QString, id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::DoUpdateDriveFreeSpace(const QString& id) {
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
if (!devices_.contains(id))
|
|
|
|
return;
|
|
|
|
|
|
|
|
UpdateFreeSpace(&devices_[id]);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceChanged(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::UpdateFreeSpace(DeviceInfo* info) {
|
|
|
|
IWMDMStorageGlobals* globals;
|
|
|
|
info->storage_->GetStorageGlobals(&globals);
|
|
|
|
|
|
|
|
info->total_bytes_ = GetSpaceValue(boost::bind(&IWMDMStorageGlobals::GetTotalSize, globals, _1, _2));
|
|
|
|
info->free_bytes_ = GetSpaceValue(boost::bind(&IWMDMStorageGlobals::GetTotalFree, globals, _1, _2));
|
|
|
|
info->free_bytes_ -= GetSpaceValue(boost::bind(&IWMDMStorageGlobals::GetTotalBad, globals, _1, _2));
|
|
|
|
|
|
|
|
globals->Release();
|
2010-08-15 20:08:09 +02:00
|
|
|
}
|
2010-08-22 17:26:59 +02:00
|
|
|
|
|
|
|
HRESULT WmdmLister::WMDMMessage(DWORD message_type, LPCWSTR name) {
|
2010-08-22 18:25:22 +02:00
|
|
|
QString canonical_name = QString::fromWCharArray(name).toLower();
|
|
|
|
|
|
|
|
switch (message_type) {
|
|
|
|
case WMDM_MSG_DEVICE_ARRIVAL: WMDMDeviceAdded(canonical_name); break;
|
|
|
|
case WMDM_MSG_DEVICE_REMOVAL: WMDMDeviceRemoved(canonical_name); break;
|
|
|
|
}
|
2010-08-22 18:11:14 +02:00
|
|
|
|
2010-08-22 17:26:59 +02:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-22 18:25:22 +02:00
|
|
|
void WmdmLister::WMDMDeviceAdded(const QString& canonical_name) {
|
2010-08-23 21:13:27 +02:00
|
|
|
ScopedWCharArray name(canonical_name);
|
2010-08-22 18:25:22 +02:00
|
|
|
|
|
|
|
IWMDMDevice* device = NULL;
|
2010-08-23 21:13:27 +02:00
|
|
|
if (thread_->manager()->GetDeviceFromCanonicalName(name, &device)) {
|
2010-08-22 18:25:22 +02:00
|
|
|
qWarning() << "Error in GetDeviceFromCanonicalName for" << canonical_name;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
IWMDMDevice2* device2 = NULL;
|
|
|
|
if (device->QueryInterface(IID_IWMDMDevice2, (void**) &device2)) {
|
|
|
|
qWarning() << "Error getting IWMDMDevice2 from device";
|
|
|
|
device->Release();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
device->Release();
|
|
|
|
|
|
|
|
DeviceInfo info = ReadDeviceInfo(device2);
|
|
|
|
if (info.is_suitable_) {
|
|
|
|
QString id = info.unique_id();
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
devices_[id] = info;
|
|
|
|
}
|
|
|
|
emit DeviceAdded(id);
|
|
|
|
} else {
|
|
|
|
device2->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WmdmLister::WMDMDeviceRemoved(const QString& canonical_name) {
|
|
|
|
QString id = CanonicalNameToId(canonical_name);
|
|
|
|
{
|
|
|
|
QMutexLocker l(&mutex_);
|
|
|
|
if (!devices_.contains(id))
|
|
|
|
return;
|
|
|
|
|
2010-08-22 21:18:22 +02:00
|
|
|
devices_[id].device_->Release();
|
|
|
|
devices_[id].storage_->Release();
|
|
|
|
|
2010-08-22 18:25:22 +02:00
|
|
|
devices_.remove(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit DeviceRemoved(id);
|
|
|
|
}
|
|
|
|
|
2010-08-22 17:26:59 +02:00
|
|
|
LONG WmdmLister::QueryInterface(REFIID riid, void** object) {
|
|
|
|
*object = 0;
|
|
|
|
|
|
|
|
if (riid == IID_IUnknown)
|
|
|
|
*object = (IUnknown*) this;
|
|
|
|
else if (riid == IID_IWMDMNotification)
|
|
|
|
*object = (IWMDMNotification*) this;
|
|
|
|
else
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG WmdmLister::AddRef() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG WmdmLister::Release() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-08-22 21:18:22 +02:00
|
|
|
QString WmdmLister::DeviceCanonicalName(const QString& id) {
|
|
|
|
return LockAndGetDeviceInfo(id, &DeviceInfo::canonical_name_);
|
|
|
|
}
|
|
|
|
|