mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 11:35:24 +01:00
Get the drive letter for MSC WMDM devices on Windows 7
This commit is contained in:
parent
a59025cdec
commit
1dd6ac323e
@ -41,7 +41,7 @@ pkg_check_modules(LIBMTP libmtp)
|
||||
|
||||
if (WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_library(MSWMDM_LIBRARIES MSWMDM)
|
||||
find_library(MSWMDM_LIBRARIES mswmdm)
|
||||
find_library(SAC_SHIM_LIBRARIES sac_shim)
|
||||
endif (WIN32)
|
||||
|
||||
|
@ -53,91 +53,6 @@
|
||||
#ifdef Q_OS_WIN32
|
||||
# include <mswmdm.h>
|
||||
# include <QUuid>
|
||||
|
||||
// Copied from the WMDM SDK 11, it doesn't seem to be included in SDK 9 for
|
||||
// some reason, even though the devices use it.
|
||||
typedef enum tagWMDM_FORMATCODE {
|
||||
WMDM_FORMATCODE_NOTUSED = 0x0000,
|
||||
WMDM_FORMATCODE_ALLIMAGES = 0xFFFFFFFF,
|
||||
WMDM_FORMATCODE_UNDEFINED = 0x3000,
|
||||
WMDM_FORMATCODE_ASSOCIATION = 0x3001,
|
||||
WMDM_FORMATCODE_SCRIPT = 0x3002,
|
||||
WMDM_FORMATCODE_EXECUTABLE = 0x3003,
|
||||
WMDM_FORMATCODE_TEXT = 0x3004,
|
||||
WMDM_FORMATCODE_HTML = 0x3005,
|
||||
WMDM_FORMATCODE_DPOF = 0x3006,
|
||||
WMDM_FORMATCODE_AIFF = 0x3007,
|
||||
WMDM_FORMATCODE_WAVE = 0x3008,
|
||||
WMDM_FORMATCODE_MP3 = 0x3009,
|
||||
WMDM_FORMATCODE_AVI = 0x300A,
|
||||
WMDM_FORMATCODE_MPEG = 0x300B,
|
||||
WMDM_FORMATCODE_ASF = 0x300C,
|
||||
WMDM_FORMATCODE_RESERVED_FIRST = 0x300D,
|
||||
WMDM_FORMATCODE_RESERVED_LAST = 0x37FF,
|
||||
WMDM_FORMATCODE_IMAGE_UNDEFINED = 0x3800,
|
||||
WMDM_FORMATCODE_IMAGE_EXIF = 0x3801,
|
||||
WMDM_FORMATCODE_IMAGE_TIFFEP = 0x3802,
|
||||
WMDM_FORMATCODE_IMAGE_FLASHPIX = 0x3803,
|
||||
WMDM_FORMATCODE_IMAGE_BMP = 0x3804,
|
||||
WMDM_FORMATCODE_IMAGE_CIFF = 0x3805,
|
||||
WMDM_FORMATCODE_IMAGE_GIF = 0x3807,
|
||||
WMDM_FORMATCODE_IMAGE_JFIF = 0x3808,
|
||||
WMDM_FORMATCODE_IMAGE_PCD = 0x3809,
|
||||
WMDM_FORMATCODE_IMAGE_PICT = 0x380A,
|
||||
WMDM_FORMATCODE_IMAGE_PNG = 0x380B,
|
||||
WMDM_FORMATCODE_IMAGE_TIFF = 0x380D,
|
||||
WMDM_FORMATCODE_IMAGE_TIFFIT = 0x380E,
|
||||
WMDM_FORMATCODE_IMAGE_JP2 = 0x380F,
|
||||
WMDM_FORMATCODE_IMAGE_JPX = 0x3810,
|
||||
WMDM_FORMATCODE_IMAGE_RESERVED_FIRST = 0x3811,
|
||||
WMDM_FORMATCODE_IMAGE_RESERVED_LAST = 0x3FFF,
|
||||
WMDM_FORMATCODE_UNDEFINEDFIRMWARE = 0xB802,
|
||||
WMDM_FORMATCODE_WINDOWSIMAGEFORMAT = 0xB881,
|
||||
WMDM_FORMATCODE_UNDEFINEDAUDIO = 0xB900,
|
||||
WMDM_FORMATCODE_WMA = 0xB901,
|
||||
WMDM_FORMATCODE_OGG = 0xB902,
|
||||
WMDM_FORMATCODE_AAC = 0xB903,
|
||||
WMDM_FORMATCODE_AUDIBLE = 0xB904,
|
||||
WMDM_FORMATCODE_FLAC = 0xB906,
|
||||
WMDM_FORMATCODE_UNDEFINEDVIDEO = 0xB980,
|
||||
WMDM_FORMATCODE_WMV = 0xB981,
|
||||
WMDM_FORMATCODE_MP4 = 0xB982,
|
||||
WMDM_FORMATCODE_MP2 = 0xB983,
|
||||
WMDM_FORMATCODE_UNDEFINEDCOLLECTION = 0xBA00,
|
||||
WMDM_FORMATCODE_ABSTRACTMULTIMEDIAALBUM = 0xBA01,
|
||||
WMDM_FORMATCODE_ABSTRACTIMAGEALBUM = 0xBA02,
|
||||
WMDM_FORMATCODE_ABSTRACTAUDIOALBUM = 0xBA03,
|
||||
WMDM_FORMATCODE_ABSTRACTVIDEOALBUM = 0xBA04,
|
||||
WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST = 0xBA05,
|
||||
WMDM_FORMATCODE_ABSTRACTCONTACTGROUP = 0xBA06,
|
||||
WMDM_FORMATCODE_ABSTRACTMESSAGEFOLDER = 0xBA07,
|
||||
WMDM_FORMATCODE_ABSTRACTCHAPTEREDPRODUCTION = 0xBA08,
|
||||
WMDM_FORMATCODE_WPLPLAYLIST = 0xBA10,
|
||||
WMDM_FORMATCODE_M3UPLAYLIST = 0xBA11,
|
||||
WMDM_FORMATCODE_MPLPLAYLIST = 0xBA12,
|
||||
WMDM_FORMATCODE_ASXPLAYLIST = 0xBA13,
|
||||
WMDM_FORMATCODE_PLSPLAYLIST = 0xBA14,
|
||||
WMDM_FORMATCODE_UNDEFINEDDOCUMENT = 0xBA80,
|
||||
WMDM_FORMATCODE_ABSTRACTDOCUMENT = 0xBA81,
|
||||
WMDM_FORMATCODE_XMLDOCUMENT = 0xBA82,
|
||||
WMDM_FORMATCODE_MICROSOFTWORDDOCUMENT= 0xBA83,
|
||||
WMDM_FORMATCODE_MHTCOMPILEDHTMLDOCUMENT = 0xBA84,
|
||||
WMDM_FORMATCODE_MICROSOFTEXCELSPREADSHEET = 0xBA85,
|
||||
WMDM_FORMATCODE_MICROSOFTPOWERPOINTDOCUMENT = 0xBA86,
|
||||
WMDM_FORMATCODE_UNDEFINEDMESSAGE = 0xBB00,
|
||||
WMDM_FORMATCODE_ABSTRACTMESSAGE = 0xBB01,
|
||||
WMDM_FORMATCODE_UNDEFINEDCONTACT = 0xBB80,
|
||||
WMDM_FORMATCODE_ABSTRACTCONTACT = 0xBB81,
|
||||
WMDM_FORMATCODE_VCARD2 = 0xBB82,
|
||||
WMDM_FORMATCODE_VCARD3 = 0xBB83,
|
||||
WMDM_FORMATCODE_UNDEFINEDCALENDARITEM = 0xBE00,
|
||||
WMDM_FORMATCODE_ABSTRACTCALENDARITEM = 0xBE01,
|
||||
WMDM_FORMATCODE_VCALENDAR1 = 0xBE02,
|
||||
WMDM_FORMATCODE_VCALENDAR2 = 0xBE03,
|
||||
WMDM_FORMATCODE_UNDEFINEDWINDOWSEXECUTABLE = 0xBE80,
|
||||
WMDM_FORMATCODE_MEDIA_CAST = 0xBE81,
|
||||
WMDM_FORMATCODE_SECTION = 0xBE82
|
||||
} WMDM_FORMATCODE;
|
||||
#endif // Q_OS_WIN32
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
@ -14,13 +14,15 @@
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
#include "wmdmlister.h"
|
||||
#include "wmdmthread.h"
|
||||
#include "core/utilities.h"
|
||||
|
||||
#include <icomponentauthenticate.h>
|
||||
#include <objbase.h>
|
||||
#include <mswmdm_i.c>
|
||||
#include <winbase.h>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
@ -29,6 +31,9 @@
|
||||
#include <QStringList>
|
||||
#include <QtDebug>
|
||||
|
||||
const QUuid WmdmLister::kDeviceProtocolMsc(
|
||||
0xa4d2c26c, 0xa881, 0x44bb, 0xbd, 0x5d, 0x1f, 0x70, 0x3c, 0x71, 0xf7, 0xa9);
|
||||
|
||||
QString WmdmLister::CanonicalNameToId(const QString& canonical_name) {
|
||||
return "wmdm/" + canonical_name;
|
||||
}
|
||||
@ -139,14 +144,23 @@ WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
|
||||
const int max_size = 512;
|
||||
wchar_t buf[max_size];
|
||||
device->GetName(buf, max_size);
|
||||
ret.name_ = QString::fromWCharArray(buf);
|
||||
ret.name_ = QString::fromWCharArray(buf).trimmed();
|
||||
|
||||
device->GetManufacturer(buf, max_size);
|
||||
ret.manufacturer_ = QString::fromWCharArray(buf);
|
||||
ret.manufacturer_ = QString::fromWCharArray(buf).trimmed();
|
||||
|
||||
device->GetCanonicalName(buf, max_size);
|
||||
ret.canonical_name_ = QString::fromWCharArray(buf).toLower();
|
||||
|
||||
// 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;
|
||||
device3->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
|
||||
device3->Release();
|
||||
|
||||
// Get the type and check whether it has storage
|
||||
DWORD type = 0;
|
||||
device->GetType(&type);
|
||||
@ -180,34 +194,99 @@ WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
|
||||
|
||||
// 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.
|
||||
QRegExp drive_letter("\\(([A-Z]:)\\)$");
|
||||
if (drive_letter.indexIn(ret.name_) != -1) {
|
||||
// Sanity check to make sure there really is a drive there
|
||||
ScopedWCharArray path(drive_letter.cap(1) + "\\");
|
||||
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_letter.cap(1);
|
||||
} else {
|
||||
ret.mount_point_ = drive_letter.cap(1) + "/";
|
||||
ret.fs_name_ = name.ToString();
|
||||
ret.fs_type_ = type.ToString();
|
||||
ret.fs_serial_ = serial;
|
||||
}
|
||||
}
|
||||
if (QUuid(*protocol.puuid) == kDeviceProtocolMsc)
|
||||
GuessDriveLetter(&ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WmdmLister::GuessDriveLetter(DeviceInfo* info) {
|
||||
// Windows XP puts the drive letter in brackets at the end of the name
|
||||
QRegExp drive_letter("\\(([A-Z]:)\\)$");
|
||||
if (drive_letter.indexIn(info->name_) != -1) {
|
||||
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) {
|
||||
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!
|
||||
CheckDriveLetter(info, QString::fromWCharArray(volume_path));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!FindNextVolumeW(handle, volume_name, MAX_PATH))
|
||||
break;
|
||||
}
|
||||
FindVolumeClose(handle);
|
||||
}
|
||||
|
||||
void WmdmLister::CheckDriveLetter(DeviceInfo* info, const QString& drive) {
|
||||
// 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;
|
||||
} else {
|
||||
info->mount_point_ = drive + "/";
|
||||
info->fs_name_ = name.ToString();
|
||||
info->fs_type_ = type.ToString();
|
||||
info->fs_serial_ = serial;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList WmdmLister::DeviceUniqueIDs() {
|
||||
QMutexLocker l(&mutex_);
|
||||
return devices_.keys();
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QPixmap>
|
||||
#include <QUuid>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
@ -98,12 +99,16 @@ private:
|
||||
int fs_serial_;
|
||||
};
|
||||
|
||||
static const QUuid kDeviceProtocolMsc;
|
||||
|
||||
DeviceInfo ReadDeviceInfo(IWMDMDevice2* device);
|
||||
|
||||
template <typename T>
|
||||
T LockAndGetDeviceInfo(const QString& id, T DeviceInfo::*field);
|
||||
|
||||
void UpdateFreeSpace(DeviceInfo* info);
|
||||
void GuessDriveLetter(DeviceInfo* info);
|
||||
void CheckDriveLetter(DeviceInfo* info, const QString& drive);
|
||||
|
||||
static QString CanonicalNameToId(const QString& canonical_name);
|
||||
void WMDMDeviceAdded(const QString& canonical_name);
|
||||
|
Loading…
x
Reference in New Issue
Block a user